mirror of https://gitee.com/openkylin/linux.git
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
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
@ -20,28 +18,51 @@ pressed or released a BUTTON_IRQ happens. The driver could look like:
|
|||
#include <asm/irq.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
static struct input_dev *button_dev;
|
||||
|
||||
static void button_interrupt(int irq, void *dummy, struct pt_regs *fp)
|
||||
{
|
||||
input_report_key(&button_dev, BTN_1, inb(BUTTON_PORT) & 1);
|
||||
input_sync(&button_dev);
|
||||
input_report_key(button_dev, BTN_1, inb(BUTTON_PORT) & 1);
|
||||
input_sync(button_dev);
|
||||
}
|
||||
|
||||
static int __init button_init(void)
|
||||
{
|
||||
int error;
|
||||
|
||||
if (request_irq(BUTTON_IRQ, button_interrupt, 0, "button", NULL)) {
|
||||
printk(KERN_ERR "button.c: Can't allocate irq %d\n", button_irq);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
button_dev.evbit[0] = BIT(EV_KEY);
|
||||
button_dev.keybit[LONG(BTN_0)] = BIT(BTN_0);
|
||||
|
||||
input_register_device(&button_dev);
|
||||
|
||||
button_dev = input_allocate_device();
|
||||
if (!button_dev) {
|
||||
printk(KERN_ERR "button.c: Not enough memory\n");
|
||||
error = -ENOMEM;
|
||||
goto err_free_irq;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
input_unregister_device(&button_dev);
|
||||
input_unregister_device(button_dev);
|
||||
free_irq(BUTTON_IRQ, button_interrupt);
|
||||
}
|
||||
|
||||
|
@ -58,17 +79,18 @@ 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
|
||||
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
|
||||
accepted by this input device. Our example device can only generate EV_KEY type
|
||||
events, and from those only BTN_0 event code. Thus we only set these two
|
||||
bits. We could have used
|
||||
accepted by this input device. Our example device can only generate EV_KEY
|
||||
type events, and from those only BTN_0 event code. Thus we only set these
|
||||
two bits. We could have used
|
||||
|
||||
set_bit(EV_KEY, button_dev.evbit);
|
||||
set_bit(BTN_0, button_dev.keybit);
|
||||
|
||||
as well, but with more than single bits the first approach tends to be
|
||||
shorter.
|
||||
shorter.
|
||||
|
||||
Then the example driver registers the input device structure by calling
|
||||
|
||||
|
@ -76,16 +98,15 @@ 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
|
||||
calls device handler modules _connect functions to tell them a new input
|
||||
device has appeared. Because the _connect functions may call kmalloc(,
|
||||
GFP_KERNEL), which can sleep, input_register_device() must not be called
|
||||
from an interrupt or with a spinlock held.
|
||||
device has appeared. input_register_device() may sleep and therefore must
|
||||
not be called from an interrupt or with a spinlock held.
|
||||
|
||||
While in use, the only used function of the driver is
|
||||
|
||||
button_interrupt()
|
||||
|
||||
which upon every interrupt from the button checks its state and reports it
|
||||
via the
|
||||
via the
|
||||
|
||||
input_report_key()
|
||||
|
||||
|
@ -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
|
||||
again. To do that, we would add this to our example driver:
|
||||
|
||||
int button_used = 0;
|
||||
|
||||
static int button_open(struct input_dev *dev)
|
||||
{
|
||||
if (button_used++)
|
||||
return 0;
|
||||
|
||||
if (request_irq(BUTTON_IRQ, button_interrupt, 0, "button", NULL)) {
|
||||
printk(KERN_ERR "button.c: Can't allocate irq %d\n", button_irq);
|
||||
button_used--;
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
|
@ -131,20 +146,21 @@ static int button_open(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)
|
||||
{
|
||||
...
|
||||
button_dev.open = button_open;
|
||||
button_dev.close = button_close;
|
||||
button_dev->open = button_open;
|
||||
button_dev->close = button_close;
|
||||
...
|
||||
}
|
||||
|
||||
Note the button_used variable - we have to track how many times the open
|
||||
function was called to know when exactly our device stops being used.
|
||||
Note that input core keeps track of number of users for the device and
|
||||
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
|
||||
in case of failure. The close() callback (which is void) must always succeed.
|
||||
|
@ -175,7 +191,7 @@ set the corresponding bits and call the
|
|||
|
||||
input_report_rel(struct input_dev *dev, int code, int value)
|
||||
|
||||
function. Events are generated only for nonzero value.
|
||||
function. Events are generated only for nonzero value.
|
||||
|
||||
However EV_ABS requires a little special care. Before calling
|
||||
input_register_device, you have to fill additional fields in the input_dev
|
||||
|
@ -187,6 +203,10 @@ the ABS_X axis:
|
|||
button_dev.absfuzz[ABS_X] = 4;
|
||||
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
|
||||
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
|
||||
|
@ -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
|
||||
(if it has any).
|
||||
|
||||
1.4 The void *private field
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
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()
|
||||
1.4 NBITS(), LONG(), BIT()
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
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
|
||||
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
|
||||
device driver. It's a string like 'Generic button device' containing a
|
||||
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.
|
||||
|
||||
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
|
||||
as scancodes. If not all scancodes can be known by autodetection, they may
|
||||
need to be set by userland utilities. The keycode array then is an array
|
||||
used to map from scancodes to input system keycodes. The keycode max will
|
||||
contain the size of the array and keycodesize the size of each entry in it
|
||||
(in bytes).
|
||||
These three fields should be used by input devices that have dense keymaps.
|
||||
The keycode is an array used to map from scancodes to input system keycodes.
|
||||
The keycode max should 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
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
@ -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,
|
||||
*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);
|
||||
{
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
# 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_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/reboot.h>
|
||||
|
||||
static void kbd_disconnect(struct input_handle *handle);
|
||||
extern void ctrl_alt_del(void);
|
||||
|
||||
/*
|
||||
|
@ -159,65 +158,41 @@ static int sysrq_alt_use;
|
|||
static int sysrq_alt;
|
||||
|
||||
/*
|
||||
* Translation of scancodes to keycodes. We set them on only the first attached
|
||||
* keyboard - for per-keyboard setting, /dev/input/event is more useful.
|
||||
* Translation of scancodes to keycodes. We set them on only the first
|
||||
* 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)
|
||||
{
|
||||
struct list_head *node;
|
||||
struct input_dev *dev = NULL;
|
||||
struct input_handle *handle;
|
||||
int keycode;
|
||||
int error = -ENODEV;
|
||||
|
||||
list_for_each(node, &kbd_handler.h_list) {
|
||||
struct input_handle *handle = to_handle_h(node);
|
||||
if (handle->dev->keycodesize) {
|
||||
dev = handle->dev;
|
||||
break;
|
||||
}
|
||||
list_for_each_entry(handle, &kbd_handler.h_list, h_node) {
|
||||
error = handle->dev->getkeycode(handle->dev, scancode, &keycode);
|
||||
if (!error)
|
||||
return keycode;
|
||||
}
|
||||
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
|
||||
if (scancode >= dev->keycodemax)
|
||||
return -EINVAL;
|
||||
|
||||
return INPUT_KEYCODE(dev, scancode);
|
||||
return error;
|
||||
}
|
||||
|
||||
int setkeycode(unsigned int scancode, unsigned int keycode)
|
||||
{
|
||||
struct list_head *node;
|
||||
struct input_dev *dev = NULL;
|
||||
unsigned int i, oldkey;
|
||||
struct input_handle *handle;
|
||||
int error = -ENODEV;
|
||||
|
||||
list_for_each(node, &kbd_handler.h_list) {
|
||||
struct input_handle *handle = to_handle_h(node);
|
||||
if (handle->dev->keycodesize) {
|
||||
dev = handle->dev;
|
||||
list_for_each_entry(handle, &kbd_handler.h_list, h_node) {
|
||||
error = handle->dev->setkeycode(handle->dev, scancode, keycode);
|
||||
if (!error)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!dev)
|
||||
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;
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -225,10 +200,9 @@ int setkeycode(unsigned int scancode, unsigned int keycode)
|
|||
*/
|
||||
static void kd_nosound(unsigned long ignored)
|
||||
{
|
||||
struct list_head *node;
|
||||
struct input_handle *handle;
|
||||
|
||||
list_for_each(node, &kbd_handler.h_list) {
|
||||
struct input_handle *handle = to_handle_h(node);
|
||||
list_for_each_entry(handle, &kbd_handler.h_list, h_node) {
|
||||
if (test_bit(EV_SND, handle->dev->evbit)) {
|
||||
if (test_bit(SND_TONE, handle->dev->sndbit))
|
||||
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 (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);
|
||||
|
||||
#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)
|
||||
* function, we should decide which VT to bind that keyboard to initially.
|
||||
*/
|
||||
static struct input_handle *kbd_connect(struct input_handler *handler,
|
||||
struct input_dev *dev,
|
||||
const struct input_device_id *id)
|
||||
static int kbd_connect(struct input_handler *handler, struct input_dev *dev,
|
||||
const struct input_device_id *id)
|
||||
{
|
||||
struct input_handle *handle;
|
||||
int error;
|
||||
int i;
|
||||
|
||||
for (i = KEY_RESERVED; i < BTN_MISC; i++)
|
||||
|
@ -1297,24 +1271,37 @@ static struct input_handle *kbd_connect(struct input_handler *handler,
|
|||
break;
|
||||
|
||||
if (i == BTN_MISC && !test_bit(EV_SND, dev->evbit))
|
||||
return NULL;
|
||||
return -ENODEV;
|
||||
|
||||
handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
|
||||
if (!handle)
|
||||
return NULL;
|
||||
return -ENOMEM;
|
||||
|
||||
handle->dev = dev;
|
||||
handle->handler = handler;
|
||||
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)
|
||||
{
|
||||
input_close_device(handle);
|
||||
input_unregister_handle(handle);
|
||||
kfree(handle);
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@ obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o
|
|||
obj-$(CONFIG_INPUT_JOYDEV) += joydev.o
|
||||
obj-$(CONFIG_INPUT_EVDEV) += evdev.o
|
||||
obj-$(CONFIG_INPUT_TSDEV) += tsdev.o
|
||||
obj-$(CONFIG_INPUT_POWER) += power.o
|
||||
obj-$(CONFIG_INPUT_EVBUG) += evbug.o
|
||||
|
||||
obj-$(CONFIG_INPUT_KEYBOARD) += keyboard/
|
||||
|
|
|
@ -38,31 +38,43 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
|||
MODULE_DESCRIPTION("Input driver event debug module");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static char evbug_name[] = "evbug";
|
||||
|
||||
static void evbug_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
|
||||
{
|
||||
printk(KERN_DEBUG "evbug.c: Event. Dev: %s, Type: %d, Code: %d, Value: %d\n",
|
||||
handle->dev->phys, type, code, value);
|
||||
}
|
||||
|
||||
static struct input_handle *evbug_connect(struct input_handler *handler, struct input_dev *dev,
|
||||
const struct input_device_id *id)
|
||||
static int evbug_connect(struct input_handler *handler, struct input_dev *dev,
|
||||
const struct input_device_id *id)
|
||||
{
|
||||
struct input_handle *handle;
|
||||
int error;
|
||||
|
||||
if (!(handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL)))
|
||||
return NULL;
|
||||
handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
|
||||
if (!handle)
|
||||
return -ENOMEM;
|
||||
|
||||
handle->dev = dev;
|
||||
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);
|
||||
|
||||
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)
|
||||
|
@ -70,7 +82,7 @@ static void evbug_disconnect(struct input_handle *handle)
|
|||
printk(KERN_DEBUG "evbug.c: Disconnected device: %s\n", handle->dev->phys);
|
||||
|
||||
input_close_device(handle);
|
||||
|
||||
input_unregister_handle(handle);
|
||||
kfree(handle);
|
||||
}
|
||||
|
||||
|
|
|
@ -29,11 +29,11 @@ struct evdev {
|
|||
char name[16];
|
||||
struct input_handle handle;
|
||||
wait_queue_head_t wait;
|
||||
struct evdev_list *grab;
|
||||
struct list_head list;
|
||||
struct evdev_client *grab;
|
||||
struct list_head client_list;
|
||||
};
|
||||
|
||||
struct evdev_list {
|
||||
struct evdev_client {
|
||||
struct input_event buffer[EVDEV_BUFFER_SIZE];
|
||||
int head;
|
||||
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)
|
||||
{
|
||||
struct evdev *evdev = handle->private;
|
||||
struct evdev_list *list;
|
||||
struct evdev_client *client;
|
||||
|
||||
if (evdev->grab) {
|
||||
list = evdev->grab;
|
||||
client = evdev->grab;
|
||||
|
||||
do_gettimeofday(&list->buffer[list->head].time);
|
||||
list->buffer[list->head].type = type;
|
||||
list->buffer[list->head].code = code;
|
||||
list->buffer[list->head].value = value;
|
||||
list->head = (list->head + 1) & (EVDEV_BUFFER_SIZE - 1);
|
||||
do_gettimeofday(&client->buffer[client->head].time);
|
||||
client->buffer[client->head].type = type;
|
||||
client->buffer[client->head].code = code;
|
||||
client->buffer[client->head].value = value;
|
||||
client->head = (client->head + 1) & (EVDEV_BUFFER_SIZE - 1);
|
||||
|
||||
kill_fasync(&list->fasync, SIGIO, POLL_IN);
|
||||
kill_fasync(&client->fasync, SIGIO, POLL_IN);
|
||||
} 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);
|
||||
list->buffer[list->head].type = type;
|
||||
list->buffer[list->head].code = code;
|
||||
list->buffer[list->head].value = value;
|
||||
list->head = (list->head + 1) & (EVDEV_BUFFER_SIZE - 1);
|
||||
do_gettimeofday(&client->buffer[client->head].time);
|
||||
client->buffer[client->head].type = type;
|
||||
client->buffer[client->head].code = code;
|
||||
client->buffer[client->head].value = value;
|
||||
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);
|
||||
|
@ -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)
|
||||
{
|
||||
struct evdev_client *client = file->private_data;
|
||||
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;
|
||||
}
|
||||
|
||||
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 input_flush_device(&list->evdev->handle, file);
|
||||
return input_flush_device(&evdev->handle, file);
|
||||
}
|
||||
|
||||
static void evdev_free(struct evdev *evdev)
|
||||
|
@ -100,48 +101,62 @@ static void evdev_free(struct evdev *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) {
|
||||
input_release_device(&list->evdev->handle);
|
||||
list->evdev->grab = NULL;
|
||||
if (evdev->grab == client) {
|
||||
input_release_device(&evdev->handle);
|
||||
evdev->grab = NULL;
|
||||
}
|
||||
|
||||
evdev_fasync(-1, file, 0);
|
||||
list_del(&list->node);
|
||||
list_del(&client->node);
|
||||
kfree(client);
|
||||
|
||||
if (!--list->evdev->open) {
|
||||
if (list->evdev->exist)
|
||||
input_close_device(&list->evdev->handle);
|
||||
if (!--evdev->open) {
|
||||
if (evdev->exist)
|
||||
input_close_device(&evdev->handle);
|
||||
else
|
||||
evdev_free(list->evdev);
|
||||
evdev_free(evdev);
|
||||
}
|
||||
|
||||
kfree(list);
|
||||
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 error;
|
||||
|
||||
if (i >= EVDEV_MINORS || !evdev_table[i] || !evdev_table[i]->exist)
|
||||
if (i >= EVDEV_MINORS)
|
||||
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;
|
||||
|
||||
list->evdev = evdev_table[i];
|
||||
list_add_tail(&list->node, &evdev_table[i]->list);
|
||||
file->private_data = list;
|
||||
client->evdev = evdev;
|
||||
list_add_tail(&client->node, &evdev->client_list);
|
||||
|
||||
if (!list->evdev->open++)
|
||||
if (list->evdev->exist)
|
||||
input_open_device(&list->evdev->handle);
|
||||
if (!evdev->open++ && evdev->exist) {
|
||||
error = input_open_device(&evdev->handle);
|
||||
if (error) {
|
||||
list_del(&client->node);
|
||||
kfree(client);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
file->private_data = client;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -243,54 +258,55 @@ static int evdev_event_to_user(char __user *buffer, const struct input_event *ev
|
|||
|
||||
#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;
|
||||
int retval = 0;
|
||||
|
||||
if (!list->evdev->exist)
|
||||
if (!evdev->exist)
|
||||
return -ENODEV;
|
||||
|
||||
while (retval < count) {
|
||||
|
||||
if (evdev_event_from_user(buffer + retval, &event))
|
||||
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();
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (count < evdev_event_size())
|
||||
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;
|
||||
|
||||
retval = wait_event_interruptible(list->evdev->wait,
|
||||
list->head != list->tail || (!list->evdev->exist));
|
||||
|
||||
retval = wait_event_interruptible(evdev->wait,
|
||||
client->head != client->tail || !evdev->exist);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (!list->evdev->exist)
|
||||
if (!evdev->exist)
|
||||
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))
|
||||
return -EFAULT;
|
||||
|
||||
list->tail = (list->tail + 1) & (EVDEV_BUFFER_SIZE - 1);
|
||||
client->tail = (client->tail + 1) & (EVDEV_BUFFER_SIZE - 1);
|
||||
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 */
|
||||
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);
|
||||
return ((list->head == list->tail) ? 0 : (POLLIN | POLLRDNORM)) |
|
||||
(list->evdev->exist ? 0 : (POLLHUP | POLLERR));
|
||||
poll_wait(file, &evdev->wait, wait);
|
||||
return ((client->head == client->tail) ? 0 : (POLLIN | POLLRDNORM)) |
|
||||
(evdev->exist ? 0 : (POLLHUP | POLLERR));
|
||||
}
|
||||
|
||||
#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,
|
||||
void __user *p, int compat_mode)
|
||||
{
|
||||
struct evdev_list *list = file->private_data;
|
||||
struct evdev *evdev = list->evdev;
|
||||
struct evdev_client *client = file->private_data;
|
||||
struct evdev *evdev = client->evdev;
|
||||
struct input_dev *dev = evdev->handle.dev;
|
||||
struct input_absinfo abs;
|
||||
struct ff_effect effect;
|
||||
|
@ -434,32 +451,21 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd,
|
|||
case EVIOCGKEYCODE:
|
||||
if (get_user(t, ip))
|
||||
return -EFAULT;
|
||||
if (t < 0 || t >= dev->keycodemax || !dev->keycodesize)
|
||||
return -EINVAL;
|
||||
if (put_user(INPUT_KEYCODE(dev, t), ip + 1))
|
||||
|
||||
error = dev->getkeycode(dev, t, &v);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (put_user(v, ip + 1))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
|
||||
case EVIOCSKEYCODE:
|
||||
if (get_user(t, ip))
|
||||
if (get_user(t, ip) || get_user(v, ip + 1))
|
||||
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);
|
||||
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;
|
||||
return dev->setkeycode(dev, t, v);
|
||||
|
||||
case EVIOCSFF:
|
||||
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;
|
||||
if (input_grab_device(&evdev->handle))
|
||||
return -EBUSY;
|
||||
evdev->grab = list;
|
||||
evdev->grab = client;
|
||||
return 0;
|
||||
} else {
|
||||
if (evdev->grab != list)
|
||||
if (evdev->grab != client)
|
||||
return -EINVAL;
|
||||
input_release_device(&evdev->handle);
|
||||
evdev->grab = NULL;
|
||||
|
@ -616,23 +622,26 @@ static const struct file_operations evdev_fops = {
|
|||
.flush = evdev_flush
|
||||
};
|
||||
|
||||
static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev,
|
||||
const struct input_device_id *id)
|
||||
static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
|
||||
const struct input_device_id *id)
|
||||
{
|
||||
struct evdev *evdev;
|
||||
struct class_device *cdev;
|
||||
dev_t devt;
|
||||
int minor;
|
||||
int error;
|
||||
|
||||
for (minor = 0; minor < EVDEV_MINORS && evdev_table[minor]; minor++);
|
||||
if (minor == EVDEV_MINORS) {
|
||||
printk(KERN_ERR "evdev: no more free evdev devices\n");
|
||||
return NULL;
|
||||
return -ENFILE;
|
||||
}
|
||||
|
||||
if (!(evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL)))
|
||||
return NULL;
|
||||
evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);
|
||||
if (!evdev)
|
||||
return -ENOMEM;
|
||||
|
||||
INIT_LIST_HEAD(&evdev->list);
|
||||
INIT_LIST_HEAD(&evdev->client_list);
|
||||
init_waitqueue_head(&evdev->wait);
|
||||
|
||||
evdev->exist = 1;
|
||||
|
@ -645,21 +654,43 @@ static struct input_handle *evdev_connect(struct input_handler *handler, struct
|
|||
|
||||
evdev_table[minor] = evdev;
|
||||
|
||||
cdev = class_device_create(&input_class, &dev->cdev,
|
||||
MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor),
|
||||
dev->cdev.dev, evdev->name);
|
||||
devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor),
|
||||
|
||||
cdev = class_device_create(&input_class, &dev->cdev, devt,
|
||||
dev->cdev.dev, evdev->name);
|
||||
if (IS_ERR(cdev)) {
|
||||
error = PTR_ERR(cdev);
|
||||
goto err_free_evdev;
|
||||
}
|
||||
|
||||
/* temporary symlink to keep userspace happy */
|
||||
sysfs_create_link(&input_class.subsys.kobj, &cdev->kobj,
|
||||
evdev->name);
|
||||
error = sysfs_create_link(&input_class.subsys.kobj,
|
||||
&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)
|
||||
{
|
||||
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);
|
||||
class_device_destroy(&input_class,
|
||||
|
@ -670,8 +701,8 @@ static void evdev_disconnect(struct input_handle *handle)
|
|||
input_flush_device(handle, NULL);
|
||||
input_close_device(handle);
|
||||
wake_up_interruptible(&evdev->wait);
|
||||
list_for_each_entry(list, &evdev->list, node)
|
||||
kill_fasync(&list->fasync, SIGIO, POLL_HUP);
|
||||
list_for_each_entry(client, &evdev->client_list, node)
|
||||
kill_fasync(&client->fasync, SIGIO, POLL_HUP);
|
||||
} else
|
||||
evdev_free(evdev);
|
||||
}
|
||||
|
|
|
@ -299,12 +299,87 @@ void input_close_device(struct input_handle *handle)
|
|||
}
|
||||
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);
|
||||
list_add_tail(&handle->h_node, &handle->handler->h_list);
|
||||
switch (dev->keycodesize) {
|
||||
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) \
|
||||
for (i = 0; i < NBITS(max); 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;
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
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, "P: Phys=%s\n", dev->phys ? dev->phys : "");
|
||||
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=");
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
if (dev) {
|
||||
dev->cdev.class = &input_class;
|
||||
dev->cdev.groups = input_dev_attr_groups;
|
||||
class_device_initialize(&dev->cdev);
|
||||
mutex_init(&dev->mutex);
|
||||
INIT_LIST_HEAD(&dev->h_list);
|
||||
|
@ -934,23 +1041,71 @@ EXPORT_SYMBOL(input_allocate_device);
|
|||
*/
|
||||
void input_free_device(struct input_dev *dev)
|
||||
{
|
||||
if (dev) {
|
||||
|
||||
mutex_lock(&dev->mutex);
|
||||
dev->name = dev->phys = dev->uniq = NULL;
|
||||
mutex_unlock(&dev->mutex);
|
||||
|
||||
if (dev)
|
||||
input_put_device(dev);
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
static atomic_t input_no = ATOMIC_INIT(0);
|
||||
struct input_handle *handle;
|
||||
struct input_handler *handler;
|
||||
const struct input_device_id *id;
|
||||
const char *path;
|
||||
int error;
|
||||
|
||||
|
@ -969,55 +1124,41 @@ int input_register_device(struct input_dev *dev)
|
|||
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);
|
||||
|
||||
snprintf(dev->cdev.class_id, sizeof(dev->cdev.class_id),
|
||||
"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);
|
||||
if (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);
|
||||
printk(KERN_INFO "input: %s as %s\n",
|
||||
dev->name ? dev->name : "Unspecified device", path ? path : "N/A");
|
||||
kfree(path);
|
||||
|
||||
list_for_each_entry(handler, &input_handler_list, node)
|
||||
if (!handler->blacklist || !input_match_device(handler->blacklist, dev))
|
||||
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_attach_handler(dev, handler);
|
||||
|
||||
input_wakeup_procfs_readers();
|
||||
|
||||
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);
|
||||
|
||||
void input_unregister_device(struct input_dev *dev)
|
||||
{
|
||||
struct list_head *node, *next;
|
||||
struct input_handle *handle, *next;
|
||||
int 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);
|
||||
|
||||
list_for_each_safe(node, next, &dev->h_list) {
|
||||
struct input_handle * handle = to_handle(node);
|
||||
list_del_init(&handle->d_node);
|
||||
list_del_init(&handle->h_node);
|
||||
list_for_each_entry_safe(handle, next, &dev->h_list, d_node)
|
||||
handle->handler->disconnect(handle);
|
||||
}
|
||||
WARN_ON(!list_empty(&dev->h_list));
|
||||
|
||||
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);
|
||||
|
||||
input_wakeup_procfs_readers();
|
||||
|
@ -1049,8 +1183,6 @@ EXPORT_SYMBOL(input_unregister_device);
|
|||
int input_register_handler(struct input_handler *handler)
|
||||
{
|
||||
struct input_dev *dev;
|
||||
struct input_handle *handle;
|
||||
const struct input_device_id *id;
|
||||
|
||||
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_for_each_entry(dev, &input_dev_list, node)
|
||||
if (!handler->blacklist || !input_match_device(handler->blacklist, dev))
|
||||
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_attach_handler(dev, handler);
|
||||
|
||||
input_wakeup_procfs_readers();
|
||||
return 0;
|
||||
|
@ -1079,14 +1205,11 @@ EXPORT_SYMBOL(input_register_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) {
|
||||
struct input_handle * handle = to_handle_h(node);
|
||||
list_del_init(&handle->h_node);
|
||||
list_del_init(&handle->d_node);
|
||||
list_for_each_entry_safe(handle, next, &handler->h_list, h_node)
|
||||
handler->disconnect(handle);
|
||||
}
|
||||
WARN_ON(!list_empty(&handler->h_list));
|
||||
|
||||
list_del_init(&handler->node);
|
||||
|
||||
|
@ -1097,6 +1220,27 @@ void input_unregister_handler(struct input_handler *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)
|
||||
{
|
||||
struct input_handler *handler = input_table[iminor(inode) >> 5];
|
||||
|
|
|
@ -43,7 +43,7 @@ struct joydev {
|
|||
char name[16];
|
||||
struct input_handle handle;
|
||||
wait_queue_head_t wait;
|
||||
struct list_head list;
|
||||
struct list_head client_list;
|
||||
struct js_corr corr[ABS_MAX + 1];
|
||||
struct JS_DATA_SAVE_TYPE glue;
|
||||
int nabs;
|
||||
|
@ -55,7 +55,7 @@ struct joydev {
|
|||
__s16 abs[ABS_MAX + 1];
|
||||
};
|
||||
|
||||
struct joydev_list {
|
||||
struct joydev_client {
|
||||
struct js_event buffer[JOYDEV_BUFFER_SIZE];
|
||||
int head;
|
||||
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)
|
||||
{
|
||||
struct joydev *joydev = handle->private;
|
||||
struct joydev_list *list;
|
||||
struct joydev_client *client;
|
||||
struct js_event event;
|
||||
|
||||
switch (type) {
|
||||
|
@ -115,15 +115,15 @@ static void joydev_event(struct input_handle *handle, unsigned int type, unsigne
|
|||
|
||||
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 (list->tail == (list->head = (list->head + 1) & (JOYDEV_BUFFER_SIZE - 1)))
|
||||
list->startup = 0;
|
||||
if (client->startup == joydev->nabs + joydev->nkey)
|
||||
if (client->tail == (client->head = (client->head + 1) & (JOYDEV_BUFFER_SIZE - 1)))
|
||||
client->startup = 0;
|
||||
|
||||
kill_fasync(&list->fasync, SIGIO, POLL_IN);
|
||||
kill_fasync(&client->fasync, SIGIO, POLL_IN);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@ -145,60 +145,73 @@ static void joydev_free(struct joydev *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);
|
||||
|
||||
list_del(&list->node);
|
||||
list_del(&client->node);
|
||||
kfree(client);
|
||||
|
||||
if (!--list->joydev->open) {
|
||||
if (list->joydev->exist)
|
||||
input_close_device(&list->joydev->handle);
|
||||
if (!--joydev->open) {
|
||||
if (joydev->exist)
|
||||
input_close_device(&joydev->handle);
|
||||
else
|
||||
joydev_free(list->joydev);
|
||||
joydev_free(joydev);
|
||||
}
|
||||
|
||||
kfree(list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 error;
|
||||
|
||||
if (i >= JOYDEV_MINORS || !joydev_table[i])
|
||||
if (i >= JOYDEV_MINORS)
|
||||
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;
|
||||
|
||||
list->joydev = joydev_table[i];
|
||||
list_add_tail(&list->node, &joydev_table[i]->list);
|
||||
file->private_data = list;
|
||||
client->joydev = joydev;
|
||||
list_add_tail(&client->node, &joydev->client_list);
|
||||
|
||||
if (!list->joydev->open++)
|
||||
if (list->joydev->exist)
|
||||
input_open_device(&list->joydev->handle);
|
||||
if (!joydev->open++ && joydev->exist) {
|
||||
error = input_open_device(&joydev->handle);
|
||||
if (error) {
|
||||
list_del(&client->node);
|
||||
kfree(client);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
file->private_data = client;
|
||||
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;
|
||||
}
|
||||
|
||||
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 *joydev = list->joydev;
|
||||
struct joydev_client *client = file->private_data;
|
||||
struct joydev *joydev = client->joydev;
|
||||
struct input_dev *input = joydev->handle.dev;
|
||||
int retval = 0;
|
||||
|
||||
if (!list->joydev->exist)
|
||||
if (!joydev->exist)
|
||||
return -ENODEV;
|
||||
|
||||
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)))
|
||||
return -EFAULT;
|
||||
|
||||
list->startup = 0;
|
||||
list->tail = list->head;
|
||||
client->startup = 0;
|
||||
client->tail = client->head;
|
||||
|
||||
return sizeof(struct JS_DATA_TYPE);
|
||||
}
|
||||
|
||||
if (list->startup == joydev->nabs + joydev->nkey &&
|
||||
list->head == list->tail && (file->f_flags & O_NONBLOCK))
|
||||
if (client->startup == joydev->nabs + joydev->nkey &&
|
||||
client->head == client->tail && (file->f_flags & O_NONBLOCK))
|
||||
return -EAGAIN;
|
||||
|
||||
retval = wait_event_interruptible(list->joydev->wait,
|
||||
!list->joydev->exist ||
|
||||
list->startup < joydev->nabs + joydev->nkey ||
|
||||
list->head != list->tail);
|
||||
|
||||
retval = wait_event_interruptible(joydev->wait,
|
||||
!joydev->exist ||
|
||||
client->startup < joydev->nabs + joydev->nkey ||
|
||||
client->head != client->tail);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (!list->joydev->exist)
|
||||
if (!joydev->exist)
|
||||
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;
|
||||
|
||||
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.number = list->startup;
|
||||
event.number = client->startup;
|
||||
event.value = !!test_bit(joydev->keypam[event.number], input->key);
|
||||
} else {
|
||||
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];
|
||||
}
|
||||
|
||||
if (copy_to_user(buf + retval, &event, sizeof(struct js_event)))
|
||||
return -EFAULT;
|
||||
|
||||
list->startup++;
|
||||
client->startup++;
|
||||
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;
|
||||
|
||||
list->tail = (list->tail + 1) & (JOYDEV_BUFFER_SIZE - 1);
|
||||
client->tail = (client->tail + 1) & (JOYDEV_BUFFER_SIZE - 1);
|
||||
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 */
|
||||
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);
|
||||
return ((list->head != list->tail || list->startup < list->joydev->nabs + list->joydev->nkey) ?
|
||||
(POLLIN | POLLRDNORM) : 0) | (list->joydev->exist ? 0 : (POLLHUP | POLLERR));
|
||||
poll_wait(file, &joydev->wait, wait);
|
||||
return ((client->head != client->tail || client->startup < joydev->nabs + joydev->nkey) ?
|
||||
(POLLIN | POLLRDNORM) : 0) | (joydev->exist ? 0 : (POLLHUP | POLLERR));
|
||||
}
|
||||
|
||||
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
|
||||
static long joydev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct joydev_list *list = file->private_data;
|
||||
struct joydev *joydev = list->joydev;
|
||||
struct joydev_client *client = file->private_data;
|
||||
struct joydev *joydev = client->joydev;
|
||||
void __user *argp = (void __user *)arg;
|
||||
s32 tmp32;
|
||||
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)
|
||||
{
|
||||
struct joydev_list *list = file->private_data;
|
||||
struct joydev *joydev = list->joydev;
|
||||
struct joydev_client *client = file->private_data;
|
||||
struct joydev *joydev = client->joydev;
|
||||
void __user *argp = (void __user *)arg;
|
||||
|
||||
if (!joydev->exist)
|
||||
|
@ -465,23 +478,26 @@ static const struct file_operations joydev_fops = {
|
|||
.fasync = joydev_fasync,
|
||||
};
|
||||
|
||||
static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev,
|
||||
const struct input_device_id *id)
|
||||
static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
|
||||
const struct input_device_id *id)
|
||||
{
|
||||
struct joydev *joydev;
|
||||
struct class_device *cdev;
|
||||
dev_t devt;
|
||||
int i, j, t, minor;
|
||||
int error;
|
||||
|
||||
for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++);
|
||||
if (minor == JOYDEV_MINORS) {
|
||||
printk(KERN_ERR "joydev: no more free joydev devices\n");
|
||||
return NULL;
|
||||
return -ENFILE;
|
||||
}
|
||||
|
||||
if (!(joydev = kzalloc(sizeof(struct joydev), GFP_KERNEL)))
|
||||
return NULL;
|
||||
joydev = kzalloc(sizeof(struct joydev), GFP_KERNEL);
|
||||
if (!joydev)
|
||||
return -ENOMEM;
|
||||
|
||||
INIT_LIST_HEAD(&joydev->list);
|
||||
INIT_LIST_HEAD(&joydev->client_list);
|
||||
init_waitqueue_head(&joydev->wait);
|
||||
|
||||
joydev->minor = minor;
|
||||
|
@ -534,21 +550,44 @@ static struct input_handle *joydev_connect(struct input_handler *handler, struct
|
|||
|
||||
joydev_table[minor] = joydev;
|
||||
|
||||
cdev = class_device_create(&input_class, &dev->cdev,
|
||||
MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor),
|
||||
dev->cdev.dev, joydev->name);
|
||||
devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor),
|
||||
|
||||
cdev = class_device_create(&input_class, &dev->cdev, devt,
|
||||
dev->cdev.dev, joydev->name);
|
||||
if (IS_ERR(cdev)) {
|
||||
error = PTR_ERR(cdev);
|
||||
goto err_free_joydev;
|
||||
}
|
||||
|
||||
/* temporary symlink to keep userspace happy */
|
||||
sysfs_create_link(&input_class.subsys.kobj, &cdev->kobj,
|
||||
joydev->name);
|
||||
error = sysfs_create_link(&input_class.subsys.kobj,
|
||||
&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)
|
||||
{
|
||||
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);
|
||||
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) {
|
||||
input_close_device(handle);
|
||||
wake_up_interruptible(&joydev->wait);
|
||||
list_for_each_entry(list, &joydev->list, node)
|
||||
kill_fasync(&list->fasync, SIGIO, POLL_HUP);
|
||||
list_for_each_entry(client, &joydev->client_list, node)
|
||||
kill_fasync(&client->fasync, SIGIO, POLL_HUP);
|
||||
} else
|
||||
joydev_free(joydev);
|
||||
}
|
||||
|
|
|
@ -241,7 +241,7 @@ static void a3d_adc_close(struct gameport *gameport)
|
|||
|
||||
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);
|
||||
return 0;
|
||||
|
@ -253,7 +253,7 @@ static int a3d_open(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);
|
||||
}
|
||||
|
@ -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.product = a3d->mode;
|
||||
input_dev->id.version = 0x0100;
|
||||
input_dev->cdev.dev = &gameport->dev;
|
||||
input_dev->private = a3d;
|
||||
input_dev->dev.parent = &gameport->dev;
|
||||
input_dev->open = a3d_open;
|
||||
input_dev->close = a3d_close;
|
||||
|
||||
input_set_drvdata(input_dev, a3d);
|
||||
|
||||
if (a3d->mode == A3D_MODE_PXL) {
|
||||
|
||||
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)
|
||||
{
|
||||
struct adi_port *port = dev->private;
|
||||
struct adi_port *port = input_get_drvdata(dev);
|
||||
|
||||
gameport_start_polling(port->gameport);
|
||||
return 0;
|
||||
|
@ -302,7 +302,7 @@ static int adi_open(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);
|
||||
}
|
||||
|
@ -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.product = adi->id;
|
||||
input_dev->id.version = 0x0100;
|
||||
input_dev->cdev.dev = &port->gameport->dev;
|
||||
input_dev->private = port;
|
||||
input_dev->dev.parent = &port->gameport->dev;
|
||||
|
||||
input_set_drvdata(input_dev, port);
|
||||
|
||||
input_dev->open = adi_open;
|
||||
input_dev->close = adi_close;
|
||||
|
|
|
@ -343,7 +343,7 @@ static void analog_poll(struct gameport *gameport)
|
|||
|
||||
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);
|
||||
return 0;
|
||||
|
@ -355,7 +355,7 @@ static int analog_open(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);
|
||||
}
|
||||
|
@ -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.product = analog->mask >> 4;
|
||||
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->close = analog_close;
|
||||
input_dev->private = port;
|
||||
|
||||
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
|
||||
|
||||
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)
|
||||
{
|
||||
struct cobra *cobra = dev->private;
|
||||
struct cobra *cobra = input_get_drvdata(dev);
|
||||
|
||||
gameport_start_polling(cobra->gameport);
|
||||
return 0;
|
||||
|
@ -150,7 +150,7 @@ static int cobra_open(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);
|
||||
}
|
||||
|
@ -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.product = 0x0008;
|
||||
input_dev->id.version = 0x0100;
|
||||
input_dev->cdev.dev = &gameport->dev;
|
||||
input_dev->private = cobra;
|
||||
input_dev->dev.parent = &gameport->dev;
|
||||
|
||||
input_set_drvdata(input_dev, cobra);
|
||||
|
||||
input_dev->open = cobra_open;
|
||||
input_dev->close = cobra_close;
|
||||
|
|
|
@ -518,7 +518,7 @@ static void db9_timer(unsigned long private)
|
|||
|
||||
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;
|
||||
int err;
|
||||
|
||||
|
@ -542,7 +542,7 @@ static int db9_open(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;
|
||||
|
||||
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.product = mode;
|
||||
input_dev->id.version = 0x0100;
|
||||
input_dev->private = db9;
|
||||
|
||||
input_set_drvdata(input_dev, db9);
|
||||
|
||||
input_dev->open = db9_open;
|
||||
input_dev->close = db9_close;
|
||||
|
|
|
@ -591,7 +591,7 @@ static void gc_timer(unsigned long private)
|
|||
|
||||
static int gc_open(struct input_dev *dev)
|
||||
{
|
||||
struct gc *gc = dev->private;
|
||||
struct gc *gc = input_get_drvdata(dev);
|
||||
int err;
|
||||
|
||||
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)
|
||||
{
|
||||
struct gc *gc = dev->private;
|
||||
struct gc *gc = input_get_drvdata(dev);
|
||||
|
||||
mutex_lock(&gc->mutex);
|
||||
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.product = pad_type;
|
||||
input_dev->id.version = 0x0100;
|
||||
input_dev->private = gc;
|
||||
|
||||
input_set_drvdata(input_dev, gc);
|
||||
|
||||
input_dev->open = gc_open;
|
||||
input_dev->close = gc_close;
|
||||
|
|
|
@ -220,7 +220,7 @@ static void gf2k_poll(struct gameport *gameport)
|
|||
|
||||
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);
|
||||
return 0;
|
||||
|
@ -228,7 +228,7 @@ static int gf2k_open(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);
|
||||
}
|
||||
|
@ -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.product = gf2k->id;
|
||||
input_dev->id.version = 0x0100;
|
||||
input_dev->cdev.dev = &gameport->dev;
|
||||
input_dev->private = gf2k;
|
||||
input_dev->dev.parent = &gameport->dev;
|
||||
|
||||
input_set_drvdata(input_dev, gf2k);
|
||||
|
||||
input_dev->open = gf2k_open;
|
||||
input_dev->close = gf2k_close;
|
||||
|
||||
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
|
||||
|
||||
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)
|
||||
{
|
||||
struct grip *grip = dev->private;
|
||||
struct grip *grip = input_get_drvdata(dev);
|
||||
|
||||
gameport_start_polling(grip->gameport);
|
||||
return 0;
|
||||
|
@ -293,7 +293,7 @@ static int grip_open(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);
|
||||
}
|
||||
|
@ -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.product = grip->mode[i];
|
||||
input_dev->id.version = 0x0100;
|
||||
input_dev->cdev.dev = &gameport->dev;
|
||||
input_dev->private = grip;
|
||||
input_dev->dev.parent = &gameport->dev;
|
||||
|
||||
input_set_drvdata(input_dev, grip);
|
||||
|
||||
input_dev->open = grip_open;
|
||||
input_dev->close = grip_close;
|
||||
|
|
|
@ -562,7 +562,7 @@ static void grip_poll(struct gameport *gameport)
|
|||
|
||||
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);
|
||||
return 0;
|
||||
|
@ -574,9 +574,9 @@ static int grip_open(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.product = 0x0100 + port->mode;
|
||||
input_dev->id.version = 0x0100;
|
||||
input_dev->cdev.dev = &grip->gameport->dev;
|
||||
input_dev->private = grip;
|
||||
input_dev->dev.parent = &grip->gameport->dev;
|
||||
|
||||
input_set_drvdata(input_dev, grip);
|
||||
|
||||
input_dev->open = grip_open;
|
||||
input_dev->close = grip_close;
|
||||
|
|
|
@ -156,7 +156,7 @@ static void guillemot_poll(struct gameport *gameport)
|
|||
|
||||
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);
|
||||
return 0;
|
||||
|
@ -168,7 +168,7 @@ static int guillemot_open(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);
|
||||
}
|
||||
|
@ -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.product = guillemot_type[i].id;
|
||||
input_dev->id.version = (int)data[14] << 8 | data[15];
|
||||
input_dev->cdev.dev = &gameport->dev;
|
||||
input_dev->private = guillemot;
|
||||
input_dev->dev.parent = &gameport->dev;
|
||||
|
||||
input_set_drvdata(input_dev, guillemot);
|
||||
|
||||
input_dev->open = guillemot_open;
|
||||
input_dev->close = guillemot_close;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* $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) 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.
|
||||
*/
|
||||
|
@ -205,7 +205,7 @@ static int need_condition_modifier(struct ff_effect *old, struct ff_effect *new)
|
|||
int i;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -258,7 +258,7 @@ static int need_envelope_modifier(struct ff_effect *old, struct ff_effect *effec
|
|||
break;
|
||||
|
||||
default:
|
||||
printk(KERN_WARNING "iforce.c: bad effect type in need_envelope_modifier\n");
|
||||
warn("bad effect type in need_envelope_modifier");
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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 (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 $
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
@ -29,7 +29,7 @@
|
|||
|
||||
#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_LICENSE("GPL");
|
||||
|
||||
|
@ -220,7 +220,7 @@ static void iforce_release(struct input_dev *dev)
|
|||
/* Check: no effects should be present in memory */
|
||||
for (i = 0; i < dev->ff->max_effects; i++) {
|
||||
if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags)) {
|
||||
printk(KERN_WARNING "iforce_release: Device still owns effects\n");
|
||||
warn("iforce_release: Device still owns effects");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -232,7 +232,7 @@ static void iforce_release(struct input_dev *dev)
|
|||
switch (iforce->bus) {
|
||||
#ifdef CONFIG_JOYSTICK_IFORCE_USB
|
||||
case IFORCE_USB:
|
||||
usb_unlink_urb(iforce->irq);
|
||||
usb_kill_urb(iforce->irq);
|
||||
|
||||
/* The device was unplugged before the file
|
||||
* was released */
|
||||
|
@ -287,13 +287,13 @@ int iforce_init_device(struct iforce *iforce)
|
|||
#ifdef CONFIG_JOYSTICK_IFORCE_USB
|
||||
case IFORCE_USB:
|
||||
input_dev->id.bustype = BUS_USB;
|
||||
input_dev->cdev.dev = &iforce->usbdev->dev;
|
||||
input_dev->dev.parent = &iforce->usbdev->dev;
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_JOYSTICK_IFORCE_232
|
||||
case IFORCE_232:
|
||||
input_dev->id.bustype = BUS_RS232;
|
||||
input_dev->cdev.dev = &iforce->serio->dev;
|
||||
input_dev->dev.parent = &iforce->serio->dev;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
@ -324,7 +324,7 @@ int iforce_init_device(struct iforce *iforce)
|
|||
break;
|
||||
|
||||
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;
|
||||
goto fail;
|
||||
}
|
||||
|
@ -336,26 +336,26 @@ int iforce_init_device(struct iforce *iforce)
|
|||
if (!iforce_get_id_packet(iforce, "M"))
|
||||
input_dev->id.vendor = (iforce->edata[2] << 8) | iforce->edata[1];
|
||||
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"))
|
||||
input_dev->id.product = (iforce->edata[2] << 8) | iforce->edata[1];
|
||||
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"))
|
||||
iforce->device_memory.end = (iforce->edata[2] << 8) | iforce->edata[1];
|
||||
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"))
|
||||
ff_effects = iforce->edata[1];
|
||||
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 */
|
||||
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);
|
||||
ff_effects = IFORCE_EFFECTS_MAX;
|
||||
}
|
||||
|
@ -457,8 +457,6 @@ int iforce_init_device(struct iforce *iforce)
|
|||
if (error)
|
||||
goto fail;
|
||||
|
||||
printk(KERN_DEBUG "iforce->dev->open = %p\n", iforce->dev->open);
|
||||
|
||||
return 0;
|
||||
|
||||
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 $
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
@ -39,10 +39,10 @@ void iforce_dump_packet(char *msg, u16 cmd, unsigned char *data)
|
|||
{
|
||||
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++)
|
||||
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;
|
||||
tail = iforce->xmit.tail;
|
||||
|
||||
|
||||
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);
|
||||
return -1;
|
||||
}
|
||||
|
@ -126,8 +127,6 @@ int iforce_control_playback(struct iforce* iforce, u16 id, unsigned int value)
|
|||
{
|
||||
unsigned char data[3];
|
||||
|
||||
printk(KERN_DEBUG "iforce-packets.c: control_playback %d %d\n", id, value);
|
||||
|
||||
data[0] = LO(id);
|
||||
data[1] = (value > 0) ? ((value > 1) ? 0x41 : 0x01) : 0;
|
||||
data[2] = LO(value);
|
||||
|
@ -151,7 +150,7 @@ static int mark_core_as_ready(struct iforce *iforce, unsigned short addr)
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
printk(KERN_WARNING "iforce-packets.c: unused effect %04x updated !!!\n", addr);
|
||||
warn("unused effect %04x updated !!!", addr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -162,7 +161,7 @@ void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data)
|
|||
static int being_used = 0;
|
||||
|
||||
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++;
|
||||
|
||||
#ifdef CONFIG_JOYSTICK_IFORCE_232
|
||||
|
@ -266,7 +265,7 @@ int iforce_get_id_packet(struct iforce *iforce, char *packet)
|
|||
return -1;
|
||||
}
|
||||
#else
|
||||
printk(KERN_ERR "iforce_get_id_packet: iforce->bus = USB!\n");
|
||||
err("iforce_get_id_packet: iforce->bus = USB!");
|
||||
#endif
|
||||
break;
|
||||
|
||||
|
@ -284,13 +283,12 @@ int iforce_get_id_packet(struct iforce *iforce, char *packet)
|
|||
return -1;
|
||||
}
|
||||
#else
|
||||
printk(KERN_ERR "iforce_get_id_packet: iforce->bus = SERIO!\n");
|
||||
err("iforce_get_id_packet: iforce->bus = SERIO!");
|
||||
#endif
|
||||
break;
|
||||
|
||||
default:
|
||||
printk(KERN_ERR "iforce_get_id_packet: iforce->bus = %d\n",
|
||||
iforce->bus);
|
||||
err("iforce_get_id_packet: iforce->bus = %d", iforce->bus);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* $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) 2001 Johann Deneux <deneux@ifrance.com>
|
||||
* Copyright (c) 2001, 2007 Johann Deneux <johann.deneux@gmail.com>
|
||||
*
|
||||
* 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 $
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
@ -65,7 +65,7 @@ void iforce_usb_xmit(struct iforce *iforce)
|
|||
XMIT_INC(iforce->xmit.tail, n);
|
||||
|
||||
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.
|
||||
|
@ -110,7 +110,7 @@ static void iforce_usb_out(struct urb *urb)
|
|||
struct iforce *iforce = urb->context;
|
||||
|
||||
if (urb->status) {
|
||||
printk(KERN_DEBUG "iforce_usb_out: urb->status %d, exiting", urb->status);
|
||||
dbg("urb->status %d, exiting", urb->status);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -190,10 +190,9 @@ static int iforce_usb_probe(struct usb_interface *intf,
|
|||
/* Called by iforce_delete() */
|
||||
void iforce_usb_delete(struct iforce* iforce)
|
||||
{
|
||||
usb_unlink_urb(iforce->irq);
|
||||
/* Is it ok to unlink those ? */
|
||||
usb_unlink_urb(iforce->out);
|
||||
usb_unlink_urb(iforce->ctrl);
|
||||
usb_kill_urb(iforce->irq);
|
||||
usb_kill_urb(iforce->out);
|
||||
usb_kill_urb(iforce->ctrl);
|
||||
|
||||
usb_free_urb(iforce->irq);
|
||||
usb_free_urb(iforce->out);
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* $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) 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.
|
||||
*/
|
||||
|
|
|
@ -185,7 +185,7 @@ static void interact_poll(struct gameport *gameport)
|
|||
|
||||
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);
|
||||
return 0;
|
||||
|
@ -197,7 +197,7 @@ static int interact_open(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);
|
||||
}
|
||||
|
@ -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.product = interact_type[i].id;
|
||||
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->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.product = 0x0001;
|
||||
input_dev->id.version = 0x0100;
|
||||
input_dev->cdev.dev = &serio->dev;
|
||||
input_dev->private = magellan;
|
||||
input_dev->dev.parent = &serio->dev;
|
||||
|
||||
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)
|
||||
{
|
||||
struct sw *sw = dev->private;
|
||||
struct sw *sw = input_get_drvdata(dev);
|
||||
|
||||
gameport_start_polling(sw->gameport);
|
||||
return 0;
|
||||
|
@ -517,7 +517,7 @@ static int sw_open(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);
|
||||
}
|
||||
|
@ -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.product = sw->type;
|
||||
input_dev->id.version = 0x0100;
|
||||
input_dev->cdev.dev = &gameport->dev;
|
||||
input_dev->private = sw;
|
||||
input_dev->dev.parent = &gameport->dev;
|
||||
|
||||
input_set_drvdata(input_dev, sw);
|
||||
|
||||
input_dev->open = sw_open;
|
||||
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.product = id;
|
||||
input_dev->id.version = 0x0100;
|
||||
input_dev->cdev.dev = &serio->dev;
|
||||
input_dev->private = spaceball;
|
||||
input_dev->dev.parent = &serio->dev;
|
||||
|
||||
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.product = 0x0001;
|
||||
input_dev->id.version = 0x0100;
|
||||
input_dev->cdev.dev = &serio->dev;
|
||||
input_dev->private = spaceorb;
|
||||
input_dev->dev.parent = &serio->dev;
|
||||
|
||||
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.product = 0x0001;
|
||||
input_dev->id.version = 0x0100;
|
||||
input_dev->cdev.dev = &serio->dev;
|
||||
input_dev->private = stinger;
|
||||
input_dev->dev.parent = &serio->dev;
|
||||
|
||||
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) |
|
||||
|
|
|
@ -265,7 +265,7 @@ static void tmdc_poll(struct gameport *gameport)
|
|||
|
||||
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);
|
||||
return 0;
|
||||
|
@ -273,7 +273,7 @@ static int tmdc_open(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);
|
||||
}
|
||||
|
@ -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.product = model->id;
|
||||
input_dev->id.version = 0x0100;
|
||||
input_dev->cdev.dev = &tmdc->gameport->dev;
|
||||
input_dev->private = tmdc;
|
||||
input_dev->dev.parent = &tmdc->gameport->dev;
|
||||
|
||||
input_set_drvdata(input_dev, tmdc);
|
||||
|
||||
input_dev->open = tmdc_open;
|
||||
input_dev->close = tmdc_close;
|
||||
|
|
|
@ -122,7 +122,7 @@ static void tgfx_timer(unsigned long private)
|
|||
|
||||
static int tgfx_open(struct input_dev *dev)
|
||||
{
|
||||
struct tgfx *tgfx = dev->private;
|
||||
struct tgfx *tgfx = input_get_drvdata(dev);
|
||||
int err;
|
||||
|
||||
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)
|
||||
{
|
||||
struct tgfx *tgfx = dev->private;
|
||||
struct tgfx *tgfx = input_get_drvdata(dev);
|
||||
|
||||
mutex_lock(&tgfx->sem);
|
||||
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.version = 0x0100;
|
||||
|
||||
input_dev->private = tgfx;
|
||||
input_set_drvdata(input_dev, tgfx);
|
||||
|
||||
input_dev->open = tgfx_open;
|
||||
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.product = 0x0001;
|
||||
input_dev->id.version = 0x0100;
|
||||
input_dev->cdev.dev = &serio->dev;
|
||||
input_dev->private = twidjoy;
|
||||
input_dev->dev.parent = &serio->dev;
|
||||
|
||||
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_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.product = 0x0001;
|
||||
input_dev->id.version = 0x0100;
|
||||
input_dev->cdev.dev = &serio->dev;
|
||||
input_dev->private = warrior;
|
||||
input_dev->dev.parent = &serio->dev;
|
||||
|
||||
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);
|
||||
|
|
|
@ -214,6 +214,15 @@ config KEYBOARD_OMAP
|
|||
To compile this driver as a module, choose M here: the
|
||||
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
|
||||
tristate "AAED-2000 keyboard"
|
||||
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_OLD) += hilkbd.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_GPIO) += gpio_keys.o
|
||||
|
||||
|
|
|
@ -97,7 +97,7 @@ static void aaedkbd_work(void *data)
|
|||
|
||||
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));
|
||||
|
||||
|
@ -106,7 +106,7 @@ static int aaedkbd_open(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);
|
||||
flush_scheduled_work();
|
||||
|
@ -141,8 +141,9 @@ static int __devinit aaedkbd_probe(struct platform_device *pdev)
|
|||
input_dev->id.vendor = 0x0001;
|
||||
input_dev->id.product = 0x0001;
|
||||
input_dev->id.version = 0x0100;
|
||||
input_dev->cdev.dev = &pdev->dev;
|
||||
input_dev->private = aaedkbd;
|
||||
input_dev->dev.parent = &pdev->dev;
|
||||
|
||||
input_set_drvdata(input_dev, aaedkbd);
|
||||
|
||||
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
|
||||
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)
|
||||
{
|
||||
struct atkbd *atkbd = dev->private;
|
||||
struct atkbd *atkbd = input_get_drvdata(dev);
|
||||
|
||||
if (!atkbd->write)
|
||||
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.version = atkbd->id;
|
||||
input_dev->event = atkbd_event;
|
||||
input_dev->private = atkbd;
|
||||
input_dev->cdev.dev = &atkbd->ps2dev.serio->dev;
|
||||
input_dev->dev.parent = &atkbd->ps2dev.serio->dev;
|
||||
|
||||
input_set_drvdata(input_dev, atkbd);
|
||||
|
||||
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.product = 0x0001;
|
||||
input_dev->id.version = 0x0100;
|
||||
input_dev->cdev.dev = &pdev->dev;
|
||||
input_dev->private = corgikbd;
|
||||
input_dev->dev.parent = &pdev->dev;
|
||||
|
||||
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_PWR) | BIT(EV_SW);
|
||||
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);
|
||||
|
||||
for (i = 0; i < pdata->nbuttons; i++) {
|
||||
int gpio = pdata->buttons[i].gpio;
|
||||
if (irq == gpio_to_irq(gpio)) {
|
||||
int state = (gpio_get_value(gpio) ? 1 : 0) ^ (pdata->buttons[i].active_low);
|
||||
struct gpio_keys_button *button = &pdata->buttons[i];
|
||||
int gpio = button->gpio;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -63,8 +66,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
|
|||
|
||||
input->name = pdev->name;
|
||||
input->phys = "gpio-keys/input0";
|
||||
input->cdev.dev = &pdev->dev;
|
||||
input->private = pdata;
|
||||
input->dev.parent = &pdev->dev;
|
||||
|
||||
input->id.bustype = BUS_HOST;
|
||||
input->id.vendor = 0x0001;
|
||||
|
@ -72,19 +74,21 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
|
|||
input->id.version = 0x0100;
|
||||
|
||||
for (i = 0; i < pdata->nbuttons; i++) {
|
||||
int code = pdata->buttons[i].keycode;
|
||||
int irq = gpio_to_irq(pdata->buttons[i].gpio);
|
||||
struct gpio_keys_button *button = &pdata->buttons[i];
|
||||
int irq = gpio_to_irq(button->gpio);
|
||||
unsigned int type = button->type ?: EV_KEY;
|
||||
|
||||
set_irq_type(irq, IRQ_TYPE_EDGE_BOTH);
|
||||
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);
|
||||
if (error) {
|
||||
printk(KERN_ERR "gpio-keys: unable to claim irq %d; error %d\n",
|
||||
irq, error);
|
||||
goto fail;
|
||||
}
|
||||
set_bit(code, input->keybit);
|
||||
|
||||
input_set_capability(input, type, button->code);
|
||||
}
|
||||
|
||||
error = input_register_device(input);
|
||||
|
|
|
@ -51,7 +51,7 @@ MODULE_LICENSE("Dual BSD/GPL");
|
|||
|
||||
#define HIL_KBD_SET1_UPBIT 0x01
|
||||
#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 };
|
||||
|
||||
#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_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 };
|
||||
|
||||
static char hil_language[][16] = { HIL_LOCALE_MAP };
|
||||
static const char hil_language[][16] = { HIL_LOCALE_MAP };
|
||||
|
||||
struct hil_kbd {
|
||||
struct input_dev *dev;
|
||||
|
@ -94,10 +94,12 @@ static void hil_kbd_process_record(struct hil_kbd *kbd)
|
|||
idx = kbd->idx4/4;
|
||||
p = data[idx - 1];
|
||||
|
||||
if ((p & ~HIL_CMDCT_POL) ==
|
||||
(HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL)) goto report;
|
||||
if ((p & ~HIL_CMDCT_RPL) ==
|
||||
(HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL)) goto report;
|
||||
if ((p & ~HIL_CMDCT_POL) ==
|
||||
(HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL))
|
||||
goto report;
|
||||
if ((p & ~HIL_CMDCT_RPL) ==
|
||||
(HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL))
|
||||
goto report;
|
||||
|
||||
/* Not a poll response. See if we are loading config records. */
|
||||
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++)
|
||||
kbd->idd[i] = 0;
|
||||
break;
|
||||
|
||||
case HIL_CMD_RSC:
|
||||
for (i = 0; i < idx; i++)
|
||||
kbd->rsc[i] = kbd->data[i] & HIL_PKT_DATA_MASK;
|
||||
for (; i < HIL_KBD_MAX_LENGTH; i++)
|
||||
kbd->rsc[i] = 0;
|
||||
break;
|
||||
|
||||
case HIL_CMD_EXD:
|
||||
for (i = 0; i < idx; i++)
|
||||
kbd->exd[i] = kbd->data[i] & HIL_PKT_DATA_MASK;
|
||||
for (; i < HIL_KBD_MAX_LENGTH; i++)
|
||||
kbd->exd[i] = 0;
|
||||
break;
|
||||
|
||||
case HIL_CMD_RNM:
|
||||
for (i = 0; i < idx; i++)
|
||||
kbd->rnm[i] = kbd->data[i] & HIL_PKT_DATA_MASK;
|
||||
for (; i < HIL_KBD_MAX_LENGTH + 1; i++)
|
||||
kbd->rnm[i] = '\0';
|
||||
break;
|
||||
|
||||
default:
|
||||
/* 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. */
|
||||
printk(KERN_WARNING PREFIX "Device sent unknown record %x\n", p);
|
||||
break;
|
||||
|
@ -139,16 +146,19 @@ static void hil_kbd_process_record(struct hil_kbd *kbd)
|
|||
switch (kbd->data[0] & HIL_POL_CHARTYPE_MASK) {
|
||||
case HIL_POL_CHARTYPE_NONE:
|
||||
break;
|
||||
|
||||
case HIL_POL_CHARTYPE_ASCII:
|
||||
while (cnt < idx - 1)
|
||||
input_report_key(dev, kbd->data[cnt++] & 0x7f, 1);
|
||||
break;
|
||||
|
||||
case HIL_POL_CHARTYPE_RSVD1:
|
||||
case HIL_POL_CHARTYPE_RSVD2:
|
||||
case HIL_POL_CHARTYPE_BINARY:
|
||||
while (cnt < idx - 1)
|
||||
input_report_key(dev, kbd->data[cnt++], 1);
|
||||
break;
|
||||
|
||||
case HIL_POL_CHARTYPE_SET1:
|
||||
while (cnt < idx - 1) {
|
||||
unsigned int key;
|
||||
|
@ -161,6 +171,7 @@ static void hil_kbd_process_record(struct hil_kbd *kbd)
|
|||
input_report_key(dev, key, !up);
|
||||
}
|
||||
break;
|
||||
|
||||
case HIL_POL_CHARTYPE_SET2:
|
||||
while (cnt < idx - 1) {
|
||||
unsigned int key;
|
||||
|
@ -173,6 +184,7 @@ static void hil_kbd_process_record(struct hil_kbd *kbd)
|
|||
input_report_key(dev, key, !up);
|
||||
}
|
||||
break;
|
||||
|
||||
case HIL_POL_CHARTYPE_SET3:
|
||||
while (cnt < idx - 1) {
|
||||
unsigned int key;
|
||||
|
@ -191,42 +203,43 @@ static void hil_kbd_process_record(struct hil_kbd *kbd)
|
|||
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");
|
||||
kbd->idx4 = 0;
|
||||
up(&kbd->sem);
|
||||
}
|
||||
|
||||
static irqreturn_t hil_kbd_interrupt(struct serio *serio,
|
||||
unsigned char data, unsigned int flags)
|
||||
static irqreturn_t hil_kbd_interrupt(struct serio *serio,
|
||||
unsigned char data, unsigned int flags)
|
||||
{
|
||||
struct hil_kbd *kbd;
|
||||
hil_packet packet;
|
||||
int idx;
|
||||
|
||||
kbd = serio_get_drvdata(serio);
|
||||
if (kbd == NULL) {
|
||||
BUG();
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
BUG_ON(kbd == NULL);
|
||||
|
||||
if (kbd->idx4 >= (HIL_KBD_MAX_LENGTH * sizeof(hil_packet))) {
|
||||
hil_kbd_process_err(kbd);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
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 |= ((hil_packet)data) << ((3 - (kbd->idx4 % 4)) * 8);
|
||||
kbd->data[idx] = packet;
|
||||
|
||||
/* 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) {
|
||||
hil_kbd_process_err(kbd);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -235,10 +248,7 @@ static void hil_kbd_disconnect(struct serio *serio)
|
|||
struct hil_kbd *kbd;
|
||||
|
||||
kbd = serio_get_drvdata(serio);
|
||||
if (kbd == NULL) {
|
||||
BUG();
|
||||
return;
|
||||
}
|
||||
BUG_ON(kbd == NULL);
|
||||
|
||||
serio_close(serio);
|
||||
input_unregister_device(kbd->dev);
|
||||
|
@ -259,42 +269,40 @@ static int hil_kbd_connect(struct serio *serio, struct serio_driver *drv)
|
|||
if (!kbd->dev)
|
||||
goto bail0;
|
||||
|
||||
kbd->dev->private = kbd;
|
||||
|
||||
if (serio_open(serio, drv))
|
||||
goto bail1;
|
||||
|
||||
serio_set_drvdata(serio, kbd);
|
||||
kbd->serio = serio;
|
||||
|
||||
init_MUTEX_LOCKED(&(kbd->sem));
|
||||
init_MUTEX_LOCKED(&kbd->sem);
|
||||
|
||||
/* Get device info. MLC driver supplies devid/status/etc. */
|
||||
serio->write(serio, 0);
|
||||
serio->write(serio, 0);
|
||||
serio->write(serio, HIL_PKT_CMD >> 8);
|
||||
serio->write(serio, HIL_CMD_IDD);
|
||||
down(&(kbd->sem));
|
||||
down(&kbd->sem);
|
||||
|
||||
serio->write(serio, 0);
|
||||
serio->write(serio, 0);
|
||||
serio->write(serio, HIL_PKT_CMD >> 8);
|
||||
serio->write(serio, HIL_CMD_RSC);
|
||||
down(&(kbd->sem));
|
||||
down(&kbd->sem);
|
||||
|
||||
serio->write(serio, 0);
|
||||
serio->write(serio, 0);
|
||||
serio->write(serio, HIL_PKT_CMD >> 8);
|
||||
serio->write(serio, HIL_CMD_RNM);
|
||||
down(&(kbd->sem));
|
||||
down(&kbd->sem);
|
||||
|
||||
serio->write(serio, 0);
|
||||
serio->write(serio, 0);
|
||||
serio->write(serio, HIL_PKT_CMD >> 8);
|
||||
serio->write(serio, HIL_CMD_EXD);
|
||||
down(&(kbd->sem));
|
||||
down(&kbd->sem);
|
||||
|
||||
up(&(kbd->sem));
|
||||
up(&kbd->sem);
|
||||
|
||||
did = kbd->idd[0];
|
||||
idd = kbd->idd + 1;
|
||||
|
@ -310,12 +318,11 @@ static int hil_kbd_connect(struct serio *serio, struct serio_driver *drv)
|
|||
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");
|
||||
goto bail2;
|
||||
}
|
||||
|
||||
|
||||
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->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.product = 0x0001; /* 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++) {
|
||||
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, HIL_PKT_CMD >> 8);
|
||||
serio->write(serio, HIL_CMD_EK1); /* Enable Keyswitch Autorepeat 1 */
|
||||
down(&(kbd->sem));
|
||||
up(&(kbd->sem));
|
||||
down(&kbd->sem);
|
||||
up(&kbd->sem);
|
||||
|
||||
return 0;
|
||||
bail2:
|
||||
|
@ -368,26 +375,26 @@ static struct serio_device_id hil_kbd_ids[] = {
|
|||
{ 0 }
|
||||
};
|
||||
|
||||
struct serio_driver hil_kbd_serio_drv = {
|
||||
static struct serio_driver hil_kbd_serio_drv = {
|
||||
.driver = {
|
||||
.name = "hil_kbd",
|
||||
},
|
||||
.description = "HP HIL keyboard driver",
|
||||
.id_table = hil_kbd_ids,
|
||||
.connect = hil_kbd_connect,
|
||||
.disconnect = hil_kbd_disconnect,
|
||||
.interrupt = hil_kbd_interrupt
|
||||
.connect = hil_kbd_connect,
|
||||
.disconnect = hil_kbd_disconnect,
|
||||
.interrupt = hil_kbd_interrupt
|
||||
};
|
||||
|
||||
static int __init hil_kbd_init(void)
|
||||
{
|
||||
return serio_register_driver(&hil_kbd_serio_drv);
|
||||
}
|
||||
|
||||
|
||||
static void __exit hil_kbd_exit(void)
|
||||
{
|
||||
serio_unregister_driver(&hil_kbd_serio_drv);
|
||||
}
|
||||
|
||||
|
||||
module_init(hil_kbd_init);
|
||||
module_exit(hil_kbd_exit);
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Copyright (C) 1998 Philip Blundell <philb@gnu.org>
|
||||
* 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.
|
||||
* 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_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 structure */
|
||||
|
@ -211,10 +211,10 @@ hil_keyb_init(void)
|
|||
return -ENODEV; /* already initialized */
|
||||
}
|
||||
|
||||
spin_lock_init(&hil_dev.lock);
|
||||
hil_dev.dev = input_allocate_device();
|
||||
if (!hil_dev.dev)
|
||||
return -ENOMEM;
|
||||
hil_dev.dev->private = &hil_dev;
|
||||
|
||||
#if defined(CONFIG_HP300)
|
||||
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,
|
||||
int value)
|
||||
{
|
||||
struct lkkbd *lk = dev->private;
|
||||
struct lkkbd *lk = input_get_drvdata (dev);
|
||||
unsigned char leds_on = 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.product = 0;
|
||||
input_dev->id.version = 0x0100;
|
||||
input_dev->cdev.dev = &serio->dev;
|
||||
input_dev->dev.parent = &serio->dev;
|
||||
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_LED, input_dev->evbit);
|
||||
|
|
|
@ -231,7 +231,7 @@ static int locomokbd_probe(struct locomo_dev *dev)
|
|||
input_dev->id.vendor = 0x0001;
|
||||
input_dev->id.product = 0x0001;
|
||||
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->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.product = 0x0001;
|
||||
input_dev->id.version = 0x0100;
|
||||
input_dev->cdev.dev = &serio->dev;
|
||||
input_dev->private = nkbd;
|
||||
input_dev->dev.parent = &serio->dev;
|
||||
|
||||
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
|
||||
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);
|
||||
input_dev->name = "omap-keypad";
|
||||
input_dev->phys = "omap-keypad/input0";
|
||||
input_dev->cdev.dev = &pdev->dev;
|
||||
input_dev->private = omap_kp;
|
||||
input_dev->dev.parent = &pdev->dev;
|
||||
|
||||
input_dev->id.bustype = BUS_HOST;
|
||||
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;
|
||||
|
||||
input_dev->private = spitzkbd;
|
||||
input_dev->name = "Spitz Keyboard";
|
||||
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.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.product = 0x0001;
|
||||
input_dev->id.version = 0x0100;
|
||||
input_dev->cdev.dev = &serio->dev;
|
||||
input_dev->private = skbd;
|
||||
input_dev->dev.parent = &serio->dev;
|
||||
|
||||
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
|
||||
input_dev->keycode = skbd->keycode;
|
||||
|
|
|
@ -146,7 +146,7 @@ static irqreturn_t sunkbd_interrupt(struct serio *serio,
|
|||
|
||||
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) {
|
||||
|
||||
|
@ -271,8 +271,10 @@ static int sunkbd_connect(struct serio *serio, struct serio_driver *drv)
|
|||
input_dev->id.vendor = SERIO_SUNKBD;
|
||||
input_dev->id.product = sunkbd->type;
|
||||
input_dev->id.version = 0x0100;
|
||||
input_dev->cdev.dev = &serio->dev;
|
||||
input_dev->private = sunkbd;
|
||||
input_dev->dev.parent = &serio->dev;
|
||||
|
||||
input_set_drvdata(input_dev, sunkbd);
|
||||
|
||||
input_dev->event = sunkbd_event;
|
||||
|
||||
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.product = 0x0001;
|
||||
input_dev->id.version = 0x0100;
|
||||
input_dev->cdev.dev = &serio->dev;
|
||||
input_dev->private = xtkbd;
|
||||
input_dev->dev.parent = &serio->dev;
|
||||
|
||||
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
|
||||
input_dev->keycode = xtkbd->keycode;
|
||||
|
|
|
@ -40,6 +40,16 @@ config INPUT_M68K_BEEP
|
|||
tristate "M68k Beeper support"
|
||||
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
|
||||
tristate "x86 Wistron laptop button interface"
|
||||
depends on X86 && !X86_64
|
||||
|
@ -81,8 +91,19 @@ config INPUT_UINPUT
|
|||
To compile this driver as a module, choose M here: the
|
||||
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
|
||||
tristate "HP SDC Real Time Clock"
|
||||
tristate "HP SDC Real Time Clock"
|
||||
depends on GSC || HP300
|
||||
select HP_SDC
|
||||
help
|
||||
|
|
|
@ -4,10 +4,12 @@
|
|||
|
||||
# Each configuration option enables a list of files.
|
||||
|
||||
obj-$(CONFIG_INPUT_POLLDEV) += input-polldev.o
|
||||
obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o
|
||||
obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o
|
||||
obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.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_ATLAS_BTNS) += atlas_btns.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)
|
||||
{
|
||||
unsigned int pin = (unsigned int) dev->private;
|
||||
unsigned int pin = (unsigned int) input_get_drvdata(input_dev);
|
||||
unsigned int count = 0;
|
||||
|
||||
if (type != EV_SND)
|
||||
|
@ -99,14 +99,15 @@ static int __devinit ixp4xx_spkr_probe(struct platform_device *dev)
|
|||
if (!input_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
input_dev->private = (void *) dev->id;
|
||||
input_set_drvdata(input_dev, (void *) dev->id);
|
||||
|
||||
input_dev->name = "ixp4xx beeper",
|
||||
input_dev->phys = "ixp4xx/gpio";
|
||||
input_dev->id.bustype = BUS_HOST;
|
||||
input_dev->id.vendor = 0x001f;
|
||||
input_dev->id.product = 0x0001;
|
||||
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->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)
|
||||
{
|
||||
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);
|
||||
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)
|
||||
{
|
||||
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 */
|
||||
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.product = 0x0001;
|
||||
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->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.product = 0x0001;
|
||||
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->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)
|
||||
{
|
||||
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 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)
|
||||
{
|
||||
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 long flags;
|
||||
|
||||
|
@ -113,7 +113,7 @@ static int __devinit sparcspkr_probe(struct device *dev)
|
|||
input_dev->id.vendor = 0x001f;
|
||||
input_dev->id.product = 0x0001;
|
||||
input_dev->id.version = 0x0100;
|
||||
input_dev->cdev.dev = dev;
|
||||
input_dev->dev.parent = dev;
|
||||
|
||||
input_dev->evbit[0] = BIT(EV_SND);
|
||||
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)
|
||||
{
|
||||
struct uinput_device *udev;
|
||||
|
||||
udev = dev->private;
|
||||
struct uinput_device *udev = input_get_drvdata(dev);
|
||||
|
||||
udev->buff[udev->head].type = type;
|
||||
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.old = old;
|
||||
|
||||
retval = uinput_request_reserve_slot(dev->private, &request);
|
||||
retval = uinput_request_reserve_slot(input_get_drvdata(dev), &request);
|
||||
if (!retval)
|
||||
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.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)
|
||||
retval = uinput_request_submit(dev, &request);
|
||||
|
||||
|
@ -274,7 +272,7 @@ static int uinput_allocate_device(struct uinput_device *udev)
|
|||
return -ENOMEM;
|
||||
|
||||
udev->dev->event = uinput_dev_event;
|
||||
udev->dev->private = udev;
|
||||
input_set_drvdata(udev->dev, udev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@
|
|||
MODULE_AUTHOR("Miloslav Trmac <mitr@volny.cz>");
|
||||
MODULE_DESCRIPTION("Wistron laptop button driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_VERSION("0.1");
|
||||
MODULE_VERSION("0.2");
|
||||
|
||||
static int force; /* = 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; */
|
||||
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;
|
||||
|
||||
|
@ -233,10 +233,20 @@ static void bios_set_state(u8 subsys, int enable)
|
|||
struct key_entry {
|
||||
char type; /* See KE_* below */
|
||||
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 int have_wifi;
|
||||
|
@ -256,93 +266,341 @@ static int __init dmi_matched(struct dmi_system_id *dmi)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static struct key_entry keymap_empty[] = {
|
||||
static struct key_entry keymap_empty[] __initdata = {
|
||||
{ KE_END, 0 }
|
||||
};
|
||||
|
||||
static struct key_entry keymap_fs_amilo_pro_v2000[] = {
|
||||
{ KE_KEY, 0x01, KEY_HELP },
|
||||
{ KE_KEY, 0x11, KEY_PROG1 },
|
||||
{ KE_KEY, 0x12, KEY_PROG2 },
|
||||
{ KE_WIFI, 0x30, 0 },
|
||||
{ KE_KEY, 0x31, KEY_MAIL },
|
||||
{ KE_KEY, 0x36, KEY_WWW },
|
||||
static struct key_entry keymap_fs_amilo_pro_v2000[] __initdata = {
|
||||
{ KE_KEY, 0x01, {KEY_HELP} },
|
||||
{ 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 }
|
||||
};
|
||||
|
||||
static struct key_entry keymap_fujitsu_n3510[] = {
|
||||
{ KE_KEY, 0x11, KEY_PROG1 },
|
||||
{ KE_KEY, 0x12, KEY_PROG2 },
|
||||
{ KE_KEY, 0x36, KEY_WWW },
|
||||
{ KE_KEY, 0x31, KEY_MAIL },
|
||||
{ KE_KEY, 0x71, KEY_STOPCD },
|
||||
{ KE_KEY, 0x72, KEY_PLAYPAUSE },
|
||||
{ KE_KEY, 0x74, KEY_REWIND },
|
||||
{ KE_KEY, 0x78, KEY_FORWARD },
|
||||
static struct key_entry keymap_fujitsu_n3510[] __initdata = {
|
||||
{ KE_KEY, 0x11, {KEY_PROG1} },
|
||||
{ KE_KEY, 0x12, {KEY_PROG2} },
|
||||
{ KE_KEY, 0x36, {KEY_WWW} },
|
||||
{ KE_KEY, 0x31, {KEY_MAIL} },
|
||||
{ KE_KEY, 0x71, {KEY_STOPCD} },
|
||||
{ KE_KEY, 0x72, {KEY_PLAYPAUSE} },
|
||||
{ KE_KEY, 0x74, {KEY_REWIND} },
|
||||
{ KE_KEY, 0x78, {KEY_FORWARD} },
|
||||
{ KE_END, 0 }
|
||||
};
|
||||
|
||||
static struct key_entry keymap_wistron_ms2111[] = {
|
||||
{ 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 },
|
||||
static struct key_entry keymap_wistron_ms2111[] __initdata = {
|
||||
{ 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_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 }
|
||||
};
|
||||
|
||||
static struct key_entry keymap_wistron_ms2141[] = {
|
||||
{ KE_KEY, 0x11, KEY_PROG1 },
|
||||
{ KE_KEY, 0x12, KEY_PROG2 },
|
||||
{ KE_WIFI, 0x30, 0 },
|
||||
{ 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 }
|
||||
static struct key_entry keymap_acer_aspire_1500[] __initdata = {
|
||||
{ KE_KEY, 0x01, {KEY_HELP} },
|
||||
{ KE_KEY, 0x03, {KEY_POWER} },
|
||||
{ KE_KEY, 0x11, {KEY_PROG1} },
|
||||
{ KE_KEY, 0x12, {KEY_PROG2} },
|
||||
{ KE_WIFI, 0x30 },
|
||||
{ KE_KEY, 0x31, {KEY_MAIL} },
|
||||
{ KE_KEY, 0x36, {KEY_WWW} },
|
||||
{ KE_KEY, 0x49, {KEY_CONFIG} },
|
||||
{ KE_BLUETOOTH, 0x44 },
|
||||
{ KE_END, FE_UNTESTED }
|
||||
};
|
||||
|
||||
static struct key_entry keymap_acer_aspire_1500[] = {
|
||||
{ KE_KEY, 0x11, KEY_PROG1 },
|
||||
{ KE_KEY, 0x12, KEY_PROG2 },
|
||||
{ KE_WIFI, 0x30, 0 },
|
||||
{ KE_KEY, 0x31, KEY_MAIL },
|
||||
{ KE_KEY, 0x36, KEY_WWW },
|
||||
{ KE_BLUETOOTH, 0x44, 0 },
|
||||
{ KE_END, 0 }
|
||||
static struct key_entry keymap_acer_aspire_1600[] __initdata = {
|
||||
{ KE_KEY, 0x01, {KEY_HELP} },
|
||||
{ KE_KEY, 0x03, {KEY_POWER} },
|
||||
{ KE_KEY, 0x08, {KEY_MUTE} },
|
||||
{ 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_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[] = {
|
||||
{ KE_KEY, 0x31, KEY_MAIL },
|
||||
{ KE_KEY, 0x36, KEY_WWW },
|
||||
{ KE_KEY, 0x11, KEY_PROG1 },
|
||||
{ KE_KEY, 0x12, KEY_PROG2 },
|
||||
{ KE_BLUETOOTH, 0x44, 0 },
|
||||
{ KE_WIFI, 0x30, 0 },
|
||||
{ KE_END, 0 }
|
||||
/* 3020 has been tested */
|
||||
static struct key_entry keymap_acer_aspire_5020[] __initdata = {
|
||||
{ KE_KEY, 0x01, {KEY_HELP} },
|
||||
{ KE_KEY, 0x03, {KEY_POWER} },
|
||||
{ KE_KEY, 0x05, {KEY_SWITCHVIDEOMODE} }, /* Display selection */
|
||||
{ KE_KEY, 0x11, {KEY_PROG1} },
|
||||
{ KE_KEY, 0x12, {KEY_PROG2} },
|
||||
{ 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[] = {
|
||||
{ KE_KEY, 0x01, KEY_HELP },
|
||||
{ KE_KEY, 0x06, KEY_PROG3 },
|
||||
{ KE_KEY, 0x11, KEY_PROG1 },
|
||||
{ KE_KEY, 0x12, KEY_PROG2 },
|
||||
{ KE_WIFI, 0x30, 0 },
|
||||
{ KE_KEY, 0x31, KEY_MAIL },
|
||||
{ KE_KEY, 0x36, KEY_WWW },
|
||||
static struct key_entry keymap_acer_travelmate_2410[] __initdata = {
|
||||
{ KE_KEY, 0x01, {KEY_HELP} },
|
||||
{ KE_KEY, 0x6d, {KEY_POWER} },
|
||||
{ KE_KEY, 0x11, {KEY_PROG1} },
|
||||
{ KE_KEY, 0x12, {KEY_PROG2} },
|
||||
{ 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_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 },
|
||||
};
|
||||
|
||||
static struct key_entry keymap_fs_amilo_d88x0[] = {
|
||||
{ KE_KEY, 0x01, KEY_HELP },
|
||||
{ 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_KEY, 0x13, KEY_PROG3 },
|
||||
static struct key_entry keymap_fs_amilo_d88x0[] __initdata = {
|
||||
{ KE_KEY, 0x01, {KEY_HELP} },
|
||||
{ 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_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 }
|
||||
};
|
||||
|
||||
|
@ -388,6 +646,133 @@ static struct dmi_system_id dmi_ids[] __initdata = {
|
|||
},
|
||||
.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,
|
||||
.ident = "Acer TravelMate 240",
|
||||
|
@ -397,6 +782,15 @@ static struct dmi_system_id dmi_ids[] __initdata = {
|
|||
},
|
||||
.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,
|
||||
.ident = "Acer TravelMate 2424NWXCi",
|
||||
|
@ -406,6 +800,51 @@ static struct dmi_system_id dmi_ids[] __initdata = {
|
|||
},
|
||||
.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,
|
||||
.ident = "AOpen 1559AS",
|
||||
|
@ -424,6 +863,51 @@ static struct dmi_system_id dmi_ids[] __initdata = {
|
|||
},
|
||||
.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,
|
||||
.ident = "Fujitsu Siemens Amilo D88x0",
|
||||
|
@ -436,17 +920,39 @@ static struct dmi_system_id dmi_ids[] __initdata = {
|
|||
{ 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)
|
||||
{
|
||||
dmi_check_system(dmi_ids);
|
||||
if (keymap_name != NULL) {
|
||||
if (strcmp (keymap_name, "1557/MS2141") == 0)
|
||||
keymap = keymap_wistron_ms2141;
|
||||
else if (strcmp (keymap_name, "generic") == 0)
|
||||
keymap = keymap_wistron_generic;
|
||||
else {
|
||||
printk(KERN_ERR "wistron_btns: Keymap unknown\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
dmi_check_system(dmi_ids);
|
||||
if (keymap == NULL) {
|
||||
if (!force) {
|
||||
printk(KERN_ERR "wistron_btns: System unknown\n");
|
||||
|
@ -454,7 +960,8 @@ static int __init select_keymap(void)
|
|||
}
|
||||
keymap = keymap_empty;
|
||||
}
|
||||
return 0;
|
||||
|
||||
return copy_keymap();
|
||||
}
|
||||
|
||||
/* Input layer interface */
|
||||
|
@ -476,12 +983,28 @@ static int __devinit setup_input_dev(void)
|
|||
input_dev->cdev.dev = &wistron_device->dev;
|
||||
|
||||
for (key = keymap; key->type != KE_END; key++) {
|
||||
if (key->type == KE_KEY) {
|
||||
input_dev->evbit[LONG(EV_KEY)] = BIT(EV_KEY);
|
||||
set_bit(key->keycode, input_dev->keybit);
|
||||
switch (key->type) {
|
||||
case KE_KEY:
|
||||
set_bit(EV_KEY, input_dev->evbit);
|
||||
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);
|
||||
if (error) {
|
||||
input_free_device(input_dev);
|
||||
|
@ -499,6 +1022,12 @@ static void report_key(unsigned keycode)
|
|||
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 */
|
||||
|
||||
static int wifi_enabled;
|
||||
|
@ -519,6 +1048,10 @@ static void handle_key(u8 code)
|
|||
report_key(key->keycode);
|
||||
break;
|
||||
|
||||
case KE_SW:
|
||||
report_switch(key->sw.code, key->sw.value);
|
||||
break;
|
||||
|
||||
case KE_WIFI:
|
||||
if (have_wifi) {
|
||||
wifi_enabled = !wifi_enabled;
|
||||
|
@ -534,6 +1067,7 @@ static void handle_key(u8 code)
|
|||
break;
|
||||
|
||||
case KE_END:
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
@ -690,6 +1224,7 @@ static void __exit wb_module_exit(void)
|
|||
platform_device_unregister(wistron_device);
|
||||
platform_driver_unregister(&wistron_driver);
|
||||
unmap_bios();
|
||||
kfree(keymap);
|
||||
}
|
||||
|
||||
module_init(wb_module_init);
|
||||
|
|
|
@ -37,6 +37,65 @@ config MOUSE_PS2
|
|||
To compile this driver as a module, choose M here: the
|
||||
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
|
||||
tristate "Serial mouse"
|
||||
select SERIO
|
||||
|
@ -129,7 +188,7 @@ config MOUSE_VSXXXAA
|
|||
digitizer (VSXXX-AB) DEC produced.
|
||||
|
||||
config MOUSE_HIL
|
||||
tristate "HIL pointers (mice etc)."
|
||||
tristate "HIL pointers (mice etc)."
|
||||
depends on GSC || HP300
|
||||
select HP_SDC
|
||||
select HIL_MLC
|
||||
|
|
|
@ -15,4 +15,10 @@ obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o
|
|||
obj-$(CONFIG_MOUSE_HIL) += hil_ptr.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;
|
||||
int version;
|
||||
|
||||
psmouse->private = priv = kzalloc(sizeof(struct alps_data), GFP_KERNEL);
|
||||
priv = kzalloc(sizeof(struct alps_data), GFP_KERNEL);
|
||||
dev2 = input_allocate_device();
|
||||
if (!priv || !dev2)
|
||||
goto init_fail;
|
||||
|
||||
priv->dev2 = dev2;
|
||||
|
||||
if (!(priv->i = alps_get_model(psmouse, &version)))
|
||||
priv->i = alps_get_model(psmouse, &version);
|
||||
if (!priv->i)
|
||||
goto init_fail;
|
||||
|
||||
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->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->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 */
|
||||
psmouse->resync_time = 0;
|
||||
|
||||
psmouse->private = priv;
|
||||
return 0;
|
||||
|
||||
init_fail:
|
||||
psmouse_reset(psmouse);
|
||||
input_free_device(dev2);
|
||||
kfree(priv);
|
||||
return -1;
|
||||
|
@ -504,7 +508,8 @@ int alps_detect(struct psmouse *psmouse, int set_properties)
|
|||
int version;
|
||||
const struct alps_model_info *model;
|
||||
|
||||
if (!(model = alps_get_model(psmouse, &version)))
|
||||
model = alps_get_model(psmouse, &version);
|
||||
if (!model)
|
||||
return -1;
|
||||
|
||||
if (set_properties) {
|
||||
|
|
|
@ -12,9 +12,6 @@
|
|||
#ifndef _ALPS_H
|
||||
#define _ALPS_H
|
||||
|
||||
int alps_detect(struct psmouse *psmouse, int set_properties);
|
||||
int alps_init(struct psmouse *psmouse);
|
||||
|
||||
struct alps_model_info {
|
||||
unsigned char signature[3];
|
||||
unsigned char byte0, mask0;
|
||||
|
@ -23,10 +20,23 @@ struct alps_model_info {
|
|||
|
||||
struct alps_data {
|
||||
struct input_dev *dev2; /* Relative device */
|
||||
char name[32]; /* Name */
|
||||
char phys[32]; /* Phys */
|
||||
const struct alps_model_info *i;/* Info */
|
||||
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
|
||||
|
|
|
@ -88,10 +88,12 @@ static void hil_ptr_process_record(struct hil_ptr *ptr)
|
|||
idx = ptr->idx4/4;
|
||||
p = data[idx - 1];
|
||||
|
||||
if ((p & ~HIL_CMDCT_POL) ==
|
||||
(HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL)) goto report;
|
||||
if ((p & ~HIL_CMDCT_RPL) ==
|
||||
(HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL)) goto report;
|
||||
if ((p & ~HIL_CMDCT_POL) ==
|
||||
(HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL))
|
||||
goto report;
|
||||
if ((p & ~HIL_CMDCT_RPL) ==
|
||||
(HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL))
|
||||
goto report;
|
||||
|
||||
/* Not a poll response. See if we are loading config records. */
|
||||
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++)
|
||||
ptr->idd[i] = 0;
|
||||
break;
|
||||
|
||||
case HIL_CMD_RSC:
|
||||
for (i = 0; i < idx; i++)
|
||||
ptr->rsc[i] = ptr->data[i] & HIL_PKT_DATA_MASK;
|
||||
for (; i < HIL_PTR_MAX_LENGTH; i++)
|
||||
ptr->rsc[i] = 0;
|
||||
break;
|
||||
|
||||
case HIL_CMD_EXD:
|
||||
for (i = 0; i < idx; i++)
|
||||
ptr->exd[i] = ptr->data[i] & HIL_PKT_DATA_MASK;
|
||||
for (; i < HIL_PTR_MAX_LENGTH; i++)
|
||||
ptr->exd[i] = 0;
|
||||
break;
|
||||
|
||||
case HIL_CMD_RNM:
|
||||
for (i = 0; i < idx; i++)
|
||||
ptr->rnm[i] = ptr->data[i] & HIL_PKT_DATA_MASK;
|
||||
for (; i < HIL_PTR_MAX_LENGTH + 1; i++)
|
||||
ptr->rnm[i] = '\0';
|
||||
ptr->rnm[i] = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* 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. */
|
||||
printk(KERN_WARNING PREFIX "Device sent unknown record %x\n", p);
|
||||
break;
|
||||
|
@ -130,7 +137,8 @@ static void hil_ptr_process_record(struct hil_ptr *ptr)
|
|||
|
||||
report:
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -139,7 +147,7 @@ static void hil_ptr_process_record(struct hil_ptr *ptr)
|
|||
laxis += i;
|
||||
|
||||
ax16 = ptr->idd[1] & HIL_IDD_HEADER_16BIT; /* 8 or 16bit resolution */
|
||||
absdev = ptr->idd[1] & HIL_IDD_HEADER_ABS;
|
||||
absdev = ptr->idd[1] & HIL_IDD_HEADER_ABS;
|
||||
|
||||
for (cnt = 1; i < laxis; i++) {
|
||||
unsigned int lo,hi,val;
|
||||
|
@ -157,7 +165,8 @@ static void hil_ptr_process_record(struct hil_ptr *ptr)
|
|||
input_report_abs(dev, ABS_X + i, val);
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -168,10 +177,11 @@ static void hil_ptr_process_record(struct hil_ptr *ptr)
|
|||
btn = ptr->data[cnt++];
|
||||
up = btn & 1;
|
||||
btn &= 0xfe;
|
||||
if (btn == 0x8e) {
|
||||
if (btn == 0x8e)
|
||||
continue; /* TODO: proximity == touch? */
|
||||
}
|
||||
else if ((btn > 0x8c) || (btn < 0x80)) continue;
|
||||
else
|
||||
if ((btn > 0x8c) || (btn < 0x80))
|
||||
continue;
|
||||
btn = (btn - 0x80) >> 1;
|
||||
btn = ptr->btnmap[btn];
|
||||
input_report_key(dev, btn, !up);
|
||||
|
@ -182,14 +192,14 @@ static void hil_ptr_process_record(struct hil_ptr *ptr)
|
|||
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");
|
||||
ptr->idx4 = 0;
|
||||
up(&ptr->sem);
|
||||
return;
|
||||
}
|
||||
|
||||
static irqreturn_t hil_ptr_interrupt(struct serio *serio,
|
||||
static irqreturn_t hil_ptr_interrupt(struct serio *serio,
|
||||
unsigned char data, unsigned int flags)
|
||||
{
|
||||
struct hil_ptr *ptr;
|
||||
|
@ -197,29 +207,29 @@ static irqreturn_t hil_ptr_interrupt(struct serio *serio,
|
|||
int idx;
|
||||
|
||||
ptr = serio_get_drvdata(serio);
|
||||
if (ptr == NULL) {
|
||||
BUG();
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
BUG_ON(ptr == NULL);
|
||||
|
||||
if (ptr->idx4 >= (HIL_PTR_MAX_LENGTH * sizeof(hil_packet))) {
|
||||
hil_ptr_process_err(ptr);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
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 |= ((hil_packet)data) << ((3 - (ptr->idx4 % 4)) * 8);
|
||||
ptr->data[idx] = packet;
|
||||
|
||||
/* 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) {
|
||||
hil_ptr_process_err(ptr);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
if (packet & HIL_PKT_CMD)
|
||||
if (packet & HIL_PKT_CMD)
|
||||
hil_ptr_process_record(ptr);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
@ -228,10 +238,7 @@ static void hil_ptr_disconnect(struct serio *serio)
|
|||
struct hil_ptr *ptr;
|
||||
|
||||
ptr = serio_get_drvdata(serio);
|
||||
if (ptr == NULL) {
|
||||
BUG();
|
||||
return;
|
||||
}
|
||||
BUG_ON(ptr == NULL);
|
||||
|
||||
serio_close(serio);
|
||||
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)
|
||||
{
|
||||
struct hil_ptr *ptr;
|
||||
char *txt;
|
||||
const char *txt;
|
||||
unsigned int i, naxsets, btntype;
|
||||
uint8_t did, *idd;
|
||||
|
||||
|
@ -252,42 +259,40 @@ static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver)
|
|||
if (!ptr->dev)
|
||||
goto bail0;
|
||||
|
||||
ptr->dev->private = ptr;
|
||||
|
||||
if (serio_open(serio, driver))
|
||||
goto bail1;
|
||||
|
||||
serio_set_drvdata(serio, ptr);
|
||||
ptr->serio = serio;
|
||||
|
||||
init_MUTEX_LOCKED(&(ptr->sem));
|
||||
init_MUTEX_LOCKED(&ptr->sem);
|
||||
|
||||
/* Get device info. MLC driver supplies devid/status/etc. */
|
||||
serio->write(serio, 0);
|
||||
serio->write(serio, 0);
|
||||
serio->write(serio, HIL_PKT_CMD >> 8);
|
||||
serio->write(serio, HIL_CMD_IDD);
|
||||
down(&(ptr->sem));
|
||||
down(&ptr->sem);
|
||||
|
||||
serio->write(serio, 0);
|
||||
serio->write(serio, 0);
|
||||
serio->write(serio, HIL_PKT_CMD >> 8);
|
||||
serio->write(serio, HIL_CMD_RSC);
|
||||
down(&(ptr->sem));
|
||||
down(&ptr->sem);
|
||||
|
||||
serio->write(serio, 0);
|
||||
serio->write(serio, 0);
|
||||
serio->write(serio, HIL_PKT_CMD >> 8);
|
||||
serio->write(serio, HIL_CMD_RNM);
|
||||
down(&(ptr->sem));
|
||||
down(&ptr->sem);
|
||||
|
||||
serio->write(serio, 0);
|
||||
serio->write(serio, 0);
|
||||
serio->write(serio, HIL_PKT_CMD >> 8);
|
||||
serio->write(serio, HIL_CMD_EXD);
|
||||
down(&(ptr->sem));
|
||||
down(&ptr->sem);
|
||||
|
||||
up(&(ptr->sem));
|
||||
up(&ptr->sem);
|
||||
|
||||
did = ptr->idd[0];
|
||||
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);
|
||||
txt = "absolute";
|
||||
}
|
||||
if (!ptr->dev->evbit[0]) {
|
||||
if (!ptr->dev->evbit[0])
|
||||
goto bail2;
|
||||
}
|
||||
|
||||
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);
|
||||
ptr->naxes = HIL_IDD_NUM_AXES_PER_SET(*idd);
|
||||
|
@ -315,7 +320,7 @@ static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver)
|
|||
did, txt);
|
||||
printk(KERN_INFO PREFIX "HIL pointer has %i buttons and %i sets of %i axes\n",
|
||||
ptr->nbtn, naxsets, ptr->naxes);
|
||||
|
||||
|
||||
btntype = BTN_MISC;
|
||||
if ((did & HIL_IDD_DID_ABS_TABLET_MASK) == HIL_IDD_DID_ABS_TABLET)
|
||||
#ifdef TABLET_SIMULATES_MOUSE
|
||||
|
@ -325,7 +330,7 @@ static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver)
|
|||
#endif
|
||||
if ((did & HIL_IDD_DID_ABS_TSCREEN_MASK) == HIL_IDD_DID_ABS_TSCREEN)
|
||||
btntype = BTN_TOUCH;
|
||||
|
||||
|
||||
if ((did & HIL_IDD_DID_REL_MOUSE_MASK) == HIL_IDD_DID_REL_MOUSE)
|
||||
btntype = BTN_MOUSE;
|
||||
|
||||
|
@ -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) {
|
||||
for (i = 0; i < ptr->naxes; i++) {
|
||||
for (i = 0; i < ptr->naxes; i++)
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < ptr->naxes; i++) {
|
||||
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.product = 0x0001; /* 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);
|
||||
printk(KERN_INFO "input: %s (%s), ID: %d\n",
|
||||
|
@ -419,11 +422,11 @@ static int __init hil_ptr_init(void)
|
|||
{
|
||||
return serio_register_driver(&hil_ptr_serio_driver);
|
||||
}
|
||||
|
||||
|
||||
static void __exit hil_ptr_exit(void)
|
||||
{
|
||||
serio_unregister_driver(&hil_ptr_serio_driver);
|
||||
}
|
||||
|
||||
|
||||
module_init(hil_ptr_init);
|
||||
module_exit(hil_ptr_exit);
|
||||
|
|
|
@ -20,6 +20,27 @@
|
|||
#include "psmouse.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[] = {
|
||||
{
|
||||
.ident = "FLORA-ie 55mi",
|
||||
|
@ -56,6 +77,24 @@ static struct dmi_system_id lifebook_dmi_table[] = {
|
|||
.matches = {
|
||||
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",
|
||||
|
@ -68,30 +107,70 @@ static struct dmi_system_id lifebook_dmi_table[] = {
|
|||
|
||||
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;
|
||||
struct input_dev *dev = psmouse->dev;
|
||||
int relative_packet = packet[0] & 0x08;
|
||||
|
||||
if (psmouse->pktcnt != 3)
|
||||
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)));
|
||||
if (relative_packet || !lifebook_use_6byte_proto) {
|
||||
if (psmouse->pktcnt != 3)
|
||||
return PSMOUSE_GOOD_DATA;
|
||||
} else {
|
||||
input_report_rel(dev, REL_X,
|
||||
((packet[0] & 0x10) ? packet[1] - 256 : packet[1]));
|
||||
input_report_rel(dev, REL_Y,
|
||||
-(int)((packet[0] & 0x20) ? packet[2] - 256 : packet[2]));
|
||||
switch (psmouse->pktcnt) {
|
||||
case 1:
|
||||
return (packet[0] & 0xf8) == 0x00 ?
|
||||
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);
|
||||
input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
|
||||
input_report_key(dev, BTN_TOUCH, packet[0] & 0x04);
|
||||
if (relative_packet) {
|
||||
if (!dev2)
|
||||
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;
|
||||
}
|
||||
|
@ -109,12 +188,20 @@ static int lifebook_absolute_mode(struct psmouse *psmouse)
|
|||
you leave this call out the touchsreen will never send
|
||||
absolute coordinates
|
||||
*/
|
||||
param = 0x07;
|
||||
param = lifebook_use_6byte_proto ? 0x08 : 0x07;
|
||||
ps2_command(ps2dev, ¶m, PSMOUSE_CMD_SETRES);
|
||||
|
||||
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 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)
|
||||
{
|
||||
psmouse_reset(psmouse);
|
||||
kfree(psmouse->private);
|
||||
psmouse->private = NULL;
|
||||
}
|
||||
|
||||
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))
|
||||
return -1;
|
||||
|
||||
if (desired_serio_phys &&
|
||||
strcmp(psmouse->ps2dev.serio->phys, desired_serio_phys))
|
||||
return -1;
|
||||
|
||||
if (set_properties) {
|
||||
psmouse->vendor = "Fujitsu";
|
||||
psmouse->name = "Lifebook TouchScreen";
|
||||
|
@ -146,24 +239,78 @@ int lifebook_detect(struct psmouse *psmouse, int set_properties)
|
|||
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)
|
||||
{
|
||||
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))
|
||||
return -1;
|
||||
|
||||
input_dev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY) | BIT(EV_REL);
|
||||
input_dev->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
|
||||
input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
|
||||
input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
|
||||
input_set_abs_params(input_dev, ABS_X, 0, 1024, 0, 0);
|
||||
input_set_abs_params(input_dev, ABS_Y, 0, 1024, 0, 0);
|
||||
dev1->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY);
|
||||
dev1->relbit[0] = 0;
|
||||
dev1->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
|
||||
input_set_abs_params(dev1, ABS_X, 0, max_coord, 0, 0);
|
||||
input_set_abs_params(dev1, ABS_Y, 0, max_coord, 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->set_resolution = lifebook_set_resolution;
|
||||
psmouse->disconnect = lifebook_disconnect;
|
||||
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;
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -11,7 +11,18 @@
|
|||
#ifndef _LIFEBOOK_H
|
||||
#define _LIFEBOOK_H
|
||||
|
||||
#ifdef CONFIG_MOUSE_PS2_LIFEBOOK
|
||||
int lifebook_detect(struct psmouse *psmouse, int set_properties);
|
||||
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
|
||||
|
|
|
@ -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 ps2pp_list[] = {
|
||||
{ 1, 0, 0 }, /* Simple 2-button mouse */
|
||||
{ 12, 0, PS2PP_SIDE_BTN},
|
||||
{ 13, 0, 0 },
|
||||
{ 15, PS2PP_KIND_MX, /* MX1000 */
|
||||
|
@ -338,12 +339,12 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties)
|
|||
param[1] = 0;
|
||||
ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO);
|
||||
|
||||
if (!param[1])
|
||||
return -1;
|
||||
|
||||
model = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78);
|
||||
buttons = param[1];
|
||||
|
||||
if (!model || !buttons)
|
||||
return -1;
|
||||
|
||||
if ((model_info = get_model_info(model)) != NULL) {
|
||||
|
||||
/*
|
||||
|
|
|
@ -11,6 +11,13 @@
|
|||
#ifndef _LOGIPS2PP_H
|
||||
#define _LOGIPS2PP_H
|
||||
|
||||
#ifdef CONFIG_MOUSE_PS2_LOGIPS2PP
|
||||
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
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "alps.h"
|
||||
#include "lifebook.h"
|
||||
#include "trackpoint.h"
|
||||
#include "touchkit_ps2.h"
|
||||
|
||||
#define DRIVER_DESC "PS/2 mouse driver"
|
||||
|
||||
|
@ -569,7 +570,9 @@ static int psmouse_extensions(struct psmouse *psmouse,
|
|||
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) {
|
||||
synaptics_hardware = 1;
|
||||
|
@ -605,14 +608,20 @@ static int psmouse_extensions(struct psmouse *psmouse,
|
|||
}
|
||||
}
|
||||
|
||||
if (max_proto > PSMOUSE_IMEX && genius_detect(psmouse, set_properties) == 0)
|
||||
return PSMOUSE_GENPS;
|
||||
if (max_proto > PSMOUSE_IMEX) {
|
||||
|
||||
if (max_proto > PSMOUSE_IMEX && ps2pp_init(psmouse, set_properties) == 0)
|
||||
return PSMOUSE_PS2PP;
|
||||
if (genius_detect(psmouse, set_properties) == 0)
|
||||
return PSMOUSE_GENPS;
|
||||
|
||||
if (max_proto > PSMOUSE_IMEX && trackpoint_detect(psmouse, set_properties) == 0)
|
||||
return PSMOUSE_TRACKPOINT;
|
||||
if (ps2pp_init(psmouse, set_properties) == 0)
|
||||
return PSMOUSE_PS2PP;
|
||||
|
||||
if (trackpoint_detect(psmouse, set_properties) == 0)
|
||||
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
|
||||
|
@ -654,12 +663,14 @@ static const struct psmouse_protocol psmouse_protocols[] = {
|
|||
.maxproto = 1,
|
||||
.detect = ps2bare_detect,
|
||||
},
|
||||
#ifdef CONFIG_MOUSE_PS2_LOGIPS2PP
|
||||
{
|
||||
.type = PSMOUSE_PS2PP,
|
||||
.name = "PS2++",
|
||||
.alias = "logitech",
|
||||
.detect = ps2pp_init,
|
||||
},
|
||||
#endif
|
||||
{
|
||||
.type = PSMOUSE_THINKPS,
|
||||
.name = "ThinkPS/2",
|
||||
|
@ -686,6 +697,7 @@ static const struct psmouse_protocol psmouse_protocols[] = {
|
|||
.maxproto = 1,
|
||||
.detect = im_explorer_detect,
|
||||
},
|
||||
#ifdef CONFIG_MOUSE_PS2_SYNAPTICS
|
||||
{
|
||||
.type = PSMOUSE_SYNAPTICS,
|
||||
.name = "SynPS/2",
|
||||
|
@ -693,6 +705,8 @@ static const struct psmouse_protocol psmouse_protocols[] = {
|
|||
.detect = synaptics_detect,
|
||||
.init = synaptics_init,
|
||||
},
|
||||
#endif
|
||||
#ifdef CONFIG_MOUSE_PS2_ALPS
|
||||
{
|
||||
.type = PSMOUSE_ALPS,
|
||||
.name = "AlpsPS/2",
|
||||
|
@ -700,18 +714,31 @@ static const struct psmouse_protocol psmouse_protocols[] = {
|
|||
.detect = alps_detect,
|
||||
.init = alps_init,
|
||||
},
|
||||
#endif
|
||||
#ifdef CONFIG_MOUSE_PS2_LIFEBOOK
|
||||
{
|
||||
.type = PSMOUSE_LIFEBOOK,
|
||||
.name = "LBPS/2",
|
||||
.alias = "lifebook",
|
||||
.init = lifebook_init,
|
||||
},
|
||||
#endif
|
||||
#ifdef CONFIG_MOUSE_PS2_TRACKPOINT
|
||||
{
|
||||
.type = PSMOUSE_TRACKPOINT,
|
||||
.name = "TPPS/2",
|
||||
.alias = "trackpoint",
|
||||
.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,
|
||||
.name = "auto",
|
||||
|
@ -822,12 +849,6 @@ static void psmouse_set_rate(struct psmouse *psmouse, unsigned int rate)
|
|||
|
||||
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.
|
||||
*/
|
||||
|
@ -1062,8 +1083,7 @@ static int psmouse_switch_protocol(struct psmouse *psmouse, const struct psmouse
|
|||
{
|
||||
struct input_dev *input_dev = psmouse->dev;
|
||||
|
||||
input_dev->private = psmouse;
|
||||
input_dev->cdev.dev = &psmouse->ps2dev.serio->dev;
|
||||
input_dev->dev.parent = &psmouse->ps2dev.serio->dev;
|
||||
|
||||
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);
|
||||
|
|
|
@ -87,6 +87,7 @@ enum psmouse_type {
|
|||
PSMOUSE_ALPS,
|
||||
PSMOUSE_LIFEBOOK,
|
||||
PSMOUSE_TRACKPOINT,
|
||||
PSMOUSE_TOUCHKIT_PS2,
|
||||
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) {
|
||||
|
||||
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_RIGHT, !(data & 1));
|
||||
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;
|
||||
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) {
|
||||
|
||||
|
@ -169,7 +173,8 @@ static void sermouse_process_ms(struct sermouse *sermouse, signed char data)
|
|||
|
||||
case 5:
|
||||
case 7: /* Ignore anything besides MZ++ */
|
||||
if (sermouse->type != SERIO_MZPP) break;
|
||||
if (sermouse->type != SERIO_MZPP)
|
||||
break;
|
||||
|
||||
switch (buf[1]) {
|
||||
|
||||
|
@ -206,13 +211,16 @@ static irqreturn_t sermouse_interrupt(struct serio *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;
|
||||
|
||||
if (sermouse->type > SERIO_SUN)
|
||||
sermouse_process_ms(sermouse, data);
|
||||
else
|
||||
sermouse_process_msc(sermouse, data);
|
||||
|
||||
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.product = c;
|
||||
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->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT);
|
||||
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 & 0x02) set_bit(BTN_SIDE, input_dev->keybit);
|
||||
|
|
|
@ -40,21 +40,10 @@
|
|||
#define YMIN_NOMINAL 1408
|
||||
#define YMAX_NOMINAL 4448
|
||||
|
||||
/*****************************************************************************
|
||||
* 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;
|
||||
}
|
||||
/*****************************************************************************
|
||||
* Stuff we need even when we do not want native Synaptics support
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
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
|
||||
* 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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
synaptics_reset(psmouse);
|
||||
|
@ -569,30 +600,6 @@ static int synaptics_reconnect(struct psmouse *psmouse)
|
|||
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__)
|
||||
#include <linux/dmi.h>
|
||||
static struct dmi_system_id toshiba_dmi_table[] = {
|
||||
|
@ -648,6 +655,16 @@ int synaptics_init(struct psmouse *psmouse)
|
|||
|
||||
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->set_rate = synaptics_set_rate;
|
||||
psmouse->disconnect = synaptics_disconnect;
|
||||
|
@ -680,4 +697,12 @@ int synaptics_init(struct psmouse *psmouse)
|
|||
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
|
||||
#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 */
|
||||
#define SYN_QUE_IDENTIFY 0x00
|
||||
#define SYN_QUE_MODES 0x01
|
||||
|
@ -62,9 +58,9 @@ extern void synaptics_reset(struct psmouse *psmouse);
|
|||
#define SYN_MODE_WMODE(m) ((m) & (1 << 0))
|
||||
|
||||
/* synaptics identify query bits */
|
||||
#define SYN_ID_MODEL(i) (((i) >> 4) & 0x0f)
|
||||
#define SYN_ID_MAJOR(i) ((i) & 0x0f)
|
||||
#define SYN_ID_MINOR(i) (((i) >> 16) & 0xff)
|
||||
#define SYN_ID_MODEL(i) (((i) >> 4) & 0x0f)
|
||||
#define SYN_ID_MAJOR(i) ((i) & 0x0f)
|
||||
#define SYN_ID_MINOR(i) (((i) >> 16) & 0xff)
|
||||
#define SYN_ID_IS_SYNAPTICS(i) ((((i) >> 8) & 0xff) == 0x47)
|
||||
|
||||
/* synaptics special commands */
|
||||
|
@ -98,8 +94,8 @@ struct synaptics_hw_state {
|
|||
struct synaptics_data {
|
||||
/* Data read from the touchpad */
|
||||
unsigned long int model_id; /* Model-ID */
|
||||
unsigned long int capabilities; /* Capabilities */
|
||||
unsigned long int ext_cap; /* Extended Capabilities */
|
||||
unsigned long int capabilities; /* Capabilities */
|
||||
unsigned long int ext_cap; /* Extended Capabilities */
|
||||
unsigned long int identity; /* Identification */
|
||||
|
||||
unsigned char pkt_type; /* packet type - old, new, etc */
|
||||
|
@ -107,4 +103,8 @@ struct synaptics_data {
|
|||
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 */
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
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 */
|
||||
|
|
|
@ -508,8 +508,7 @@ vsxxxaa_connect (struct serio *serio, struct serio_driver *drv)
|
|||
input_dev->name = mouse->name;
|
||||
input_dev->phys = mouse->phys;
|
||||
input_dev->id.bustype = BUS_RS232;
|
||||
input_dev->cdev.dev = &serio->dev;
|
||||
input_dev->private = mouse;
|
||||
input_dev->dev.parent = &serio->dev;
|
||||
|
||||
set_bit (EV_KEY, input_dev->evbit); /* We have buttons */
|
||||
set_bit (EV_REL, input_dev->evbit);
|
||||
|
|
|
@ -63,9 +63,12 @@ struct mousedev {
|
|||
int minor;
|
||||
char name[16];
|
||||
wait_queue_head_t wait;
|
||||
struct list_head list;
|
||||
struct list_head client_list;
|
||||
struct input_handle handle;
|
||||
|
||||
struct list_head mixdev_node;
|
||||
int mixdev_open;
|
||||
|
||||
struct mousedev_hw_data packet;
|
||||
unsigned int pkt_count;
|
||||
int old_x[4], old_y[4];
|
||||
|
@ -85,7 +88,7 @@ struct mousedev_motion {
|
|||
};
|
||||
|
||||
#define PACKET_QUEUE_LEN 16
|
||||
struct mousedev_list {
|
||||
struct mousedev_client {
|
||||
struct fasync_struct *fasync;
|
||||
struct mousedev *mousedev;
|
||||
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_mix;
|
||||
static LIST_HEAD(mousedev_mix_list);
|
||||
|
||||
#define fx(i) (mousedev->old_x[(mousedev->pkt_count - (i)) & 03])
|
||||
#define fy(i) (mousedev->old_y[(mousedev->pkt_count - (i)) & 03])
|
||||
|
@ -120,32 +124,33 @@ static void mousedev_touchpad_event(struct input_dev *dev, struct mousedev *mous
|
|||
int size, tmp;
|
||||
enum { FRACTION_DENOM = 128 };
|
||||
|
||||
if (mousedev->touch) {
|
||||
size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
|
||||
if (size == 0)
|
||||
size = 256 * 2;
|
||||
switch (code) {
|
||||
case ABS_X:
|
||||
fx(0) = value;
|
||||
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 += mousedev->frac_dx;
|
||||
mousedev->packet.dx = tmp / FRACTION_DENOM;
|
||||
mousedev->frac_dx = tmp - mousedev->packet.dx * FRACTION_DENOM;
|
||||
}
|
||||
break;
|
||||
|
||||
switch (code) {
|
||||
case ABS_X:
|
||||
fx(0) = value;
|
||||
if (mousedev->pkt_count >= 2) {
|
||||
tmp = ((value - fx(2)) * (256 * FRACTION_DENOM)) / size;
|
||||
tmp += mousedev->frac_dx;
|
||||
mousedev->packet.dx = tmp / FRACTION_DENOM;
|
||||
mousedev->frac_dx = tmp - mousedev->packet.dx * FRACTION_DENOM;
|
||||
}
|
||||
break;
|
||||
|
||||
case ABS_Y:
|
||||
fy(0) = value;
|
||||
if (mousedev->pkt_count >= 2) {
|
||||
tmp = -((value - fy(2)) * (256 * FRACTION_DENOM)) / size;
|
||||
tmp += mousedev->frac_dy;
|
||||
mousedev->packet.dy = tmp / FRACTION_DENOM;
|
||||
mousedev->frac_dy = tmp - mousedev->packet.dy * FRACTION_DENOM;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ABS_Y:
|
||||
fy(0) = value;
|
||||
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 += mousedev->frac_dy;
|
||||
mousedev->packet.dy = tmp / FRACTION_DENOM;
|
||||
mousedev->frac_dy = tmp - mousedev->packet.dy * FRACTION_DENOM;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
struct mousedev_list *list;
|
||||
struct mousedev_client *client;
|
||||
struct mousedev_motion *p;
|
||||
unsigned long flags;
|
||||
int wake_readers = 0;
|
||||
|
||||
list_for_each_entry(list, &mousedev->list, node) {
|
||||
spin_lock_irqsave(&list->packet_lock, flags);
|
||||
list_for_each_entry(client, &mousedev->client_list, node) {
|
||||
spin_lock_irqsave(&client->packet_lock, flags);
|
||||
|
||||
p = &list->packets[list->head];
|
||||
if (list->ready && p->buttons != mousedev->packet.buttons) {
|
||||
unsigned int new_head = (list->head + 1) % PACKET_QUEUE_LEN;
|
||||
if (new_head != list->tail) {
|
||||
p = &list->packets[list->head = new_head];
|
||||
p = &client->packets[client->head];
|
||||
if (client->ready && p->buttons != mousedev->packet.buttons) {
|
||||
unsigned int new_head = (client->head + 1) % PACKET_QUEUE_LEN;
|
||||
if (new_head != client->tail) {
|
||||
p = &client->packets[client->head = new_head];
|
||||
memset(p, 0, sizeof(struct mousedev_motion));
|
||||
}
|
||||
}
|
||||
|
||||
if (packet->abs_event) {
|
||||
p->dx += packet->x - list->pos_x;
|
||||
p->dy += packet->y - list->pos_y;
|
||||
list->pos_x = packet->x;
|
||||
list->pos_y = packet->y;
|
||||
p->dx += packet->x - client->pos_x;
|
||||
p->dy += packet->y - client->pos_y;
|
||||
client->pos_x = packet->x;
|
||||
client->pos_y = packet->y;
|
||||
}
|
||||
|
||||
list->pos_x += packet->dx;
|
||||
list->pos_x = list->pos_x < 0 ? 0 : (list->pos_x >= xres ? xres : list->pos_x);
|
||||
list->pos_y += packet->dy;
|
||||
list->pos_y = list->pos_y < 0 ? 0 : (list->pos_y >= yres ? yres : list->pos_y);
|
||||
client->pos_x += packet->dx;
|
||||
client->pos_x = client->pos_x < 0 ? 0 : (client->pos_x >= xres ? xres : client->pos_x);
|
||||
client->pos_y += packet->dy;
|
||||
client->pos_y = client->pos_y < 0 ? 0 : (client->pos_y >= yres ? yres : client->pos_y);
|
||||
|
||||
p->dx += packet->dx;
|
||||
p->dy += packet->dy;
|
||||
p->dz += packet->dz;
|
||||
p->buttons = mousedev->packet.buttons;
|
||||
|
||||
if (p->dx || p->dy || p->dz || p->buttons != list->last_buttons)
|
||||
list->ready = 1;
|
||||
if (p->dx || p->dy || p->dz || p->buttons != client->last_buttons)
|
||||
client->ready = 1;
|
||||
|
||||
spin_unlock_irqrestore(&list->packet_lock, flags);
|
||||
spin_unlock_irqrestore(&client->packet_lock, flags);
|
||||
|
||||
if (list->ready) {
|
||||
kill_fasync(&list->fasync, SIGIO, POLL_IN);
|
||||
if (client->ready) {
|
||||
kill_fasync(&client->fasync, SIGIO, POLL_IN);
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@ -364,50 +369,95 @@ static void mousedev_free(struct mousedev *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) {
|
||||
struct mousedev *mousedev = handle->private;
|
||||
if (mousedev_mix.open) {
|
||||
error = input_open_device(&mousedev->handle);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (!mousedev->open) {
|
||||
if (mousedev->exist)
|
||||
input_close_device(&mousedev->handle);
|
||||
else
|
||||
mousedev_free(mousedev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int mousedev_release(struct inode * inode, struct file * file)
|
||||
{
|
||||
struct mousedev_list *list = file->private_data;
|
||||
|
||||
mousedev_fasync(-1, file, 0);
|
||||
|
||||
list_del(&list->node);
|
||||
|
||||
if (!--list->mousedev->open) {
|
||||
if (list->mousedev->minor == MOUSEDEV_MIX)
|
||||
mixdev_release();
|
||||
else if (!mousedev_mix.open) {
|
||||
if (list->mousedev->exist)
|
||||
input_close_device(&list->mousedev->handle);
|
||||
else
|
||||
mousedev_free(list->mousedev);
|
||||
}
|
||||
mousedev->open++;
|
||||
mousedev->mixdev_open++;
|
||||
}
|
||||
|
||||
kfree(list);
|
||||
list_add_tail(&mousedev->mixdev_node, &mousedev_mix_list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mousedev_open(struct inode * inode, struct file * file)
|
||||
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_list *list;
|
||||
struct input_handle *handle;
|
||||
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)
|
||||
input_close_device(&mousedev->handle);
|
||||
else
|
||||
mousedev_free(mousedev);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int mousedev_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct mousedev_client *client = file->private_data;
|
||||
struct mousedev *mousedev = client->mousedev;
|
||||
|
||||
mousedev_fasync(-1, file, 0);
|
||||
|
||||
list_del(&client->node);
|
||||
kfree(client);
|
||||
|
||||
if (!--mousedev->open) {
|
||||
if (mousedev->minor == MOUSEDEV_MIX)
|
||||
mixdev_close_devices();
|
||||
else if (mousedev->exist)
|
||||
input_close_device(&mousedev->handle);
|
||||
else
|
||||
mousedev_free(mousedev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int mousedev_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct mousedev_client *client;
|
||||
struct mousedev *mousedev;
|
||||
int error;
|
||||
int i;
|
||||
|
||||
#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
|
||||
|
@ -417,31 +467,37 @@ static int mousedev_open(struct inode * inode, struct file * file)
|
|||
#endif
|
||||
i = iminor(inode) - MOUSEDEV_MINOR_BASE;
|
||||
|
||||
if (i >= MOUSEDEV_MINORS || !mousedev_table[i])
|
||||
if (i >= MOUSEDEV_MINORS)
|
||||
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;
|
||||
|
||||
spin_lock_init(&list->packet_lock);
|
||||
list->pos_x = xres / 2;
|
||||
list->pos_y = yres / 2;
|
||||
list->mousedev = mousedev_table[i];
|
||||
list_add_tail(&list->node, &mousedev_table[i]->list);
|
||||
file->private_data = list;
|
||||
spin_lock_init(&client->packet_lock);
|
||||
client->pos_x = xres / 2;
|
||||
client->pos_y = yres / 2;
|
||||
client->mousedev = mousedev;
|
||||
list_add_tail(&client->node, &mousedev->client_list);
|
||||
|
||||
if (!list->mousedev->open++) {
|
||||
if (list->mousedev->minor == MOUSEDEV_MIX) {
|
||||
list_for_each_entry(handle, &mousedev_handler.h_list, h_node) {
|
||||
mousedev = handle->private;
|
||||
if (!mousedev->open && mousedev->exist)
|
||||
input_open_device(handle);
|
||||
if (!mousedev->open++) {
|
||||
if (mousedev->minor == MOUSEDEV_MIX)
|
||||
mixdev_open_devices();
|
||||
else if (mousedev->exist) {
|
||||
error = input_open_device(&mousedev->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;
|
||||
}
|
||||
|
||||
|
@ -450,13 +506,13 @@ static inline int mousedev_limit_delta(int delta, int limit)
|
|||
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;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&list->packet_lock, flags);
|
||||
p = &list->packets[list->tail];
|
||||
spin_lock_irqsave(&client->packet_lock, flags);
|
||||
p = &client->packets[client->tail];
|
||||
|
||||
ps2_data[0] = 0x08 | ((p->dx < 0) << 4) | ((p->dy < 0) << 5) | (p->buttons & 0x07);
|
||||
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->dy -= ps2_data[2];
|
||||
|
||||
switch (list->mode) {
|
||||
switch (client->mode) {
|
||||
case MOUSEDEV_EMUL_EXPS:
|
||||
ps2_data[3] = mousedev_limit_delta(p->dz, 7);
|
||||
p->dz -= ps2_data[3];
|
||||
ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1);
|
||||
list->bufsiz = 4;
|
||||
client->bufsiz = 4;
|
||||
break;
|
||||
|
||||
case MOUSEDEV_EMUL_IMPS:
|
||||
ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
|
||||
ps2_data[3] = mousedev_limit_delta(p->dz, 127);
|
||||
p->dz -= ps2_data[3];
|
||||
list->bufsiz = 4;
|
||||
client->bufsiz = 4;
|
||||
break;
|
||||
|
||||
case MOUSEDEV_EMUL_PS2:
|
||||
default:
|
||||
ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
|
||||
p->dz = 0;
|
||||
list->bufsiz = 3;
|
||||
client->bufsiz = 3;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!p->dx && !p->dy && !p->dz) {
|
||||
if (list->tail == list->head) {
|
||||
list->ready = 0;
|
||||
list->last_buttons = p->buttons;
|
||||
if (client->tail == client->head) {
|
||||
client->ready = 0;
|
||||
client->last_buttons = p->buttons;
|
||||
} 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 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))
|
||||
return -EFAULT;
|
||||
|
||||
if (c == mousedev_imex_seq[list->imexseq]) {
|
||||
if (++list->imexseq == MOUSEDEV_SEQ_LEN) {
|
||||
list->imexseq = 0;
|
||||
list->mode = MOUSEDEV_EMUL_EXPS;
|
||||
if (c == mousedev_imex_seq[client->imexseq]) {
|
||||
if (++client->imexseq == MOUSEDEV_SEQ_LEN) {
|
||||
client->imexseq = 0;
|
||||
client->mode = MOUSEDEV_EMUL_EXPS;
|
||||
}
|
||||
} else
|
||||
list->imexseq = 0;
|
||||
client->imexseq = 0;
|
||||
|
||||
if (c == mousedev_imps_seq[list->impsseq]) {
|
||||
if (++list->impsseq == MOUSEDEV_SEQ_LEN) {
|
||||
list->impsseq = 0;
|
||||
list->mode = MOUSEDEV_EMUL_IMPS;
|
||||
if (c == mousedev_imps_seq[client->impsseq]) {
|
||||
if (++client->impsseq == MOUSEDEV_SEQ_LEN) {
|
||||
client->impsseq = 0;
|
||||
client->mode = MOUSEDEV_EMUL_IMPS;
|
||||
}
|
||||
} else
|
||||
list->impsseq = 0;
|
||||
client->impsseq = 0;
|
||||
|
||||
list->ps2[0] = 0xfa;
|
||||
client->ps2[0] = 0xfa;
|
||||
|
||||
switch (c) {
|
||||
|
||||
case 0xeb: /* Poll */
|
||||
mousedev_packet(list, &list->ps2[1]);
|
||||
list->bufsiz++; /* account for leading ACK */
|
||||
mousedev_packet(client, &client->ps2[1]);
|
||||
client->bufsiz++; /* account for leading ACK */
|
||||
break;
|
||||
|
||||
case 0xf2: /* Get ID */
|
||||
switch (list->mode) {
|
||||
case MOUSEDEV_EMUL_PS2: list->ps2[1] = 0; break;
|
||||
case MOUSEDEV_EMUL_IMPS: list->ps2[1] = 3; break;
|
||||
case MOUSEDEV_EMUL_EXPS: list->ps2[1] = 4; break;
|
||||
switch (client->mode) {
|
||||
case MOUSEDEV_EMUL_PS2: client->ps2[1] = 0; break;
|
||||
case MOUSEDEV_EMUL_IMPS: client->ps2[1] = 3; break;
|
||||
case MOUSEDEV_EMUL_EXPS: client->ps2[1] = 4; break;
|
||||
}
|
||||
list->bufsiz = 2;
|
||||
client->bufsiz = 2;
|
||||
break;
|
||||
|
||||
case 0xe9: /* Get info */
|
||||
list->ps2[1] = 0x60; list->ps2[2] = 3; list->ps2[3] = 200;
|
||||
list->bufsiz = 4;
|
||||
client->ps2[1] = 0x60; client->ps2[2] = 3; client->ps2[3] = 200;
|
||||
client->bufsiz = 4;
|
||||
break;
|
||||
|
||||
case 0xff: /* Reset */
|
||||
list->impsseq = list->imexseq = 0;
|
||||
list->mode = MOUSEDEV_EMUL_PS2;
|
||||
list->ps2[1] = 0xaa; list->ps2[2] = 0x00;
|
||||
list->bufsiz = 3;
|
||||
client->impsseq = client->imexseq = 0;
|
||||
client->mode = MOUSEDEV_EMUL_PS2;
|
||||
client->ps2[1] = 0xaa; client->ps2[2] = 0x00;
|
||||
client->bufsiz = 3;
|
||||
break;
|
||||
|
||||
default:
|
||||
list->bufsiz = 1;
|
||||
client->bufsiz = 1;
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (!list->ready && !list->buffer && (file->f_flags & O_NONBLOCK))
|
||||
if (!client->ready && !client->buffer && (file->f_flags & O_NONBLOCK))
|
||||
return -EAGAIN;
|
||||
|
||||
retval = wait_event_interruptible(list->mousedev->wait,
|
||||
!list->mousedev->exist || list->ready || list->buffer);
|
||||
retval = wait_event_interruptible(client->mousedev->wait,
|
||||
!client->mousedev->exist || client->ready || client->buffer);
|
||||
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (!list->mousedev->exist)
|
||||
if (!client->mousedev->exist)
|
||||
return -ENODEV;
|
||||
|
||||
if (!list->buffer && list->ready) {
|
||||
mousedev_packet(list, list->ps2);
|
||||
list->buffer = list->bufsiz;
|
||||
if (!client->buffer && client->ready) {
|
||||
mousedev_packet(client, client->ps2);
|
||||
client->buffer = client->bufsiz;
|
||||
}
|
||||
|
||||
if (count > list->buffer)
|
||||
count = list->buffer;
|
||||
if (count > client->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 count;
|
||||
|
@ -607,11 +663,12 @@ static ssize_t mousedev_read(struct file * file, char __user * buffer, size_t co
|
|||
/* No kernel lock - fine */
|
||||
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);
|
||||
return ((list->ready || list->buffer) ? (POLLIN | POLLRDNORM) : 0) |
|
||||
(list->mousedev->exist ? 0 : (POLLHUP | POLLERR));
|
||||
poll_wait(file, &mousedev->wait, wait);
|
||||
return ((client->ready || client->buffer) ? (POLLIN | POLLRDNORM) : 0) |
|
||||
(mousedev->exist ? 0 : (POLLHUP | POLLERR));
|
||||
}
|
||||
|
||||
static const struct file_operations mousedev_fops = {
|
||||
|
@ -624,23 +681,27 @@ static const struct file_operations mousedev_fops = {
|
|||
.fasync = mousedev_fasync,
|
||||
};
|
||||
|
||||
static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev,
|
||||
const struct input_device_id *id)
|
||||
static int mousedev_connect(struct input_handler *handler, struct input_dev *dev,
|
||||
const struct input_device_id *id)
|
||||
{
|
||||
struct mousedev *mousedev;
|
||||
struct class_device *cdev;
|
||||
int minor = 0;
|
||||
dev_t devt;
|
||||
int minor;
|
||||
int error;
|
||||
|
||||
for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++);
|
||||
if (minor == MOUSEDEV_MINORS) {
|
||||
printk(KERN_ERR "mousedev: no more free mousedev devices\n");
|
||||
return NULL;
|
||||
return -ENFILE;
|
||||
}
|
||||
|
||||
if (!(mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL)))
|
||||
return NULL;
|
||||
mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL);
|
||||
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);
|
||||
|
||||
mousedev->minor = minor;
|
||||
|
@ -651,42 +712,66 @@ static struct input_handle *mousedev_connect(struct input_handler *handler, stru
|
|||
mousedev->handle.private = mousedev;
|
||||
sprintf(mousedev->name, "mouse%d", minor);
|
||||
|
||||
if (mousedev_mix.open)
|
||||
input_open_device(&mousedev->handle);
|
||||
|
||||
mousedev_table[minor] = mousedev;
|
||||
|
||||
cdev = class_device_create(&input_class, &dev->cdev,
|
||||
MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor),
|
||||
dev->cdev.dev, mousedev->name);
|
||||
devt = MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor),
|
||||
|
||||
cdev = class_device_create(&input_class, &dev->cdev, devt,
|
||||
dev->cdev.dev, mousedev->name);
|
||||
if (IS_ERR(cdev)) {
|
||||
error = PTR_ERR(cdev);
|
||||
goto err_free_mousedev;
|
||||
}
|
||||
|
||||
/* temporary symlink to keep userspace happy */
|
||||
sysfs_create_link(&input_class.subsys.kobj, &cdev->kobj,
|
||||
mousedev->name);
|
||||
error = sysfs_create_link(&input_class.subsys.kobj,
|
||||
&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)
|
||||
{
|
||||
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);
|
||||
class_device_destroy(&input_class,
|
||||
MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + mousedev->minor));
|
||||
mousedev->exist = 0;
|
||||
|
||||
mixdev_remove_device(mousedev);
|
||||
|
||||
if (mousedev->open) {
|
||||
input_close_device(handle);
|
||||
wake_up_interruptible(&mousedev->wait);
|
||||
list_for_each_entry(list, &mousedev->list, node)
|
||||
kill_fasync(&list->fasync, SIGIO, POLL_HUP);
|
||||
} else {
|
||||
if (mousedev_mix.open)
|
||||
input_close_device(handle);
|
||||
list_for_each_entry(client, &mousedev->client_list, node)
|
||||
kill_fasync(&client->fasync, SIGIO, POLL_HUP);
|
||||
} else
|
||||
mousedev_free(mousedev);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct input_device_id mousedev_ids[] = {
|
||||
|
@ -714,7 +799,7 @@ static const struct input_device_id mousedev_ids[] = {
|
|||
.absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) | BIT(ABS_TOOL_WIDTH) },
|
||||
}, /* A touchpad */
|
||||
|
||||
{ }, /* Terminating entry */
|
||||
{ }, /* Terminating entry */
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(input, mousedev_ids);
|
||||
|
@ -746,7 +831,7 @@ static int __init mousedev_init(void)
|
|||
return error;
|
||||
|
||||
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);
|
||||
mousedev_table[MOUSEDEV_MIX] = &mousedev_mix;
|
||||
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");
|
|
@ -32,11 +32,11 @@
|
|||
*
|
||||
* Driver theory of operation:
|
||||
*
|
||||
* Some access methods and an ISR is defined by the sub-driver
|
||||
* (e.g. hp_sdc_mlc.c). These methods are expected to provide a
|
||||
* few bits of logic in addition to raw access to the HIL MLC,
|
||||
* specifically, the ISR, which is entirely registered by the
|
||||
* sub-driver and invoked directly, must check for record
|
||||
* Some access methods and an ISR is defined by the sub-driver
|
||||
* (e.g. hp_sdc_mlc.c). These methods are expected to provide a
|
||||
* few bits of logic in addition to raw access to the HIL MLC,
|
||||
* specifically, the ISR, which is entirely registered by the
|
||||
* sub-driver and invoked directly, must check for record
|
||||
* termination or packet match, at which point a semaphore must
|
||||
* be cleared and then the hil_mlcs_tasklet must be scheduled.
|
||||
*
|
||||
|
@ -47,7 +47,7 @@
|
|||
* itself if output is pending. (This rescheduling should be replaced
|
||||
* at some point with a sub-driver-specific mechanism.)
|
||||
*
|
||||
* A timer task prods the tasklet once per second to prevent
|
||||
* A timer task prods the tasklet once per second to prevent
|
||||
* hangups when attached devices do not return expected data
|
||||
* and to initiate probes of the loop for new devices.
|
||||
*/
|
||||
|
@ -83,69 +83,85 @@ DECLARE_TASKLET_DISABLED(hil_mlcs_tasklet, hil_mlcs_process, 0);
|
|||
|
||||
/********************** 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;
|
||||
for (j = val; j < 7 ; j++) {
|
||||
|
||||
for (j = val; j < 7 ; j++)
|
||||
mlc->di_map[j] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void hil_mlc_clear_di_scratch (hil_mlc *mlc) {
|
||||
memset(&(mlc->di_scratch), 0, sizeof(mlc->di_scratch));
|
||||
static void hil_mlc_clear_di_scratch(hil_mlc *mlc)
|
||||
{
|
||||
memset(&mlc->di_scratch, 0, sizeof(mlc->di_scratch));
|
||||
}
|
||||
|
||||
static void hil_mlc_copy_di_scratch (hil_mlc *mlc, int idx) {
|
||||
memcpy(&(mlc->di[idx]), &(mlc->di_scratch), sizeof(mlc->di_scratch));
|
||||
static void hil_mlc_copy_di_scratch(hil_mlc *mlc, int idx)
|
||||
{
|
||||
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;
|
||||
|
||||
for (idx = 0; idx < HIL_MLC_DEVMEM; idx++) {
|
||||
int j, found;
|
||||
int j, found = 0;
|
||||
|
||||
/* In-use slots are not eligible. */
|
||||
found = 0;
|
||||
for (j = 0; j < 7 ; j++) {
|
||||
if (mlc->di_map[j] == idx) found++;
|
||||
}
|
||||
if (found) continue;
|
||||
if (!memcmp(mlc->di + idx,
|
||||
&(mlc->di_scratch),
|
||||
sizeof(mlc->di_scratch))) break;
|
||||
for (j = 0; j < 7 ; j++)
|
||||
if (mlc->di_map[j] == idx)
|
||||
found++;
|
||||
|
||||
if (found)
|
||||
continue;
|
||||
|
||||
if (!memcmp(mlc->di + idx, &mlc->di_scratch,
|
||||
sizeof(mlc->di_scratch)))
|
||||
break;
|
||||
}
|
||||
return((idx >= HIL_MLC_DEVMEM) ? -1 : idx);
|
||||
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;
|
||||
/* TODO: Pick all-zero slots first, failing that,
|
||||
* randomize the slot picked among those eligible.
|
||||
|
||||
/* TODO: Pick all-zero slots first, failing that,
|
||||
* randomize the slot picked among those eligible.
|
||||
*/
|
||||
for (idx = 0; idx < HIL_MLC_DEVMEM; idx++) {
|
||||
int j, found;
|
||||
found = 0;
|
||||
for (j = 0; j < 7 ; j++) {
|
||||
if (mlc->di_map[j] == idx) found++;
|
||||
}
|
||||
if (!found) break;
|
||||
int j, found = 0;
|
||||
|
||||
for (j = 0; j < 7 ; j++)
|
||||
if (mlc->di_map[j] == idx)
|
||||
found++;
|
||||
|
||||
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;
|
||||
|
||||
for (idx = 0; idx < HIL_MLC_DEVMEM; idx++) {
|
||||
int j, found;
|
||||
found = 0;
|
||||
for (j = 0; j < 7 ; j++) {
|
||||
if (mlc->di_map[j] == idx) found++;
|
||||
}
|
||||
if (!found) mlc->serio_map[idx].di_revmap = -1;
|
||||
int j, found = 0;
|
||||
|
||||
for (j = 0; j < 7 ; j++)
|
||||
if (mlc->di_map[j] == idx)
|
||||
found++;
|
||||
|
||||
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;
|
||||
struct serio *serio;
|
||||
struct serio_driver *drv;
|
||||
|
@ -157,26 +173,31 @@ static void hil_mlc_send_polls(hil_mlc *mlc) {
|
|||
|
||||
while (mlc->icount < 15 - i) {
|
||||
hil_packet p;
|
||||
|
||||
p = mlc->ipacket[i];
|
||||
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, HIL_ERR_INT >> 16, 0);
|
||||
drv->interrupt(serio, HIL_PKT_CMD >> 8, 0);
|
||||
drv->interrupt(serio, HIL_CMD_POL + cnt, 0);
|
||||
}
|
||||
|
||||
drv->interrupt(serio, 0, 0);
|
||||
drv->interrupt(serio, HIL_ERR_INT >> 16, 0);
|
||||
drv->interrupt(serio, HIL_PKT_CMD >> 8, 0);
|
||||
drv->interrupt(serio, HIL_CMD_POL + cnt, 0);
|
||||
skip:
|
||||
did = (p & HIL_PKT_ADDR_MASK) >> 8;
|
||||
serio = did ? mlc->serio[mlc->di_map[did-1]] : NULL;
|
||||
drv = (serio != NULL) ? serio->drv : NULL;
|
||||
cnt = 0;
|
||||
}
|
||||
cnt++; i++;
|
||||
if (drv == NULL || drv->interrupt == NULL) continue;
|
||||
drv->interrupt(serio, (p >> 24), 0);
|
||||
drv->interrupt(serio, (p >> 16) & 0xff, 0);
|
||||
drv->interrupt(serio, (p >> 8) & ~HIL_PKT_ADDR_MASK, 0);
|
||||
drv->interrupt(serio, p & 0xff, 0);
|
||||
|
||||
cnt++;
|
||||
i++;
|
||||
|
||||
if (drv && drv->interrupt) {
|
||||
drv->interrupt(serio, (p >> 24), 0);
|
||||
drv->interrupt(serio, (p >> 16) & 0xff, 0);
|
||||
drv->interrupt(serio, (p >> 8) & ~HIL_PKT_ADDR_MASK, 0);
|
||||
drv->interrupt(serio, p & 0xff, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -215,12 +236,16 @@ static void hil_mlc_send_polls(hil_mlc *mlc) {
|
|||
#define HILSEN_DOZE (HILSEN_SAME | HILSEN_SCHED | 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;
|
||||
|
||||
rc = hil_mlc_match_di_scratch(mlc);
|
||||
if (rc == -1) {
|
||||
rc = hil_mlc_find_free_di(mlc);
|
||||
if (rc == -1) goto err;
|
||||
if (rc == -1)
|
||||
goto err;
|
||||
|
||||
#ifdef HIL_MLC_DEBUG
|
||||
printk(KERN_DEBUG PREFIX "new in slot %i\n", rc);
|
||||
#endif
|
||||
|
@ -231,6 +256,7 @@ static int hilse_match(hil_mlc *mlc, int unused) {
|
|||
serio_rescan(mlc->serio[rc]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
mlc->di_map[mlc->ddi] = rc;
|
||||
#ifdef HIL_MLC_DEBUG
|
||||
printk(KERN_DEBUG PREFIX "same in slot %i\n", rc);
|
||||
|
@ -238,152 +264,177 @@ static int hilse_match(hil_mlc *mlc, int unused) {
|
|||
mlc->serio_map[rc].di_revmap = mlc->ddi;
|
||||
hil_mlc_clean_serio_map(mlc);
|
||||
return 0;
|
||||
|
||||
err:
|
||||
printk(KERN_ERR PREFIX "Residual device slots exhausted, close some serios!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
do_gettimeofday(&tv);
|
||||
|
||||
if(mlc->lcv == 0) goto restart; /* First init, no need to dally */
|
||||
if(tv.tv_sec - mlc->lcv_tv.tv_sec < 5) return -1;
|
||||
restart:
|
||||
if (mlc->lcv && (tv.tv_sec - mlc->lcv_tv.tv_sec) < 5)
|
||||
return -1;
|
||||
|
||||
mlc->lcv_tv = tv;
|
||||
mlc->lcv = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hilse_inc_lcv(hil_mlc *mlc, int lim) {
|
||||
if (mlc->lcv++ >= lim) return -1;
|
||||
return 0;
|
||||
static int hilse_inc_lcv(hil_mlc *mlc, int lim)
|
||||
{
|
||||
return mlc->lcv++ >= lim ? -1 : 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;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* 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;
|
||||
hil_mlc_clear_di_map(mlc, val + 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hilse_dec_ddi(hil_mlc *mlc, int unused) {
|
||||
static int hilse_dec_ddi(hil_mlc *mlc, int unused)
|
||||
{
|
||||
mlc->ddi--;
|
||||
if (mlc->ddi <= -1) {
|
||||
if (mlc->ddi <= -1) {
|
||||
mlc->ddi = -1;
|
||||
hil_mlc_clear_di_map(mlc, 0);
|
||||
return -1;
|
||||
}
|
||||
hil_mlc_clear_di_map(mlc, mlc->ddi + 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hilse_inc_ddi(hil_mlc *mlc, int unused) {
|
||||
if (mlc->ddi >= 6) {
|
||||
BUG();
|
||||
return -1;
|
||||
}
|
||||
static int hilse_inc_ddi(hil_mlc *mlc, int unused)
|
||||
{
|
||||
BUG_ON(mlc->ddi >= 6);
|
||||
mlc->ddi++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hilse_take_idd(hil_mlc *mlc, int unused) {
|
||||
static int hilse_take_idd(hil_mlc *mlc, int unused)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Help the state engine:
|
||||
* Is this a real IDD response or just an echo?
|
||||
/* Help the state engine:
|
||||
* Is this a real IDD response or just an echo?
|
||||
*
|
||||
* 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. */
|
||||
for (i = 1; i < 16; i++) {
|
||||
if (((mlc->ipacket[i] & HIL_PKT_ADDR_MASK) ==
|
||||
if (((mlc->ipacket[i] & HIL_PKT_ADDR_MASK) ==
|
||||
(mlc->ipacket[0] & HIL_PKT_ADDR_MASK)) &&
|
||||
(mlc->ipacket[i] & HIL_PKT_CMD) &&
|
||||
(mlc->ipacket[i] & HIL_PKT_CMD) &&
|
||||
((mlc->ipacket[i] & HIL_PKT_DATA_MASK) == HIL_CMD_IDD))
|
||||
break;
|
||||
}
|
||||
if (i > 15) goto bail;
|
||||
if (i > 15)
|
||||
goto bail;
|
||||
|
||||
/* And the rest of the packets should still be clear. */
|
||||
while (++i < 16) {
|
||||
if (mlc->ipacket[i]) break;
|
||||
}
|
||||
if (i < 16) goto bail;
|
||||
for (i = 0; i < 16; i++) {
|
||||
mlc->di_scratch.idd[i] =
|
||||
while (++i < 16)
|
||||
if (mlc->ipacket[i])
|
||||
break;
|
||||
|
||||
if (i < 16)
|
||||
goto bail;
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
mlc->di_scratch.idd[i] =
|
||||
mlc->ipacket[i] & HIL_PKT_DATA_MASK;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
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 0;
|
||||
|
||||
bail:
|
||||
mlc->ddi--;
|
||||
|
||||
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;
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
mlc->di_scratch.rsc[i] =
|
||||
for (i = 0; i < 16; i++)
|
||||
mlc->di_scratch.rsc[i] =
|
||||
mlc->ipacket[i] & HIL_PKT_DATA_MASK;
|
||||
}
|
||||
|
||||
/* 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 0;
|
||||
}
|
||||
|
||||
static int hilse_take_exd(hil_mlc *mlc, int unused) {
|
||||
static int hilse_take_exd(hil_mlc *mlc, int unused)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
mlc->di_scratch.exd[i] =
|
||||
for (i = 0; i < 16; i++)
|
||||
mlc->di_scratch.exd[i] =
|
||||
mlc->ipacket[i] & HIL_PKT_DATA_MASK;
|
||||
}
|
||||
|
||||
/* 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 0;
|
||||
}
|
||||
|
||||
static int hilse_take_rnm(hil_mlc *mlc, int unused) {
|
||||
static int hilse_take_rnm(hil_mlc *mlc, int unused)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
mlc->di_scratch.rnm[i] =
|
||||
for (i = 0; i < 16; i++)
|
||||
mlc->di_scratch.rnm[i] =
|
||||
mlc->ipacket[i] & HIL_PKT_DATA_MASK;
|
||||
}
|
||||
do {
|
||||
char nam[17];
|
||||
snprintf(nam, 16, "%s", mlc->di_scratch.rnm);
|
||||
nam[16] = '\0';
|
||||
printk(KERN_INFO PREFIX "Device name gotten: %s\n", nam);
|
||||
} while (0);
|
||||
|
||||
printk(KERN_INFO PREFIX "Device name gotten: %16s\n",
|
||||
mlc->di_scratch.rnm);
|
||||
|
||||
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;
|
||||
|
||||
hil_mlc_send_polls(mlc);
|
||||
|
||||
if (!hil_mlcs_probe) return 0;
|
||||
if (!hil_mlcs_probe)
|
||||
return 0;
|
||||
hil_mlcs_probe = 0;
|
||||
mlc->opercnt = 0;
|
||||
return 1;
|
||||
|
@ -408,7 +459,7 @@ static int hilse_operate(hil_mlc *mlc, int repoll) {
|
|||
#define OUT_LAST(pack) \
|
||||
{ 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 */
|
||||
FUNC(hilse_init_lcv, 0, HILSEN_NEXT, HILSEN_SLEEP, 0)
|
||||
|
@ -428,7 +479,7 @@ struct hilse_node hil_mlc_se[HILSEN_END] = {
|
|||
EXPECT(HIL_ERR_INT | TEST_PACKET(0xa),
|
||||
2000, HILSEN_NEXT, HILSEN_RESTART, HILSEN_RESTART)
|
||||
OUT(HIL_CTRL_ONLY | 0) /* Disable test mode */
|
||||
|
||||
|
||||
/* 9 HILSEN_DHR */
|
||||
FUNC(hilse_init_lcv, 0, HILSEN_NEXT, HILSEN_SLEEP, 0)
|
||||
|
||||
|
@ -439,7 +490,7 @@ struct hilse_node hil_mlc_se[HILSEN_END] = {
|
|||
IN(300000, HILSEN_DHR2, HILSEN_DHR2, HILSEN_NEXT)
|
||||
|
||||
/* 14 HILSEN_IFC */
|
||||
OUT(HIL_PKT_CMD | HIL_CMD_IFC)
|
||||
OUT(HIL_PKT_CMD | HIL_CMD_IFC)
|
||||
EXPECT(HIL_PKT_CMD | HIL_CMD_IFC | HIL_ERR_INT,
|
||||
20000, HILSEN_DISC, HILSEN_DHR2, HILSEN_NEXT )
|
||||
|
||||
|
@ -455,7 +506,7 @@ struct hilse_node hil_mlc_se[HILSEN_END] = {
|
|||
|
||||
/* 18 HILSEN_HEAL */
|
||||
OUT_LAST(HIL_CMD_ELB)
|
||||
EXPECT_LAST(HIL_CMD_ELB | HIL_ERR_INT,
|
||||
EXPECT_LAST(HIL_CMD_ELB | HIL_ERR_INT,
|
||||
20000, HILSEN_REPOLL, HILSEN_DSR, HILSEN_NEXT)
|
||||
FUNC(hilse_dec_ddi, 0, HILSEN_HEAL, HILSEN_NEXT, 0)
|
||||
|
||||
|
@ -503,7 +554,7 @@ struct hilse_node hil_mlc_se[HILSEN_END] = {
|
|||
|
||||
/* 44 HILSEN_PROBE */
|
||||
OUT_LAST(HIL_PKT_CMD | HIL_CMD_EPT)
|
||||
IN(10000, HILSEN_DISC, HILSEN_DSR, HILSEN_NEXT)
|
||||
IN(10000, HILSEN_DISC, HILSEN_DSR, HILSEN_NEXT)
|
||||
OUT_DISC(HIL_PKT_CMD | HIL_CMD_ELB)
|
||||
IN(10000, HILSEN_DISC, HILSEN_DSR, HILSEN_NEXT)
|
||||
OUT(HIL_PKT_CMD | HIL_CMD_ACF | 1)
|
||||
|
@ -514,7 +565,7 @@ struct hilse_node hil_mlc_se[HILSEN_END] = {
|
|||
/* 52 HILSEN_DSR */
|
||||
FUNC(hilse_set_ddi, -1, HILSEN_NEXT, 0, 0)
|
||||
OUT(HIL_PKT_CMD | HIL_CMD_DSR)
|
||||
IN(20000, HILSEN_DHR, HILSEN_DHR, HILSEN_IFC)
|
||||
IN(20000, HILSEN_DHR, HILSEN_DHR, HILSEN_IFC)
|
||||
|
||||
/* 55 HILSEN_REPOLL */
|
||||
OUT(HIL_PKT_CMD | HIL_CMD_RPL)
|
||||
|
@ -523,14 +574,15 @@ struct hilse_node hil_mlc_se[HILSEN_END] = {
|
|||
FUNC(hilse_operate, 1, HILSEN_OPERATE, HILSEN_IFC, HILSEN_PROBE)
|
||||
|
||||
/* 58 HILSEN_IFCACF */
|
||||
OUT(HIL_PKT_CMD | HIL_CMD_IFC)
|
||||
OUT(HIL_PKT_CMD | HIL_CMD_IFC)
|
||||
EXPECT(HIL_PKT_CMD | HIL_CMD_IFC | HIL_ERR_INT,
|
||||
20000, HILSEN_ACF2, HILSEN_DHR2, HILSEN_HEAL)
|
||||
|
||||
/* 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) {
|
||||
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));
|
||||
mlc->icount = 15;
|
||||
memset(mlc->ipacket, 0, 16 * sizeof(hil_packet));
|
||||
BUG_ON(down_trylock(&(mlc->isem)));
|
||||
|
||||
return;
|
||||
BUG_ON(down_trylock(&mlc->isem));
|
||||
}
|
||||
|
||||
#ifdef HIL_MLC_DEBUG
|
||||
static int doze = 0;
|
||||
static int doze;
|
||||
static int seidx; /* For debug */
|
||||
static int kick = 1;
|
||||
#endif
|
||||
|
||||
static int hilse_donode (hil_mlc *mlc) {
|
||||
struct hilse_node *node;
|
||||
static int hilse_donode(hil_mlc *mlc)
|
||||
{
|
||||
const struct hilse_node *node;
|
||||
int nextidx = 0;
|
||||
int sched_long = 0;
|
||||
unsigned long flags;
|
||||
|
||||
#ifdef HIL_MLC_DEBUG
|
||||
if (mlc->seidx && (mlc->seidx != seidx) && mlc->seidx != 41 && mlc->seidx != 42 && mlc->seidx != 43) {
|
||||
printk(KERN_DEBUG PREFIX "z%i \n%s {%i}", doze, kick ? "K" : "", mlc->seidx);
|
||||
if (mlc->seidx && mlc->seidx != seidx &&
|
||||
mlc->seidx != 41 && mlc->seidx != 42 && mlc->seidx != 43) {
|
||||
printk(KERN_DEBUG PREFIX "z%i \n {%i}", doze, mlc->seidx);
|
||||
doze = 0;
|
||||
}
|
||||
kick = 0;
|
||||
|
||||
seidx = mlc->seidx;
|
||||
#endif
|
||||
|
@ -588,52 +638,61 @@ static int hilse_donode (hil_mlc *mlc) {
|
|||
hil_packet pack;
|
||||
|
||||
case HILSE_FUNC:
|
||||
if (node->object.func == NULL) break;
|
||||
BUG_ON(node->object.func == NULL);
|
||||
rc = node->object.func(mlc, node->arg);
|
||||
nextidx = (rc > 0) ? node->ugly :
|
||||
nextidx = (rc > 0) ? node->ugly :
|
||||
((rc < 0) ? node->bad : node->good);
|
||||
if (nextidx == HILSEN_FOLLOW) nextidx = rc;
|
||||
if (nextidx == HILSEN_FOLLOW)
|
||||
nextidx = rc;
|
||||
break;
|
||||
|
||||
case HILSE_EXPECT_LAST:
|
||||
case HILSE_EXPECT_DISC:
|
||||
case HILSE_EXPECT:
|
||||
case HILSE_IN:
|
||||
/* 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);
|
||||
if (rc == 2) {
|
||||
nextidx = HILSEN_DOZE;
|
||||
sched_long = 1;
|
||||
write_unlock_irqrestore(&(mlc->lock), flags);
|
||||
write_unlock_irqrestore(&mlc->lock, flags);
|
||||
break;
|
||||
}
|
||||
if (rc == 1) nextidx = node->ugly;
|
||||
else if (rc == 0) nextidx = node->good;
|
||||
else nextidx = node->bad;
|
||||
if (rc == 1)
|
||||
nextidx = node->ugly;
|
||||
else if (rc == 0)
|
||||
nextidx = node->good;
|
||||
else
|
||||
nextidx = node->bad;
|
||||
mlc->istarted = 0;
|
||||
write_unlock_irqrestore(&(mlc->lock), flags);
|
||||
write_unlock_irqrestore(&mlc->lock, flags);
|
||||
break;
|
||||
|
||||
case HILSE_OUT_LAST:
|
||||
write_lock_irqsave(&(mlc->lock), flags);
|
||||
write_lock_irqsave(&mlc->lock, flags);
|
||||
pack = node->object.packet;
|
||||
pack |= ((mlc->ddi + 1) << HIL_PKT_ADDR_SHIFT);
|
||||
goto out;
|
||||
|
||||
case HILSE_OUT_DISC:
|
||||
write_lock_irqsave(&(mlc->lock), flags);
|
||||
write_lock_irqsave(&mlc->lock, flags);
|
||||
pack = node->object.packet;
|
||||
pack |= ((mlc->ddi + 2) << HIL_PKT_ADDR_SHIFT);
|
||||
goto out;
|
||||
|
||||
case HILSE_OUT:
|
||||
write_lock_irqsave(&(mlc->lock), flags);
|
||||
write_lock_irqsave(&mlc->lock, flags);
|
||||
pack = node->object.packet;
|
||||
out:
|
||||
if (mlc->istarted) goto out2;
|
||||
if (mlc->istarted)
|
||||
goto out2;
|
||||
/* Prepare to receive input */
|
||||
if ((node + 1)->act & HILSE_IN)
|
||||
hilse_setup_input(mlc, node + 1);
|
||||
|
||||
out2:
|
||||
write_unlock_irqrestore(&(mlc->lock), flags);
|
||||
write_unlock_irqrestore(&mlc->lock, flags);
|
||||
|
||||
if (down_trylock(&mlc->osem)) {
|
||||
nextidx = HILSEN_DOZE;
|
||||
|
@ -641,60 +700,71 @@ static int hilse_donode (hil_mlc *mlc) {
|
|||
}
|
||||
up(&mlc->osem);
|
||||
|
||||
write_lock_irqsave(&(mlc->lock), flags);
|
||||
if (!(mlc->ostarted)) {
|
||||
write_lock_irqsave(&mlc->lock, flags);
|
||||
if (!mlc->ostarted) {
|
||||
mlc->ostarted = 1;
|
||||
mlc->opacket = pack;
|
||||
mlc->out(mlc);
|
||||
nextidx = HILSEN_DOZE;
|
||||
write_unlock_irqrestore(&(mlc->lock), flags);
|
||||
write_unlock_irqrestore(&mlc->lock, flags);
|
||||
break;
|
||||
}
|
||||
mlc->ostarted = 0;
|
||||
do_gettimeofday(&(mlc->instart));
|
||||
write_unlock_irqrestore(&(mlc->lock), flags);
|
||||
write_unlock_irqrestore(&mlc->lock, flags);
|
||||
nextidx = HILSEN_NEXT;
|
||||
break;
|
||||
|
||||
case HILSE_CTS:
|
||||
write_lock_irqsave(&mlc->lock, flags);
|
||||
nextidx = mlc->cts(mlc) ? node->bad : node->good;
|
||||
write_unlock_irqrestore(&mlc->lock, flags);
|
||||
break;
|
||||
|
||||
default:
|
||||
BUG();
|
||||
nextidx = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef HIL_MLC_DEBUG
|
||||
if (nextidx == HILSEN_DOZE) doze++;
|
||||
if (nextidx == HILSEN_DOZE)
|
||||
doze++;
|
||||
#endif
|
||||
|
||||
while (nextidx & HILSEN_SCHED) {
|
||||
struct timeval tv;
|
||||
|
||||
if (!sched_long) goto sched;
|
||||
if (!sched_long)
|
||||
goto sched;
|
||||
|
||||
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;
|
||||
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;
|
||||
mod_timer(&hil_mlcs_kicker, jiffies + tv.tv_usec);
|
||||
break;
|
||||
sched:
|
||||
tasklet_schedule(&hil_mlcs_tasklet);
|
||||
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_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_BREAK) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************** tasklet context functions **************************/
|
||||
static void hil_mlcs_process(unsigned long unused) {
|
||||
static void hil_mlcs_process(unsigned long unused)
|
||||
{
|
||||
struct list_head *tmp;
|
||||
|
||||
read_lock(&hil_mlcs_lock);
|
||||
|
@ -702,19 +772,20 @@ static void hil_mlcs_process(unsigned long unused) {
|
|||
struct hil_mlc *mlc = list_entry(tmp, hil_mlc, list);
|
||||
while (hilse_donode(mlc) == 0) {
|
||||
#ifdef HIL_MLC_DEBUG
|
||||
if (mlc->seidx != 41 &&
|
||||
mlc->seidx != 42 &&
|
||||
mlc->seidx != 43)
|
||||
printk(KERN_DEBUG PREFIX " + ");
|
||||
if (mlc->seidx != 41 &&
|
||||
mlc->seidx != 42 &&
|
||||
mlc->seidx != 43)
|
||||
printk(KERN_DEBUG PREFIX " + ");
|
||||
#endif
|
||||
};
|
||||
}
|
||||
}
|
||||
read_unlock(&hil_mlcs_lock);
|
||||
}
|
||||
|
||||
/************************* Keepalive timer task *********************/
|
||||
|
||||
void hil_mlcs_timer (unsigned long data) {
|
||||
void hil_mlcs_timer(unsigned long data)
|
||||
{
|
||||
hil_mlcs_probe = 1;
|
||||
tasklet_schedule(&hil_mlcs_tasklet);
|
||||
/* Re-insert the periodic task. */
|
||||
|
@ -724,28 +795,25 @@ void hil_mlcs_timer (unsigned long data) {
|
|||
|
||||
/******************** 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 *mlc;
|
||||
struct serio_driver *drv;
|
||||
uint8_t *idx, *last;
|
||||
|
||||
map = serio->port_data;
|
||||
if (map == NULL) {
|
||||
BUG();
|
||||
return -EIO;
|
||||
}
|
||||
BUG_ON(map == NULL);
|
||||
|
||||
mlc = map->mlc;
|
||||
if (mlc == NULL) {
|
||||
BUG();
|
||||
return -EIO;
|
||||
}
|
||||
mlc->serio_opacket[map->didx] |=
|
||||
BUG_ON(mlc == NULL);
|
||||
|
||||
mlc->serio_opacket[map->didx] |=
|
||||
((hil_packet)c) << (8 * (3 - mlc->serio_oidx[map->didx]));
|
||||
|
||||
if (mlc->serio_oidx[map->didx] >= 3) {
|
||||
/* for now only commands */
|
||||
if (!(mlc->serio_opacket[map->didx] & HIL_PKT_CMD))
|
||||
if (!(mlc->serio_opacket[map->didx] & HIL_PKT_CMD))
|
||||
return -EIO;
|
||||
switch (mlc->serio_opacket[map->didx] & HIL_PKT_DATA_MASK) {
|
||||
case HIL_CMD_IDD:
|
||||
|
@ -771,12 +839,11 @@ static int hil_mlc_serio_write(struct serio *serio, unsigned char c) {
|
|||
return -EIO;
|
||||
emu:
|
||||
drv = serio->drv;
|
||||
if (drv == NULL) {
|
||||
BUG();
|
||||
return -EIO;
|
||||
}
|
||||
BUG_ON(drv == NULL);
|
||||
|
||||
last = idx + 15;
|
||||
while ((last != idx) && (*last == 0)) last--;
|
||||
while ((last != idx) && (*last == 0))
|
||||
last--;
|
||||
|
||||
while (idx != last) {
|
||||
drv->interrupt(serio, 0, 0);
|
||||
|
@ -789,14 +856,15 @@ static int hil_mlc_serio_write(struct serio *serio, unsigned char c) {
|
|||
drv->interrupt(serio, HIL_ERR_INT >> 16, 0);
|
||||
drv->interrupt(serio, HIL_PKT_CMD >> 8, 0);
|
||||
drv->interrupt(serio, *idx, 0);
|
||||
|
||||
|
||||
mlc->serio_oidx[map->didx] = 0;
|
||||
mlc->serio_opacket[map->didx] = 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 *mlc;
|
||||
|
||||
|
@ -804,67 +872,57 @@ static int hil_mlc_serio_open(struct serio *serio) {
|
|||
return -EBUSY;
|
||||
|
||||
map = serio->port_data;
|
||||
if (map == NULL) {
|
||||
BUG();
|
||||
return -ENODEV;
|
||||
}
|
||||
BUG_ON(map == NULL);
|
||||
|
||||
mlc = map->mlc;
|
||||
if (mlc == NULL) {
|
||||
BUG();
|
||||
return -ENODEV;
|
||||
}
|
||||
BUG_ON(mlc == NULL);
|
||||
|
||||
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 *mlc;
|
||||
|
||||
map = serio->port_data;
|
||||
if (map == NULL) {
|
||||
BUG();
|
||||
return;
|
||||
}
|
||||
BUG_ON(map == NULL);
|
||||
|
||||
mlc = map->mlc;
|
||||
if (mlc == NULL) {
|
||||
BUG();
|
||||
return;
|
||||
}
|
||||
BUG_ON(mlc == NULL);
|
||||
|
||||
serio_set_drvdata(serio, NULL);
|
||||
serio->drv = NULL;
|
||||
/* 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,
|
||||
.proto = SERIO_HIL,
|
||||
.extra = SERIO_ANY,
|
||||
.id = SERIO_ANY,
|
||||
};
|
||||
|
||||
int hil_mlc_register(hil_mlc *mlc) {
|
||||
int hil_mlc_register(hil_mlc *mlc)
|
||||
{
|
||||
int i;
|
||||
unsigned long flags;
|
||||
unsigned long flags;
|
||||
|
||||
if (mlc == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
BUG_ON(mlc == NULL);
|
||||
|
||||
mlc->istarted = 0;
|
||||
mlc->ostarted = 0;
|
||||
mlc->ostarted = 0;
|
||||
|
||||
rwlock_init(&mlc->lock);
|
||||
init_MUTEX(&(mlc->osem));
|
||||
rwlock_init(&mlc->lock);
|
||||
init_MUTEX(&mlc->osem);
|
||||
|
||||
init_MUTEX(&(mlc->isem));
|
||||
mlc->icount = -1;
|
||||
mlc->imatch = 0;
|
||||
init_MUTEX(&mlc->isem);
|
||||
mlc->icount = -1;
|
||||
mlc->imatch = 0;
|
||||
|
||||
mlc->opercnt = 0;
|
||||
|
||||
init_MUTEX_LOCKED(&(mlc->csem));
|
||||
init_MUTEX_LOCKED(&(mlc->csem));
|
||||
|
||||
hil_mlc_clear_di_scratch(mlc);
|
||||
hil_mlc_clear_di_map(mlc, 0);
|
||||
|
@ -873,6 +931,8 @@ int hil_mlc_register(hil_mlc *mlc) {
|
|||
hil_mlc_copy_di_scratch(mlc, i);
|
||||
mlc_serio = kzalloc(sizeof(*mlc_serio), GFP_KERNEL);
|
||||
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->write = hil_mlc_serio_write;
|
||||
mlc_serio->open = hil_mlc_serio_open;
|
||||
|
@ -897,19 +957,18 @@ int hil_mlc_register(hil_mlc *mlc) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int hil_mlc_unregister(hil_mlc *mlc) {
|
||||
int hil_mlc_unregister(hil_mlc *mlc)
|
||||
{
|
||||
struct list_head *tmp;
|
||||
unsigned long flags;
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
if (mlc == NULL)
|
||||
return -EINVAL;
|
||||
BUG_ON(mlc == NULL);
|
||||
|
||||
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)
|
||||
goto found;
|
||||
}
|
||||
|
||||
/* not found in list */
|
||||
write_unlock_irqrestore(&hil_mlcs_lock, flags);
|
||||
|
@ -918,7 +977,7 @@ int hil_mlc_unregister(hil_mlc *mlc) {
|
|||
|
||||
found:
|
||||
list_del(tmp);
|
||||
write_unlock_irqrestore(&hil_mlcs_lock, flags);
|
||||
write_unlock_irqrestore(&hil_mlcs_lock, flags);
|
||||
|
||||
for (i = 0; i < HIL_MLC_DEVMEM; i++) {
|
||||
serio_unregister_port(mlc->serio[i]);
|
||||
|
@ -942,7 +1001,7 @@ static int __init hil_mlc_init(void)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void __exit hil_mlc_exit(void)
|
||||
{
|
||||
del_timer(&hil_mlcs_kicker);
|
||||
|
@ -950,6 +1009,6 @@ static void __exit hil_mlc_exit(void)
|
|||
tasklet_disable(&hil_mlcs_tasklet);
|
||||
tasklet_kill(&hil_mlcs_tasklet);
|
||||
}
|
||||
|
||||
|
||||
module_init(hil_mlc_init);
|
||||
module_exit(hil_mlc_exit);
|
||||
|
|
|
@ -34,27 +34,27 @@
|
|||
*
|
||||
* Driver theory of operation:
|
||||
*
|
||||
* hp_sdc_put does all writing to the SDC. ISR can run on a different
|
||||
* CPU than hp_sdc_put, but only one CPU runs hp_sdc_put at a time
|
||||
* hp_sdc_put does all writing to the SDC. ISR can run on a different
|
||||
* CPU than hp_sdc_put, but only one CPU runs hp_sdc_put at a time
|
||||
* (it cannot really benefit from SMP anyway.) A tasket fit this perfectly.
|
||||
*
|
||||
* All data coming back from the SDC is sent via interrupt and can be read
|
||||
* fully in the ISR, so there are no latency/throughput problems there.
|
||||
* The problem is with output, due to the slow clock speed of the SDC
|
||||
* compared to the CPU. This should not be too horrible most of the time,
|
||||
* but if used with HIL devices that support the multibyte transfer command,
|
||||
* keeping outbound throughput flowing at the 6500KBps that the HIL is
|
||||
* All data coming back from the SDC is sent via interrupt and can be read
|
||||
* fully in the ISR, so there are no latency/throughput problems there.
|
||||
* The problem is with output, due to the slow clock speed of the SDC
|
||||
* compared to the CPU. This should not be too horrible most of the time,
|
||||
* but if used with HIL devices that support the multibyte transfer command,
|
||||
* keeping outbound throughput flowing at the 6500KBps that the HIL is
|
||||
* capable of is more than can be done at HZ=100.
|
||||
*
|
||||
* Busy polling for IBF clear wastes CPU cycles and bus cycles. hp_sdc.ibf
|
||||
* is set to 0 when the IBF flag in the status register has cleared. ISR
|
||||
* may do this, and may also access the parts of queued transactions related
|
||||
* to reading data back from the SDC, but otherwise will not touch the
|
||||
* Busy polling for IBF clear wastes CPU cycles and bus cycles. hp_sdc.ibf
|
||||
* is set to 0 when the IBF flag in the status register has cleared. ISR
|
||||
* may do this, and may also access the parts of queued transactions related
|
||||
* to reading data back from the SDC, but otherwise will not touch the
|
||||
* hp_sdc state. Whenever a register is written hp_sdc.ibf is set to 1.
|
||||
*
|
||||
* The i8042 write index and the values in the 4-byte input buffer
|
||||
* starting at 0x70 are kept track of in hp_sdc.wi, and .r7[], respectively,
|
||||
* to minimize the amount of IO needed to the SDC. However these values
|
||||
* to minimize the amount of IO needed to the SDC. However these values
|
||||
* do not need to be locked since they are only ever accessed by hp_sdc_put.
|
||||
*
|
||||
* A timer task schedules the tasklet once per second just to make
|
||||
|
@ -100,39 +100,46 @@ EXPORT_SYMBOL(hp_sdc_release_timer_irq);
|
|||
EXPORT_SYMBOL(hp_sdc_release_hil_irq);
|
||||
EXPORT_SYMBOL(hp_sdc_release_cooked_irq);
|
||||
|
||||
EXPORT_SYMBOL(__hp_sdc_enqueue_transaction);
|
||||
EXPORT_SYMBOL(hp_sdc_enqueue_transaction);
|
||||
EXPORT_SYMBOL(hp_sdc_dequeue_transaction);
|
||||
|
||||
static hp_i8042_sdc hp_sdc; /* All driver state is kept in here. */
|
||||
|
||||
/*************** 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;
|
||||
unsigned long flags;
|
||||
|
||||
write_lock_irqsave(&hp_sdc.ibf_lock, flags);
|
||||
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);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static inline uint8_t hp_sdc_data_in8 (void) {
|
||||
return sdc_readb(hp_sdc.data_io);
|
||||
static inline uint8_t hp_sdc_data_in8(void)
|
||||
{
|
||||
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;
|
||||
|
||||
write_lock_irqsave(&hp_sdc.ibf_lock, flags);
|
||||
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);
|
||||
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;
|
||||
|
||||
write_lock_irqsave(&hp_sdc.ibf_lock, flags);
|
||||
|
@ -141,11 +148,12 @@ static inline void hp_sdc_data_out8 (uint8_t val) {
|
|||
write_unlock_irqrestore(&hp_sdc.ibf_lock, flags);
|
||||
}
|
||||
|
||||
/* Care must be taken to only invoke hp_sdc_spin_ibf when
|
||||
* absolutely needed, or in rarely invoked subroutines.
|
||||
* Not only does it waste CPU cycles, it also wastes bus cycles.
|
||||
/* Care must be taken to only invoke hp_sdc_spin_ibf when
|
||||
* absolutely needed, or in rarely invoked subroutines.
|
||||
* 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;
|
||||
rwlock_t *lock;
|
||||
|
||||
|
@ -158,19 +166,21 @@ static inline void hp_sdc_spin_ibf(void) {
|
|||
}
|
||||
read_unlock(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;
|
||||
write_unlock_irqrestore(lock, flags);
|
||||
}
|
||||
|
||||
|
||||
/************************ 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;
|
||||
|
||||
read_lock(&hp_sdc.rtq_lock);
|
||||
if (hp_sdc.rcurr < 0) {
|
||||
read_unlock(&hp_sdc.rtq_lock);
|
||||
read_unlock(&hp_sdc.rtq_lock);
|
||||
return;
|
||||
}
|
||||
curr = hp_sdc.tq[hp_sdc.rcurr];
|
||||
|
@ -183,25 +193,27 @@ static void hp_sdc_take (int irq, void *dev_id, uint8_t status, uint8_t data) {
|
|||
|
||||
if (hp_sdc.rqty <= 0) {
|
||||
/* All data has been gathered. */
|
||||
if(curr->seq[curr->actidx] & HP_SDC_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_SEMAPHORE)
|
||||
if (curr->act.semaphore)
|
||||
up(curr->act.semaphore);
|
||||
|
||||
if (curr->seq[curr->actidx] & HP_SDC_ACT_CALLBACK)
|
||||
if (curr->act.irqhook)
|
||||
curr->act.irqhook(irq, dev_id, status, data);
|
||||
}
|
||||
|
||||
curr->actidx = curr->idx;
|
||||
curr->idx++;
|
||||
/* Return control of this transaction */
|
||||
write_lock(&hp_sdc.rtq_lock);
|
||||
hp_sdc.rcurr = -1;
|
||||
hp_sdc.rcurr = -1;
|
||||
hp_sdc.rqty = 0;
|
||||
write_unlock(&hp_sdc.rtq_lock);
|
||||
tasklet_schedule(&hp_sdc.task);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
status = hp_sdc_status_in8();
|
||||
|
@ -209,67 +221,74 @@ static irqreturn_t hp_sdc_isr(int irq, void *dev_id) {
|
|||
data = hp_sdc_data_in8();
|
||||
|
||||
/* For now we are ignoring these until we get the SDC to behave. */
|
||||
if (((status & 0xf1) == 0x51) && data == 0x82) {
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
if (((status & 0xf1) == 0x51) && data == 0x82)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
switch(status & HP_SDC_STATUS_IRQMASK) {
|
||||
case 0: /* This case is not documented. */
|
||||
switch (status & HP_SDC_STATUS_IRQMASK) {
|
||||
case 0: /* This case is not documented. */
|
||||
break;
|
||||
case HP_SDC_STATUS_USERTIMER:
|
||||
case HP_SDC_STATUS_PERIODIC:
|
||||
case HP_SDC_STATUS_TIMER:
|
||||
|
||||
case HP_SDC_STATUS_USERTIMER:
|
||||
case HP_SDC_STATUS_PERIODIC:
|
||||
case HP_SDC_STATUS_TIMER:
|
||||
read_lock(&hp_sdc.hook_lock);
|
||||
if (hp_sdc.timer != NULL)
|
||||
if (hp_sdc.timer != NULL)
|
||||
hp_sdc.timer(irq, dev_id, status, data);
|
||||
read_unlock(&hp_sdc.hook_lock);
|
||||
break;
|
||||
case HP_SDC_STATUS_REG:
|
||||
|
||||
case HP_SDC_STATUS_REG:
|
||||
hp_sdc_take(irq, dev_id, status, data);
|
||||
break;
|
||||
case HP_SDC_STATUS_HILCMD:
|
||||
case HP_SDC_STATUS_HILDATA:
|
||||
|
||||
case HP_SDC_STATUS_HILCMD:
|
||||
case HP_SDC_STATUS_HILDATA:
|
||||
read_lock(&hp_sdc.hook_lock);
|
||||
if (hp_sdc.hil != NULL)
|
||||
hp_sdc.hil(irq, dev_id, status, data);
|
||||
read_unlock(&hp_sdc.hook_lock);
|
||||
break;
|
||||
case HP_SDC_STATUS_PUP:
|
||||
|
||||
case HP_SDC_STATUS_PUP:
|
||||
read_lock(&hp_sdc.hook_lock);
|
||||
if (hp_sdc.pup != NULL)
|
||||
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);
|
||||
break;
|
||||
default:
|
||||
|
||||
default:
|
||||
read_lock(&hp_sdc.hook_lock);
|
||||
if (hp_sdc.cooked != NULL)
|
||||
hp_sdc.cooked(irq, dev_id, status, data);
|
||||
read_unlock(&hp_sdc.hook_lock);
|
||||
break;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
||||
status = hp_sdc_status_in8();
|
||||
printk(KERN_WARNING PREFIX "NMI !\n");
|
||||
|
||||
#if 0
|
||||
#if 0
|
||||
if (status & HP_SDC_NMISTATUS_FHS) {
|
||||
read_lock(&hp_sdc.hook_lock);
|
||||
if (hp_sdc.timer != NULL)
|
||||
if (hp_sdc.timer != NULL)
|
||||
hp_sdc.timer(irq, dev_id, status, 0);
|
||||
read_unlock(&hp_sdc.hook_lock);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
/* TODO: pass this on to the HIL handler, or do SAK here? */
|
||||
printk(KERN_WARNING PREFIX "HIL NMI\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
@ -278,13 +297,17 @@ static irqreturn_t hp_sdc_nmisr(int irq, void *dev_id) {
|
|||
|
||||
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);
|
||||
|
||||
if (hp_sdc.rcurr >= 0) {
|
||||
struct timeval 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) {
|
||||
hp_sdc_transaction *curr;
|
||||
uint8_t tmp;
|
||||
|
@ -300,27 +323,29 @@ static void hp_sdc_tasklet(unsigned long foo) {
|
|||
hp_sdc.rqty = 0;
|
||||
tmp = curr->seq[curr->actidx];
|
||||
curr->seq[curr->actidx] |= HP_SDC_ACT_DEAD;
|
||||
if(tmp & HP_SDC_ACT_SEMAPHORE) {
|
||||
if (curr->act.semaphore)
|
||||
if (tmp & HP_SDC_ACT_SEMAPHORE)
|
||||
if (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
|
||||
* in tasklet/bh context.
|
||||
*/
|
||||
if (curr->act.irqhook)
|
||||
if (curr->act.irqhook)
|
||||
curr->act.irqhook(0, NULL, 0, 0);
|
||||
}
|
||||
|
||||
curr->actidx = curr->idx;
|
||||
curr->idx++;
|
||||
hp_sdc.rcurr = -1;
|
||||
hp_sdc.rcurr = -1;
|
||||
}
|
||||
}
|
||||
write_unlock_irq(&hp_sdc.rtq_lock);
|
||||
hp_sdc_put();
|
||||
}
|
||||
|
||||
unsigned long hp_sdc_put(void) {
|
||||
unsigned long hp_sdc_put(void)
|
||||
{
|
||||
hp_sdc_transaction *curr;
|
||||
uint8_t act;
|
||||
int idx, curridx;
|
||||
|
@ -333,19 +358,24 @@ unsigned long hp_sdc_put(void) {
|
|||
requires output, so we skip to the administrativa. */
|
||||
if (hp_sdc.ibf) {
|
||||
hp_sdc_status_in8();
|
||||
if (hp_sdc.ibf) goto finish;
|
||||
if (hp_sdc.ibf)
|
||||
goto finish;
|
||||
}
|
||||
|
||||
anew:
|
||||
/* 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);
|
||||
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);
|
||||
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;
|
||||
|
||||
if (hp_sdc.tq[curridx] != NULL) goto start;
|
||||
if (hp_sdc.tq[curridx] != NULL)
|
||||
goto start;
|
||||
|
||||
while (++curridx != hp_sdc.wcurr) {
|
||||
if (curridx >= HP_SDC_QUEUE_LEN) {
|
||||
|
@ -358,7 +388,8 @@ unsigned long hp_sdc_put(void) {
|
|||
continue;
|
||||
}
|
||||
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. */
|
||||
curridx = -1;
|
||||
|
@ -374,7 +405,8 @@ unsigned long hp_sdc_put(void) {
|
|||
goto finish;
|
||||
}
|
||||
|
||||
if (hp_sdc.wcurr == -1) goto done;
|
||||
if (hp_sdc.wcurr == -1)
|
||||
goto done;
|
||||
|
||||
curr = hp_sdc.tq[curridx];
|
||||
idx = curr->actidx;
|
||||
|
@ -383,20 +415,23 @@ unsigned long hp_sdc_put(void) {
|
|||
hp_sdc.tq[curridx] = NULL;
|
||||
/* Interleave outbound data between the transactions. */
|
||||
hp_sdc.wcurr++;
|
||||
if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN) hp_sdc.wcurr = 0;
|
||||
goto finish;
|
||||
if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN)
|
||||
hp_sdc.wcurr = 0;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
act = curr->seq[idx];
|
||||
idx++;
|
||||
|
||||
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;
|
||||
/* Interleave outbound data between the transactions. */
|
||||
hp_sdc.wcurr++;
|
||||
if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN) hp_sdc.wcurr = 0;
|
||||
goto finish;
|
||||
if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN)
|
||||
hp_sdc.wcurr = 0;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
while (act & HP_SDC_ACT_PRECMD) {
|
||||
|
@ -409,9 +444,10 @@ unsigned long hp_sdc_put(void) {
|
|||
curr->idx++;
|
||||
/* act finished? */
|
||||
if ((act & HP_SDC_ACT_DURING) == HP_SDC_ACT_PRECMD)
|
||||
goto actdone;
|
||||
goto actdone;
|
||||
/* 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;
|
||||
}
|
||||
if (act & HP_SDC_ACT_DATAOUT) {
|
||||
|
@ -423,15 +459,15 @@ unsigned long hp_sdc_put(void) {
|
|||
hp_sdc_data_out8(curr->seq[curr->idx]);
|
||||
curr->idx++;
|
||||
/* act finished? */
|
||||
if ((curr->idx - idx >= qty) &&
|
||||
((act & HP_SDC_ACT_DURING) == HP_SDC_ACT_DATAOUT))
|
||||
if (curr->idx - idx >= qty &&
|
||||
(act & HP_SDC_ACT_DURING) == HP_SDC_ACT_DATAOUT)
|
||||
goto actdone;
|
||||
goto finish;
|
||||
}
|
||||
idx += qty;
|
||||
act &= ~HP_SDC_ACT_DATAOUT;
|
||||
}
|
||||
else while (act & HP_SDC_ACT_DATAREG) {
|
||||
} else
|
||||
while (act & HP_SDC_ACT_DATAREG) {
|
||||
int mask;
|
||||
uint8_t w7[4];
|
||||
|
||||
|
@ -445,26 +481,30 @@ unsigned long hp_sdc_put(void) {
|
|||
act &= ~HP_SDC_ACT_DATAREG;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
w7[0] = (mask & 1) ? curr->seq[++idx] : hp_sdc.r7[0];
|
||||
w7[1] = (mask & 2) ? curr->seq[++idx] : hp_sdc.r7[1];
|
||||
w7[2] = (mask & 4) ? curr->seq[++idx] : hp_sdc.r7[2];
|
||||
w7[3] = (mask & 8) ? curr->seq[++idx] : hp_sdc.r7[3];
|
||||
|
||||
|
||||
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;
|
||||
|
||||
/* Need to point the write index register */
|
||||
while ((i < 4) && w7[i] == hp_sdc.r7[i]) i++;
|
||||
/* Need to point the write index register */
|
||||
while (i < 4 && w7[i] == hp_sdc.r7[i])
|
||||
i++;
|
||||
|
||||
if (i < 4) {
|
||||
hp_sdc_status_out8(HP_SDC_CMD_SET_D0 + i);
|
||||
hp_sdc.wi = 0x70 + i;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
idx++;
|
||||
if ((act & HP_SDC_ACT_DURING) == HP_SDC_ACT_DATAREG)
|
||||
goto actdone;
|
||||
|
||||
curr->idx = idx;
|
||||
act &= ~HP_SDC_ACT_DATAREG;
|
||||
break;
|
||||
|
@ -476,12 +516,13 @@ unsigned long hp_sdc_put(void) {
|
|||
{
|
||||
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) {
|
||||
curr->idx = idx + 1;
|
||||
if ((act & HP_SDC_ACT_DURING) ==
|
||||
if ((act & HP_SDC_ACT_DURING) ==
|
||||
HP_SDC_ACT_DATAREG)
|
||||
goto actdone;
|
||||
goto actdone;
|
||||
}
|
||||
}
|
||||
goto finish;
|
||||
|
@ -497,7 +538,7 @@ unsigned long hp_sdc_put(void) {
|
|||
|
||||
|
||||
if (act & HP_SDC_ACT_POSTCMD) {
|
||||
uint8_t postcmd;
|
||||
uint8_t postcmd;
|
||||
|
||||
/* curr->idx should == idx at this point. */
|
||||
postcmd = curr->seq[idx];
|
||||
|
@ -505,12 +546,12 @@ unsigned long hp_sdc_put(void) {
|
|||
if (act & HP_SDC_ACT_DATAIN) {
|
||||
|
||||
/* Start a new read */
|
||||
hp_sdc.rqty = curr->seq[curr->idx];
|
||||
hp_sdc.rqty = curr->seq[curr->idx];
|
||||
do_gettimeofday(&hp_sdc.rtv);
|
||||
curr->idx++;
|
||||
/* Still need to lock here in case of spurious irq. */
|
||||
write_lock_irq(&hp_sdc.rtq_lock);
|
||||
hp_sdc.rcurr = curridx;
|
||||
hp_sdc.rcurr = curridx;
|
||||
write_unlock_irq(&hp_sdc.rtq_lock);
|
||||
hp_sdc_status_out8(postcmd);
|
||||
goto finish;
|
||||
|
@ -519,75 +560,86 @@ unsigned long hp_sdc_put(void) {
|
|||
goto actdone;
|
||||
}
|
||||
|
||||
actdone:
|
||||
if (act & HP_SDC_ACT_SEMAPHORE) {
|
||||
actdone:
|
||||
if (act & HP_SDC_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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
curr->actidx = idx + 1;
|
||||
curr->idx = idx + 2;
|
||||
}
|
||||
/* Interleave outbound data between the transactions. */
|
||||
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:
|
||||
/* 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. */
|
||||
if (!hp_sdc.ibf && limit++ < 20) goto anew;
|
||||
if (!hp_sdc.ibf && limit++ < 20)
|
||||
goto anew;
|
||||
|
||||
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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******* Functions called in either user or kernel context ****/
|
||||
int hp_sdc_enqueue_transaction(hp_sdc_transaction *this) {
|
||||
unsigned long flags;
|
||||
int __hp_sdc_enqueue_transaction(hp_sdc_transaction *this)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (this == NULL) {
|
||||
tasklet_schedule(&hp_sdc.task);
|
||||
BUG();
|
||||
return -EINVAL;
|
||||
};
|
||||
|
||||
write_lock_irqsave(&hp_sdc.lock, flags);
|
||||
}
|
||||
|
||||
/* Can't have same transaction on queue twice */
|
||||
for (i=0; i < HP_SDC_QUEUE_LEN; i++)
|
||||
if (hp_sdc.tq[i] == this) goto fail;
|
||||
for (i = 0; i < HP_SDC_QUEUE_LEN; i++)
|
||||
if (hp_sdc.tq[i] == this)
|
||||
goto fail;
|
||||
|
||||
this->actidx = 0;
|
||||
this->idx = 1;
|
||||
|
||||
/* 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) {
|
||||
hp_sdc.tq[i] = this;
|
||||
write_unlock_irqrestore(&hp_sdc.lock, flags);
|
||||
tasklet_schedule(&hp_sdc.task);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
write_unlock_irqrestore(&hp_sdc.lock, flags);
|
||||
|
||||
printk(KERN_WARNING PREFIX "No free slot to add transaction.\n");
|
||||
return -EBUSY;
|
||||
|
||||
fail:
|
||||
write_unlock_irqrestore(&hp_sdc.lock,flags);
|
||||
printk(KERN_WARNING PREFIX "Transaction add failed: transaction already queued?\n");
|
||||
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;
|
||||
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. */
|
||||
|
||||
for (i=0; i < HP_SDC_QUEUE_LEN; i++)
|
||||
if (hp_sdc.tq[i] == this) hp_sdc.tq[i] = NULL;
|
||||
for (i = 0; i < HP_SDC_QUEUE_LEN; i++)
|
||||
if (hp_sdc.tq[i] == this)
|
||||
hp_sdc.tq[i] = NULL;
|
||||
|
||||
write_unlock_irqrestore(&hp_sdc.lock, flags);
|
||||
return 0;
|
||||
|
@ -605,11 +658,11 @@ int hp_sdc_dequeue_transaction(hp_sdc_transaction *this) {
|
|||
|
||||
|
||||
/********************** User context functions **************************/
|
||||
int hp_sdc_request_timer_irq(hp_sdc_irqhook *callback) {
|
||||
|
||||
if (callback == NULL || hp_sdc.dev == NULL) {
|
||||
int hp_sdc_request_timer_irq(hp_sdc_irqhook *callback)
|
||||
{
|
||||
if (callback == NULL || hp_sdc.dev == NULL)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
write_lock_irq(&hp_sdc.hook_lock);
|
||||
if (hp_sdc.timer != NULL) {
|
||||
write_unlock_irq(&hp_sdc.hook_lock);
|
||||
|
@ -629,11 +682,11 @@ int hp_sdc_request_timer_irq(hp_sdc_irqhook *callback) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int hp_sdc_request_hil_irq(hp_sdc_irqhook *callback) {
|
||||
|
||||
if (callback == NULL || hp_sdc.dev == NULL) {
|
||||
int hp_sdc_request_hil_irq(hp_sdc_irqhook *callback)
|
||||
{
|
||||
if (callback == NULL || hp_sdc.dev == NULL)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
write_lock_irq(&hp_sdc.hook_lock);
|
||||
if (hp_sdc.hil != NULL) {
|
||||
write_unlock_irq(&hp_sdc.hook_lock);
|
||||
|
@ -650,11 +703,11 @@ int hp_sdc_request_hil_irq(hp_sdc_irqhook *callback) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int hp_sdc_request_cooked_irq(hp_sdc_irqhook *callback) {
|
||||
|
||||
if (callback == NULL || hp_sdc.dev == NULL) {
|
||||
int hp_sdc_request_cooked_irq(hp_sdc_irqhook *callback)
|
||||
{
|
||||
if (callback == NULL || hp_sdc.dev == NULL)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
write_lock_irq(&hp_sdc.hook_lock);
|
||||
if (hp_sdc.cooked != NULL) {
|
||||
write_unlock_irq(&hp_sdc.hook_lock);
|
||||
|
@ -672,9 +725,8 @@ int hp_sdc_request_cooked_irq(hp_sdc_irqhook *callback) {
|
|||
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);
|
||||
if ((callback != hp_sdc.timer) ||
|
||||
(hp_sdc.timer == NULL)) {
|
||||
|
@ -694,8 +746,8 @@ int hp_sdc_release_timer_irq(hp_sdc_irqhook *callback) {
|
|||
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);
|
||||
if ((callback != hp_sdc.hil) ||
|
||||
(hp_sdc.hil == NULL)) {
|
||||
|
@ -715,8 +767,8 @@ int hp_sdc_release_hil_irq(hp_sdc_irqhook *callback) {
|
|||
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);
|
||||
if ((callback != hp_sdc.cooked) ||
|
||||
(hp_sdc.cooked == NULL)) {
|
||||
|
@ -738,7 +790,8 @@ int hp_sdc_release_cooked_irq(hp_sdc_irqhook *callback) {
|
|||
|
||||
/************************* Keepalive timer task *********************/
|
||||
|
||||
void hp_sdc_kicker (unsigned long data) {
|
||||
void hp_sdc_kicker (unsigned long data)
|
||||
{
|
||||
tasklet_schedule(&hp_sdc.task);
|
||||
/* Re-insert the periodic task. */
|
||||
mod_timer(&hp_sdc.kicker, jiffies + HZ);
|
||||
|
@ -748,12 +801,12 @@ void hp_sdc_kicker (unsigned long data) {
|
|||
|
||||
#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 = HVERSION_ANY_ID,
|
||||
.sversion = 0x73,
|
||||
.sversion = 0x73,
|
||||
},
|
||||
{ 0, }
|
||||
};
|
||||
|
@ -772,16 +825,15 @@ static struct parisc_driver hp_sdc_driver = {
|
|||
|
||||
static int __init hp_sdc_init(void)
|
||||
{
|
||||
int i;
|
||||
char *errstr;
|
||||
hp_sdc_transaction t_sync;
|
||||
uint8_t ts_sync[6];
|
||||
struct semaphore s_sync;
|
||||
|
||||
rwlock_init(&hp_sdc.lock);
|
||||
rwlock_init(&hp_sdc.ibf_lock);
|
||||
rwlock_init(&hp_sdc.rtq_lock);
|
||||
rwlock_init(&hp_sdc.hook_lock);
|
||||
rwlock_init(&hp_sdc.lock);
|
||||
rwlock_init(&hp_sdc.ibf_lock);
|
||||
rwlock_init(&hp_sdc.rtq_lock);
|
||||
rwlock_init(&hp_sdc.hook_lock);
|
||||
|
||||
hp_sdc.timer = NULL;
|
||||
hp_sdc.hil = NULL;
|
||||
|
@ -796,7 +848,8 @@ static int __init hp_sdc_init(void)
|
|||
hp_sdc.r7[3] = 0xff;
|
||||
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.rcurr = -1;
|
||||
hp_sdc.rqty = 0;
|
||||
|
@ -804,27 +857,32 @@ static int __init hp_sdc_init(void)
|
|||
hp_sdc.dev_err = -ENODEV;
|
||||
|
||||
errstr = "IO not found for";
|
||||
if (!hp_sdc.base_io) goto err0;
|
||||
if (!hp_sdc.base_io)
|
||||
goto err0;
|
||||
|
||||
errstr = "IRQ not found for";
|
||||
if (!hp_sdc.irq) goto err0;
|
||||
if (!hp_sdc.irq)
|
||||
goto err0;
|
||||
|
||||
hp_sdc.dev_err = -EBUSY;
|
||||
|
||||
#if defined(__hppa__)
|
||||
errstr = "IO not available for";
|
||||
if (request_region(hp_sdc.data_io, 2, hp_sdc_driver.name)) goto err0;
|
||||
#endif
|
||||
if (request_region(hp_sdc.data_io, 2, hp_sdc_driver.name))
|
||||
goto err0;
|
||||
#endif
|
||||
|
||||
errstr = "IRQ not available for";
|
||||
if(request_irq(hp_sdc.irq, &hp_sdc_isr, 0, "HP SDC",
|
||||
(void *) hp_sdc.base_io)) goto err1;
|
||||
if (request_irq(hp_sdc.irq, &hp_sdc_isr, IRQF_SHARED|IRQF_SAMPLE_RANDOM,
|
||||
"HP SDC", &hp_sdc))
|
||||
goto err1;
|
||||
|
||||
errstr = "NMI not available for";
|
||||
if (request_irq(hp_sdc.nmi, &hp_sdc_nmisr, 0, "HP SDC NMI",
|
||||
(void *) hp_sdc.base_io)) goto err2;
|
||||
if (request_irq(hp_sdc.nmi, &hp_sdc_nmisr, IRQF_SHARED,
|
||||
"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);
|
||||
|
||||
hp_sdc_status_in8();
|
||||
|
@ -854,13 +912,14 @@ static int __init hp_sdc_init(void)
|
|||
hp_sdc.dev_err = 0;
|
||||
return 0;
|
||||
err2:
|
||||
free_irq(hp_sdc.irq, NULL);
|
||||
free_irq(hp_sdc.irq, &hp_sdc);
|
||||
err1:
|
||||
release_region(hp_sdc.data_io, 2);
|
||||
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);
|
||||
hp_sdc.dev = NULL;
|
||||
|
||||
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)
|
||||
{
|
||||
if (!d) return 1;
|
||||
if (hp_sdc.dev != NULL) return 1; /* We only expect one SDC */
|
||||
if (!d)
|
||||
return 1;
|
||||
if (hp_sdc.dev != NULL)
|
||||
return 1; /* We only expect one SDC */
|
||||
|
||||
hp_sdc.dev = d;
|
||||
hp_sdc.irq = d->irq;
|
||||
|
@ -898,18 +959,16 @@ static void hp_sdc_exit(void)
|
|||
/* Wait until we know this has been processed by the i8042 */
|
||||
hp_sdc_spin_ibf();
|
||||
|
||||
free_irq(hp_sdc.nmi, NULL);
|
||||
free_irq(hp_sdc.irq, NULL);
|
||||
free_irq(hp_sdc.nmi, &hp_sdc);
|
||||
free_irq(hp_sdc.irq, &hp_sdc);
|
||||
write_unlock_irq(&hp_sdc.lock);
|
||||
|
||||
del_timer(&hp_sdc.kicker);
|
||||
|
||||
tasklet_kill(&hp_sdc.task);
|
||||
|
||||
/* release_region(hp_sdc.data_io, 2); */
|
||||
|
||||
#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");
|
||||
#endif
|
||||
}
|
||||
|
@ -923,7 +982,7 @@ static int __init hp_sdc_register(void)
|
|||
mm_segment_t fs;
|
||||
unsigned char i;
|
||||
#endif
|
||||
|
||||
|
||||
hp_sdc.dev = NULL;
|
||||
hp_sdc.dev_err = 0;
|
||||
#if defined(__hppa__)
|
||||
|
@ -960,8 +1019,8 @@ static int __init hp_sdc_register(void)
|
|||
tq_init.seq = tq_init_seq;
|
||||
tq_init.act.semaphore = &tq_init_sem;
|
||||
|
||||
tq_init_seq[0] =
|
||||
HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN | HP_SDC_ACT_SEMAPHORE;
|
||||
tq_init_seq[0] =
|
||||
HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN | HP_SDC_ACT_SEMAPHORE;
|
||||
tq_init_seq[1] = HP_SDC_CMD_READ_KCC;
|
||||
tq_init_seq[2] = 1;
|
||||
tq_init_seq[3] = 0;
|
||||
|
@ -979,13 +1038,13 @@ static int __init hp_sdc_register(void)
|
|||
}
|
||||
hp_sdc.r11 = tq_init_seq[4];
|
||||
if (hp_sdc.r11 & HP_SDC_CFG_NEW) {
|
||||
char *str;
|
||||
const char *str;
|
||||
printk(KERN_INFO PREFIX "New style SDC\n");
|
||||
tq_init_seq[1] = HP_SDC_CMD_READ_XTD;
|
||||
tq_init.actidx = 0;
|
||||
tq_init.idx = 1;
|
||||
down(&tq_init_sem);
|
||||
hp_sdc_enqueue_transaction(&tq_init);
|
||||
hp_sdc_enqueue_transaction(&tq_init);
|
||||
down(&tq_init_sem);
|
||||
up(&tq_init_sem);
|
||||
if ((tq_init_seq[0] & HP_SDC_ACT_DEAD) == HP_SDC_ACT_DEAD) {
|
||||
|
@ -995,15 +1054,13 @@ static int __init hp_sdc_register(void)
|
|||
hp_sdc.r7e = tq_init_seq[4];
|
||||
HP_SDC_XTD_REV_STRINGS(hp_sdc.r7e & HP_SDC_XTD_REV, 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");
|
||||
}
|
||||
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 "Spunking the self test register to force PUP "
|
||||
"on next firmware reset.\n");
|
||||
tq_init_seq[0] = HP_SDC_ACT_PRECMD |
|
||||
tq_init_seq[0] = HP_SDC_ACT_PRECMD |
|
||||
HP_SDC_ACT_DATAOUT | HP_SDC_ACT_SEMAPHORE;
|
||||
tq_init_seq[1] = HP_SDC_CMD_SET_STR;
|
||||
tq_init_seq[2] = 1;
|
||||
|
@ -1012,14 +1069,12 @@ static int __init hp_sdc_register(void)
|
|||
tq_init.idx = 1;
|
||||
tq_init.endidx = 4;
|
||||
down(&tq_init_sem);
|
||||
hp_sdc_enqueue_transaction(&tq_init);
|
||||
hp_sdc_enqueue_transaction(&tq_init);
|
||||
down(&tq_init_sem);
|
||||
up(&tq_init_sem);
|
||||
}
|
||||
else {
|
||||
printk(KERN_INFO PREFIX "Old style SDC (1820-%s).\n",
|
||||
} else
|
||||
printk(KERN_INFO PREFIX "Old style SDC (1820-%s).\n",
|
||||
(hp_sdc.r11 & HP_SDC_CFG_REV) ? "3300" : "2564/3087");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1027,13 +1082,13 @@ static int __init hp_sdc_register(void)
|
|||
module_init(hp_sdc_register);
|
||||
module_exit(hp_sdc_exit);
|
||||
|
||||
/* Timing notes: These measurements taken on my 64MHz 7100-LC (715/64)
|
||||
/* Timing notes: These measurements taken on my 64MHz 7100-LC (715/64)
|
||||
* cycles cycles-adj time
|
||||
* between two consecutive mfctl(16)'s: 4 n/a 63ns
|
||||
* hp_sdc_spin_ibf when idle: 119 115 1.7us
|
||||
* gsc_writeb status register: 83 79 1.2us
|
||||
* IBF to clear after sending SET_IM: 6204 6006 93us
|
||||
* IBF to clear after sending LOAD_RT: 4467 4352 68us
|
||||
* IBF to clear after sending LOAD_RT: 4467 4352 68us
|
||||
* IBF to clear after sending two LOAD_RTs: 18974 18859 295us
|
||||
* READ_T1, read status/data, IRQ, call handler: 35564 n/a 556us
|
||||
* cmd to ~IBF READ_T1 2nd time right after: 5158403 n/a 81ms
|
||||
|
|
|
@ -58,12 +58,13 @@ struct hp_sdc_mlc_priv_s {
|
|||
} hp_sdc_mlc_priv;
|
||||
|
||||
/************************* Interrupt context ******************************/
|
||||
static void hp_sdc_mlc_isr (int irq, void *dev_id,
|
||||
uint8_t status, uint8_t data) {
|
||||
int idx;
|
||||
static void hp_sdc_mlc_isr (int irq, void *dev_id,
|
||||
uint8_t status, uint8_t data)
|
||||
{
|
||||
int idx;
|
||||
hil_mlc *mlc = &hp_sdc_mlc;
|
||||
|
||||
write_lock(&(mlc->lock));
|
||||
write_lock(&mlc->lock);
|
||||
if (mlc->icount < 0) {
|
||||
printk(KERN_WARNING PREFIX "HIL Overflow!\n");
|
||||
up(&mlc->isem);
|
||||
|
@ -73,239 +74,232 @@ static void hp_sdc_mlc_isr (int irq, void *dev_id,
|
|||
if ((status & HP_SDC_STATUS_IRQMASK) == HP_SDC_STATUS_HILDATA) {
|
||||
mlc->ipacket[idx] |= data | HIL_ERR_INT;
|
||||
mlc->icount--;
|
||||
if (hp_sdc_mlc_priv.got5x) goto check;
|
||||
if (!idx) goto check;
|
||||
if ((mlc->ipacket[idx-1] & HIL_PKT_ADDR_MASK) !=
|
||||
if (hp_sdc_mlc_priv.got5x || !idx)
|
||||
goto check;
|
||||
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] |= (mlc->ipacket[idx-1]
|
||||
& HIL_PKT_ADDR_MASK);
|
||||
mlc->ipacket[idx] |= (mlc->ipacket[idx - 1]
|
||||
& HIL_PKT_ADDR_MASK);
|
||||
}
|
||||
goto check;
|
||||
}
|
||||
/* We know status is 5X */
|
||||
if (data & HP_SDC_HIL_ISERR) goto err;
|
||||
mlc->ipacket[idx] =
|
||||
if (data & HP_SDC_HIL_ISERR)
|
||||
goto err;
|
||||
mlc->ipacket[idx] =
|
||||
(data & HP_SDC_HIL_R1MASK) << HIL_PKT_ADDR_SHIFT;
|
||||
hp_sdc_mlc_priv.got5x = 1;
|
||||
goto out;
|
||||
|
||||
check:
|
||||
hp_sdc_mlc_priv.got5x = 0;
|
||||
if (mlc->imatch == 0) goto done;
|
||||
if ((mlc->imatch == (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL))
|
||||
&& (mlc->ipacket[idx] == (mlc->imatch | idx))) goto done;
|
||||
if (mlc->ipacket[idx] == mlc->imatch) goto done;
|
||||
if (mlc->imatch == 0)
|
||||
goto done;
|
||||
if ((mlc->imatch == (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL))
|
||||
&& (mlc->ipacket[idx] == (mlc->imatch | idx)))
|
||||
goto done;
|
||||
if (mlc->ipacket[idx] == mlc->imatch)
|
||||
goto done;
|
||||
goto out;
|
||||
|
||||
err:
|
||||
err:
|
||||
printk(KERN_DEBUG PREFIX "err code %x\n", data);
|
||||
|
||||
switch (data) {
|
||||
case HP_SDC_HIL_RC_DONE:
|
||||
printk(KERN_WARNING PREFIX "Bastard SDC reconfigured loop!\n");
|
||||
break;
|
||||
|
||||
case HP_SDC_HIL_ERR:
|
||||
mlc->ipacket[idx] |= HIL_ERR_INT | HIL_ERR_PERR |
|
||||
HIL_ERR_FERR | HIL_ERR_FOF;
|
||||
mlc->ipacket[idx] |= HIL_ERR_INT | HIL_ERR_PERR |
|
||||
HIL_ERR_FERR | HIL_ERR_FOF;
|
||||
break;
|
||||
|
||||
case HP_SDC_HIL_TO:
|
||||
mlc->ipacket[idx] |= HIL_ERR_INT | HIL_ERR_LERR;
|
||||
break;
|
||||
|
||||
case HP_SDC_HIL_RC:
|
||||
printk(KERN_WARNING PREFIX "Bastard SDC decided to reconfigure loop!\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
printk(KERN_WARNING PREFIX "Unkown HIL Error status (%x)!\n", data);
|
||||
break;
|
||||
}
|
||||
|
||||
/* No more data will be coming due to an error. */
|
||||
done:
|
||||
tasklet_schedule(mlc->tasklet);
|
||||
up(&(mlc->isem));
|
||||
up(&mlc->isem);
|
||||
out:
|
||||
write_unlock(&(mlc->lock));
|
||||
write_unlock(&mlc->lock);
|
||||
}
|
||||
|
||||
|
||||
/******************** Tasklet or userspace context functions ****************/
|
||||
|
||||
static int hp_sdc_mlc_in (hil_mlc *mlc, suseconds_t timeout) {
|
||||
unsigned long flags;
|
||||
static int hp_sdc_mlc_in(hil_mlc *mlc, suseconds_t timeout)
|
||||
{
|
||||
struct hp_sdc_mlc_priv_s *priv;
|
||||
int rc = 2;
|
||||
|
||||
priv = mlc->priv;
|
||||
|
||||
write_lock_irqsave(&(mlc->lock), flags);
|
||||
|
||||
/* Try to down the semaphore */
|
||||
if (down_trylock(&(mlc->isem))) {
|
||||
if (down_trylock(&mlc->isem)) {
|
||||
struct timeval tv;
|
||||
if (priv->emtestmode) {
|
||||
mlc->ipacket[0] =
|
||||
HIL_ERR_INT | (mlc->opacket &
|
||||
(HIL_PKT_CMD |
|
||||
HIL_PKT_ADDR_MASK |
|
||||
mlc->ipacket[0] =
|
||||
HIL_ERR_INT | (mlc->opacket &
|
||||
(HIL_PKT_CMD |
|
||||
HIL_PKT_ADDR_MASK |
|
||||
HIL_PKT_DATA_MASK));
|
||||
mlc->icount = 14;
|
||||
/* printk(KERN_DEBUG PREFIX ">[%x]\n", mlc->ipacket[0]); */
|
||||
goto wasup;
|
||||
}
|
||||
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) {
|
||||
/* printk("!%i %i",
|
||||
tv.tv_usec - mlc->instart.tv_usec,
|
||||
mlc->intimeout);
|
||||
*/
|
||||
/* printk("!%i %i",
|
||||
tv.tv_usec - mlc->instart.tv_usec,
|
||||
mlc->intimeout);
|
||||
*/
|
||||
rc = 1;
|
||||
up(&(mlc->isem));
|
||||
up(&mlc->isem);
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
wasup:
|
||||
up(&(mlc->isem));
|
||||
up(&mlc->isem);
|
||||
rc = 0;
|
||||
goto done;
|
||||
done:
|
||||
write_unlock_irqrestore(&(mlc->lock), flags);
|
||||
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;
|
||||
unsigned long flags;
|
||||
|
||||
priv = mlc->priv;
|
||||
|
||||
write_lock_irqsave(&(mlc->lock), flags);
|
||||
priv = mlc->priv;
|
||||
|
||||
/* Try to down the semaphores -- they should be up. */
|
||||
if (down_trylock(&(mlc->isem))) {
|
||||
BUG();
|
||||
goto busy;
|
||||
}
|
||||
if (down_trylock(&(mlc->osem))) {
|
||||
BUG();
|
||||
up(&(mlc->isem));
|
||||
goto busy;
|
||||
}
|
||||
up(&(mlc->isem));
|
||||
up(&(mlc->osem));
|
||||
BUG_ON(down_trylock(&mlc->isem));
|
||||
BUG_ON(down_trylock(&mlc->osem));
|
||||
|
||||
if (down_trylock(&(mlc->csem))) {
|
||||
if (priv->trans.act.semaphore != &(mlc->csem)) goto poll;
|
||||
goto busy;
|
||||
up(&mlc->isem);
|
||||
up(&mlc->osem);
|
||||
|
||||
if (down_trylock(&mlc->csem)) {
|
||||
if (priv->trans.act.semaphore != &mlc->csem)
|
||||
goto poll;
|
||||
else
|
||||
goto busy;
|
||||
}
|
||||
if (!(priv->tseq[4] & HP_SDC_USE_LOOP)) goto done;
|
||||
|
||||
if (!(priv->tseq[4] & HP_SDC_USE_LOOP))
|
||||
goto done;
|
||||
|
||||
poll:
|
||||
priv->trans.act.semaphore = &(mlc->csem);
|
||||
priv->trans.act.semaphore = &mlc->csem;
|
||||
priv->trans.actidx = 0;
|
||||
priv->trans.idx = 1;
|
||||
priv->trans.endidx = 5;
|
||||
priv->tseq[0] =
|
||||
priv->tseq[0] =
|
||||
HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN | HP_SDC_ACT_SEMAPHORE;
|
||||
priv->tseq[1] = HP_SDC_CMD_READ_USE;
|
||||
priv->tseq[2] = 1;
|
||||
priv->tseq[3] = 0;
|
||||
priv->tseq[4] = 0;
|
||||
hp_sdc_enqueue_transaction(&(priv->trans));
|
||||
__hp_sdc_enqueue_transaction(&priv->trans);
|
||||
busy:
|
||||
write_unlock_irqrestore(&(mlc->lock), flags);
|
||||
return 1;
|
||||
done:
|
||||
priv->trans.act.semaphore = &(mlc->osem);
|
||||
up(&(mlc->csem));
|
||||
write_unlock_irqrestore(&(mlc->lock), flags);
|
||||
priv->trans.act.semaphore = &mlc->osem;
|
||||
up(&mlc->csem);
|
||||
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;
|
||||
unsigned long flags;
|
||||
|
||||
priv = mlc->priv;
|
||||
|
||||
write_lock_irqsave(&(mlc->lock), flags);
|
||||
|
||||
/* Try to down the semaphore -- it should be up. */
|
||||
if (down_trylock(&(mlc->osem))) {
|
||||
BUG();
|
||||
goto done;
|
||||
}
|
||||
BUG_ON(down_trylock(&mlc->osem));
|
||||
|
||||
if (mlc->opacket & HIL_DO_ALTER_CTRL) goto do_control;
|
||||
if (mlc->opacket & HIL_DO_ALTER_CTRL)
|
||||
goto do_control;
|
||||
|
||||
do_data:
|
||||
if (priv->emtestmode) {
|
||||
up(&(mlc->osem));
|
||||
goto done;
|
||||
up(&mlc->osem);
|
||||
return;
|
||||
}
|
||||
/* Shouldn't be sending commands when loop may be busy */
|
||||
if (down_trylock(&(mlc->csem))) {
|
||||
BUG();
|
||||
goto done;
|
||||
}
|
||||
up(&(mlc->csem));
|
||||
BUG_ON(down_trylock(&mlc->csem));
|
||||
up(&mlc->csem);
|
||||
|
||||
priv->trans.actidx = 0;
|
||||
priv->trans.idx = 1;
|
||||
priv->trans.act.semaphore = &(mlc->osem);
|
||||
priv->trans.act.semaphore = &mlc->osem;
|
||||
priv->trans.endidx = 6;
|
||||
priv->tseq[0] =
|
||||
priv->tseq[0] =
|
||||
HP_SDC_ACT_DATAREG | HP_SDC_ACT_POSTCMD | HP_SDC_ACT_SEMAPHORE;
|
||||
priv->tseq[1] = 0x7;
|
||||
priv->tseq[2] =
|
||||
(mlc->opacket &
|
||||
priv->tseq[2] =
|
||||
(mlc->opacket &
|
||||
(HIL_PKT_ADDR_MASK | HIL_PKT_CMD))
|
||||
>> HIL_PKT_ADDR_SHIFT;
|
||||
priv->tseq[3] =
|
||||
(mlc->opacket & HIL_PKT_DATA_MASK)
|
||||
priv->tseq[3] =
|
||||
(mlc->opacket & HIL_PKT_DATA_MASK)
|
||||
>> HIL_PKT_DATA_SHIFT;
|
||||
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;
|
||||
goto enqueue;
|
||||
|
||||
do_control:
|
||||
priv->emtestmode = mlc->opacket & HIL_CTRL_TEST;
|
||||
|
||||
|
||||
/* we cannot emulate this, it should not be used. */
|
||||
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_APE) {
|
||||
BUG(); /* Should not send command/data after engaging APE */
|
||||
goto done;
|
||||
}
|
||||
/* Disengaging APE this way would not be valid either since
|
||||
|
||||
if ((mlc->opacket & HIL_CTRL_ONLY) == HIL_CTRL_ONLY)
|
||||
goto control_only;
|
||||
|
||||
/* 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
|
||||
* the loop must be allowed to idle.
|
||||
*
|
||||
* So, it works out that we really never actually send control
|
||||
* and data when using SDC, we just send the data.
|
||||
* So, it works out that we really never actually send control
|
||||
* and data when using SDC, we just send the data.
|
||||
*/
|
||||
goto do_data;
|
||||
|
||||
control_only:
|
||||
priv->trans.actidx = 0;
|
||||
priv->trans.idx = 1;
|
||||
priv->trans.act.semaphore = &(mlc->osem);
|
||||
priv->trans.act.semaphore = &mlc->osem;
|
||||
priv->trans.endidx = 4;
|
||||
priv->tseq[0] =
|
||||
priv->tseq[0] =
|
||||
HP_SDC_ACT_PRECMD | HP_SDC_ACT_DATAOUT | HP_SDC_ACT_SEMAPHORE;
|
||||
priv->tseq[1] = HP_SDC_CMD_SET_LPC;
|
||||
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;
|
||||
if (mlc->opacket & HIL_CTRL_APE) {
|
||||
priv->tseq[3] |= HP_SDC_LPC_APE_IPF;
|
||||
down_trylock(&(mlc->csem));
|
||||
}
|
||||
down_trylock(&mlc->csem);
|
||||
}
|
||||
enqueue:
|
||||
hp_sdc_enqueue_transaction(&(priv->trans));
|
||||
done:
|
||||
write_unlock_irqrestore(&(mlc->lock), flags);
|
||||
hp_sdc_enqueue_transaction(&priv->trans);
|
||||
}
|
||||
|
||||
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.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;
|
||||
|
||||
mlc->cts = &hp_sdc_mlc_cts;
|
||||
mlc->in = &hp_sdc_mlc_in;
|
||||
mlc->out = &hp_sdc_mlc_out;
|
||||
mlc->cts = &hp_sdc_mlc_cts;
|
||||
mlc->in = &hp_sdc_mlc_in;
|
||||
mlc->out = &hp_sdc_mlc_out;
|
||||
mlc->priv = &hp_sdc_mlc_priv;
|
||||
|
||||
if (hil_mlc_register(mlc)) {
|
||||
printk(KERN_WARNING PREFIX "Failed to register MLC structure with hil_mlc\n");
|
||||
goto err0;
|
||||
}
|
||||
mlc->priv = &hp_sdc_mlc_priv;
|
||||
|
||||
if (hp_sdc_request_hil_irq(&hp_sdc_mlc_isr)) {
|
||||
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;
|
||||
err1:
|
||||
if (hil_mlc_unregister(mlc)) {
|
||||
if (hil_mlc_unregister(mlc))
|
||||
printk(KERN_ERR PREFIX "Failed to unregister MLC structure with hil_mlc.\n"
|
||||
"This is bad. Could cause an oops.\n");
|
||||
}
|
||||
err0:
|
||||
return -EBUSY;
|
||||
}
|
||||
|
@ -346,14 +339,14 @@ static int __init hp_sdc_mlc_init(void)
|
|||
static void __exit hp_sdc_mlc_exit(void)
|
||||
{
|
||||
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"
|
||||
"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"
|
||||
"This is bad. Could cause an oops.\n");
|
||||
}
|
||||
}
|
||||
|
||||
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"),
|
||||
},
|
||||
},
|
||||
{
|
||||
/*
|
||||
* 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",
|
||||
.matches = {
|
||||
|
@ -280,6 +302,8 @@ static struct pnp_driver i8042_pnp_kbd_driver = {
|
|||
};
|
||||
|
||||
static struct pnp_device_id pnp_aux_devids[] = {
|
||||
{ .id = "FJC6000", .driver_data = 0 },
|
||||
{ .id = "FJC6001", .driver_data = 0 },
|
||||
{ .id = "PNP0f03", .driver_data = 0 },
|
||||
{ .id = "PNP0f0b", .driver_data = 0 },
|
||||
{ .id = "PNP0f0e", .driver_data = 0 },
|
||||
|
|
|
@ -767,6 +767,13 @@ static void i8042_controller_reset(void)
|
|||
{
|
||||
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.
|
||||
*/
|
||||
|
|
|
@ -39,7 +39,8 @@
|
|||
/*
|
||||
* This code has been heavily tested on a Nokia 770, and lightly
|
||||
* 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
|
||||
* edge triggered IRQs on some platforms like the OMAP1/2. These
|
||||
|
@ -246,18 +247,16 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
|
|||
|
||||
/* REVISIT: take a few more samples, and compare ... */
|
||||
|
||||
/* maybe off internal vREF */
|
||||
if (use_internal) {
|
||||
req->ref_off = REF_OFF;
|
||||
req->xfer[4].tx_buf = &req->ref_off;
|
||||
req->xfer[4].len = 1;
|
||||
spi_message_add_tail(&req->xfer[4], &req->msg);
|
||||
/* converter in low power mode & enable PENIRQ */
|
||||
req->ref_off = PWRDOWN;
|
||||
req->xfer[4].tx_buf = &req->ref_off;
|
||||
req->xfer[4].len = 1;
|
||||
spi_message_add_tail(&req->xfer[4], &req->msg);
|
||||
|
||||
req->xfer[5].rx_buf = &req->scratch;
|
||||
req->xfer[5].len = 2;
|
||||
CS_CHANGE(req->xfer[5]);
|
||||
spi_message_add_tail(&req->xfer[5], &req->msg);
|
||||
}
|
||||
req->xfer[5].rx_buf = &req->scratch;
|
||||
req->xfer[5].len = 2;
|
||||
CS_CHANGE(req->xfer[5]);
|
||||
spi_message_add_tail(&req->xfer[5], &req->msg);
|
||||
|
||||
ts->irq_disabled = 1;
|
||||
disable_irq(spi->irq);
|
||||
|
@ -536,6 +535,9 @@ static void ads7846_rx(void *ads)
|
|||
} else
|
||||
Rt = 0;
|
||||
|
||||
if (ts->model == 7843)
|
||||
Rt = ts->pressure_max / 2;
|
||||
|
||||
/* Sample found inconsistent by debouncing or pressure is beyond
|
||||
* the maximum. Don't report it to user space, repeat at least
|
||||
* once more the measurement
|
||||
|
@ -897,7 +899,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
|
|||
|
||||
input_dev->name = "ADS784x Touchscreen";
|
||||
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->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.product = 0x0002;
|
||||
input_dev->id.version = 0x0100;
|
||||
input_dev->cdev.dev = &pdev->dev;
|
||||
input_dev->private = corgi_ts;
|
||||
input_dev->dev.parent = &pdev->dev;
|
||||
|
||||
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
|
||||
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);
|
||||
snprintf(elo->phys, sizeof(elo->phys), "%s/input0", serio->phys);
|
||||
|
||||
input_dev->private = elo;
|
||||
input_dev->name = "Elo Serial TouchScreen";
|
||||
input_dev->phys = elo->phys;
|
||||
input_dev->id.bustype = BUS_RS232;
|
||||
input_dev->id.vendor = SERIO_ELO;
|
||||
input_dev->id.product = elo->id;
|
||||
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->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;
|
||||
snprintf(gunze->phys, sizeof(serio->phys), "%s/input0", serio->phys);
|
||||
|
||||
input_dev->private = gunze;
|
||||
input_dev->name = "Gunze AHL-51S TouchScreen";
|
||||
input_dev->phys = gunze->phys;
|
||||
input_dev->id.bustype = BUS_RS232;
|
||||
input_dev->id.vendor = SERIO_GUNZE;
|
||||
input_dev->id.product = 0x0051;
|
||||
input_dev->id.version = 0x0100;
|
||||
input_dev->dev.parent = &serio->dev;
|
||||
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
|
||||
input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
|
||||
input_set_abs_params(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 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 */
|
||||
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)
|
||||
{
|
||||
#if 0
|
||||
struct h3600_dev *ts = dev->private;
|
||||
struct h3600_dev *ts = input_get_drvdata(dev);
|
||||
|
||||
switch (type) {
|
||||
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.product = 0x0666; /* FIXME !!! We can ask the hardware */
|
||||
input_dev->id.version = 0x0100;
|
||||
input_dev->cdev.dev = &serio->dev;
|
||||
input_dev->private = ts;
|
||||
input_dev->dev.parent = &serio->dev;
|
||||
|
||||
input_set_drvdata(input_dev, ts);
|
||||
|
||||
input_dev->event = h3600ts_event;
|
||||
|
||||
|
|
|
@ -144,13 +144,13 @@ static int mtouch_connect(struct serio *serio, struct serio_driver *drv)
|
|||
mtouch->dev = input_dev;
|
||||
snprintf(mtouch->phys, sizeof(mtouch->phys), "%s/input0", serio->phys);
|
||||
|
||||
input_dev->private = mtouch;
|
||||
input_dev->name = "MicroTouch Serial TouchScreen";
|
||||
input_dev->phys = mtouch->phys;
|
||||
input_dev->id.bustype = BUS_RS232;
|
||||
input_dev->id.vendor = SERIO_MICROTOUCH;
|
||||
input_dev->id.product = 0;
|
||||
input_dev->id.version = 0x0100;
|
||||
input_dev->dev.parent = &serio->dev;
|
||||
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
|
||||
input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
|
||||
input_set_abs_params(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;
|
||||
snprintf(pm->phys, sizeof(pm->phys), "%s/input0", serio->phys);
|
||||
|
||||
input_dev->private = pm;
|
||||
input_dev->name = "Penmount Serial TouchScreen";
|
||||
input_dev->phys = pm->phys;
|
||||
input_dev->id.bustype = BUS_RS232;
|
||||
input_dev->id.vendor = SERIO_PENMOUNT;
|
||||
input_dev->id.product = 0;
|
||||
input_dev->id.version = 0x0100;
|
||||
input_dev->cdev.dev = &serio->dev;
|
||||
input_dev->dev.parent = &serio->dev;
|
||||
|
||||
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
|
||||
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;
|
||||
snprintf(tr->phys, sizeof(tr->phys), "%s/input0", serio->phys);
|
||||
|
||||
input_dev->private = tr;
|
||||
input_dev->name = "Touchright Serial TouchScreen";
|
||||
input_dev->phys = tr->phys;
|
||||
input_dev->id.bustype = BUS_RS232;
|
||||
input_dev->id.vendor = SERIO_TOUCHRIGHT;
|
||||
input_dev->id.product = 0;
|
||||
input_dev->id.version = 0x0100;
|
||||
input_dev->dev.parent = &serio->dev;
|
||||
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
|
||||
input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
|
||||
input_set_abs_params(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;
|
||||
snprintf(tw->phys, sizeof(tw->phys), "%s/input0", serio->phys);
|
||||
|
||||
input_dev->private = tw;
|
||||
input_dev->name = "Touchwindow Serial TouchScreen";
|
||||
input_dev->phys = tw->phys;
|
||||
input_dev->id.bustype = BUS_RS232;
|
||||
input_dev->id.vendor = SERIO_TOUCHWIN;
|
||||
input_dev->id.product = 0;
|
||||
input_dev->id.version = 0x0100;
|
||||
input_dev->dev.parent = &serio->dev;
|
||||
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
|
||||
input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
|
||||
input_set_abs_params(tw->dev, ABS_X, TW_MIN_XC, TW_MAX_XC, 0, 0);
|
||||
|
|
|
@ -97,6 +97,8 @@ struct ucb1400 {
|
|||
};
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -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_TSMY_GND | UCB_TS_CR_TSPY_GND |
|
||||
UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
|
||||
udelay(ts_delay_pressure);
|
||||
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_MODE_POS | UCB_TS_CR_BIAS_ENA);
|
||||
|
||||
udelay(55);
|
||||
udelay(ts_delay);
|
||||
|
||||
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_MODE_POS | UCB_TS_CR_BIAS_ENA);
|
||||
|
||||
udelay(55);
|
||||
udelay(ts_delay);
|
||||
|
||||
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)
|
||||
{
|
||||
struct ucb1400 *ucb = idev->private;
|
||||
struct ucb1400 *ucb = input_get_drvdata(idev);
|
||||
int ret = 0;
|
||||
|
||||
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)
|
||||
{
|
||||
struct ucb1400 *ucb = idev->private;
|
||||
struct ucb1400 *ucb = input_get_drvdata(idev);
|
||||
|
||||
if (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);
|
||||
|
||||
idev->private = ucb;
|
||||
idev->cdev.dev = dev;
|
||||
input_set_drvdata(idev, ucb);
|
||||
|
||||
idev->dev.parent = dev;
|
||||
idev->name = "UCB1400 touchscreen interface";
|
||||
idev->id.vendor = ucb1400_reg_read(ucb, AC97_VENDOR_ID1);
|
||||
idev->id.product = id;
|
||||
|
@ -571,7 +575,15 @@ static void __exit ucb1400_ts_exit(void)
|
|||
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_exit(ucb1400_ts_exit);
|
||||
|
|
|
@ -111,13 +111,13 @@ struct tsdev {
|
|||
int minor;
|
||||
char name[8];
|
||||
wait_queue_head_t wait;
|
||||
struct list_head list;
|
||||
struct list_head client_list;
|
||||
struct input_handle handle;
|
||||
int x, y, pressure;
|
||||
struct ts_calibration cal;
|
||||
};
|
||||
|
||||
struct tsdev_list {
|
||||
struct tsdev_client {
|
||||
struct fasync_struct *fasync;
|
||||
struct list_head node;
|
||||
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)
|
||||
{
|
||||
struct tsdev_list *list = file->private_data;
|
||||
struct tsdev_client *client = file->private_data;
|
||||
int retval;
|
||||
|
||||
retval = fasync_helper(fd, file, on, &list->fasync);
|
||||
retval = fasync_helper(fd, file, on, &client->fasync);
|
||||
return retval < 0 ? retval : 0;
|
||||
}
|
||||
|
||||
static int tsdev_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
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 "
|
||||
"for removal.\nSee Documentation/feature-removal-schedule.txt "
|
||||
"for details.\n");
|
||||
|
||||
if (i >= TSDEV_MINORS || !tsdev_table[i & TSDEV_MINOR_MASK])
|
||||
if (i >= TSDEV_MINORS)
|
||||
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;
|
||||
|
||||
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;
|
||||
list->tsdev = tsdev_table[i];
|
||||
list_add_tail(&list->node, &tsdev_table[i]->list);
|
||||
file->private_data = list;
|
||||
if (!tsdev->open++ && tsdev->exist) {
|
||||
error = input_open_device(&tsdev->handle);
|
||||
if (error) {
|
||||
list_del(&client->node);
|
||||
kfree(client);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
if (!list->tsdev->open++)
|
||||
if (list->tsdev->exist)
|
||||
input_open_device(&list->tsdev->handle);
|
||||
file->private_data = client;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -182,45 +193,48 @@ static void tsdev_free(struct tsdev *tsdev)
|
|||
|
||||
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);
|
||||
list_del(&list->node);
|
||||
|
||||
if (!--list->tsdev->open) {
|
||||
if (list->tsdev->exist)
|
||||
input_close_device(&list->tsdev->handle);
|
||||
list_del(&client->node);
|
||||
kfree(client);
|
||||
|
||||
if (!--tsdev->open) {
|
||||
if (tsdev->exist)
|
||||
input_close_device(&tsdev->handle);
|
||||
else
|
||||
tsdev_free(list->tsdev);
|
||||
tsdev_free(tsdev);
|
||||
}
|
||||
kfree(list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
retval = wait_event_interruptible(list->tsdev->wait,
|
||||
list->head != list->tail || !list->tsdev->exist);
|
||||
|
||||
retval = wait_event_interruptible(tsdev->wait,
|
||||
client->head != client->tail || !tsdev->exist);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (!list->tsdev->exist)
|
||||
if (!tsdev->exist)
|
||||
return -ENODEV;
|
||||
|
||||
while (list->head != list->tail &&
|
||||
while (client->head != client->tail &&
|
||||
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)))
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -228,32 +242,33 @@ static ssize_t tsdev_read(struct file *file, char __user *buffer, size_t count,
|
|||
}
|
||||
|
||||
/* 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);
|
||||
return ((list->head == list->tail) ? 0 : (POLLIN | POLLRDNORM)) |
|
||||
(list->tsdev->exist ? 0 : (POLLHUP | POLLERR));
|
||||
poll_wait(file, &tsdev->wait, wait);
|
||||
return ((client->head == client->tail) ? 0 : (POLLIN | POLLRDNORM)) |
|
||||
(tsdev->exist ? 0 : (POLLHUP | POLLERR));
|
||||
}
|
||||
|
||||
static int tsdev_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct tsdev_list *list = file->private_data;
|
||||
struct tsdev *tsdev = list->tsdev;
|
||||
struct tsdev_client *client = file->private_data;
|
||||
struct tsdev *tsdev = client->tsdev;
|
||||
int retval = 0;
|
||||
|
||||
switch (cmd) {
|
||||
case TS_GET_CAL:
|
||||
if (copy_to_user ((void __user *)arg, &tsdev->cal,
|
||||
sizeof (struct ts_calibration)))
|
||||
if (copy_to_user((void __user *)arg, &tsdev->cal,
|
||||
sizeof (struct ts_calibration)))
|
||||
retval = -EFAULT;
|
||||
break;
|
||||
|
||||
case TS_SET_CAL:
|
||||
if (copy_from_user (&tsdev->cal, (void __user *)arg,
|
||||
sizeof (struct ts_calibration)))
|
||||
if (copy_from_user(&tsdev->cal, (void __user *)arg,
|
||||
sizeof (struct ts_calibration)))
|
||||
retval = -EFAULT;
|
||||
break;
|
||||
|
||||
|
@ -279,7 +294,7 @@ static void tsdev_event(struct input_handle *handle, unsigned int type,
|
|||
unsigned int code, int value)
|
||||
{
|
||||
struct tsdev *tsdev = handle->private;
|
||||
struct tsdev_list *list;
|
||||
struct tsdev_client *client;
|
||||
struct timeval time;
|
||||
|
||||
switch (type) {
|
||||
|
@ -343,18 +358,18 @@ static void tsdev_event(struct input_handle *handle, unsigned int type,
|
|||
if (type != EV_SYN || code != SYN_REPORT)
|
||||
return;
|
||||
|
||||
list_for_each_entry(list, &tsdev->list, node) {
|
||||
list_for_each_entry(client, &tsdev->client_list, node) {
|
||||
int x, y, tmp;
|
||||
|
||||
do_gettimeofday(&time);
|
||||
list->event[list->head].millisecs = time.tv_usec / 100;
|
||||
list->event[list->head].pressure = tsdev->pressure;
|
||||
client->event[client->head].millisecs = time.tv_usec / 100;
|
||||
client->event[client->head].pressure = tsdev->pressure;
|
||||
|
||||
x = tsdev->x;
|
||||
y = tsdev->y;
|
||||
|
||||
/* Calibration */
|
||||
if (!list->raw) {
|
||||
if (!client->raw) {
|
||||
x = ((x * tsdev->cal.xscale) >> 8) + tsdev->cal.xtrans;
|
||||
y = ((y * tsdev->cal.yscale) >> 8) + tsdev->cal.ytrans;
|
||||
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;
|
||||
list->event[list->head].y = y;
|
||||
list->head = (list->head + 1) & (TSDEV_BUFFER_SIZE - 1);
|
||||
kill_fasync(&list->fasync, SIGIO, POLL_IN);
|
||||
client->event[client->head].x = x;
|
||||
client->event[client->head].y = y;
|
||||
client->head = (client->head + 1) & (TSDEV_BUFFER_SIZE - 1);
|
||||
kill_fasync(&client->fasync, SIGIO, POLL_IN);
|
||||
}
|
||||
wake_up_interruptible(&tsdev->wait);
|
||||
}
|
||||
|
||||
static struct input_handle *tsdev_connect(struct input_handler *handler,
|
||||
struct input_dev *dev,
|
||||
const struct input_device_id *id)
|
||||
static int tsdev_connect(struct input_handler *handler, struct input_dev *dev,
|
||||
const struct input_device_id *id)
|
||||
{
|
||||
struct tsdev *tsdev;
|
||||
struct class_device *cdev;
|
||||
dev_t devt;
|
||||
int minor, delta;
|
||||
int error;
|
||||
|
||||
for (minor = 0; minor < TSDEV_MINORS / 2 && tsdev_table[minor]; minor++);
|
||||
if (minor >= TSDEV_MINORS / 2) {
|
||||
printk(KERN_ERR
|
||||
"tsdev: You have way too many touchscreens\n");
|
||||
return NULL;
|
||||
return -ENFILE;
|
||||
}
|
||||
|
||||
if (!(tsdev = kzalloc(sizeof(struct tsdev), GFP_KERNEL)))
|
||||
return NULL;
|
||||
tsdev = kzalloc(sizeof(struct tsdev), GFP_KERNEL);
|
||||
if (!tsdev)
|
||||
return -ENOMEM;
|
||||
|
||||
INIT_LIST_HEAD(&tsdev->list);
|
||||
INIT_LIST_HEAD(&tsdev->client_list);
|
||||
init_waitqueue_head(&tsdev->wait);
|
||||
|
||||
sprintf(tsdev->name, "ts%d", minor);
|
||||
|
@ -415,21 +432,43 @@ static struct input_handle *tsdev_connect(struct input_handler *handler,
|
|||
|
||||
tsdev_table[minor] = tsdev;
|
||||
|
||||
cdev = class_device_create(&input_class, &dev->cdev,
|
||||
MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor),
|
||||
dev->cdev.dev, tsdev->name);
|
||||
devt = MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor),
|
||||
|
||||
cdev = class_device_create(&input_class, &dev->cdev, devt,
|
||||
dev->cdev.dev, tsdev->name);
|
||||
if (IS_ERR(cdev)) {
|
||||
error = PTR_ERR(cdev);
|
||||
goto err_free_tsdev;
|
||||
}
|
||||
|
||||
/* temporary symlink to keep userspace happy */
|
||||
sysfs_create_link(&input_class.subsys.kobj, &cdev->kobj,
|
||||
tsdev->name);
|
||||
error = sysfs_create_link(&input_class.subsys.kobj,
|
||||
&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)
|
||||
{
|
||||
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);
|
||||
class_device_destroy(&input_class,
|
||||
|
@ -439,8 +478,8 @@ static void tsdev_disconnect(struct input_handle *handle)
|
|||
if (tsdev->open) {
|
||||
input_close_device(handle);
|
||||
wake_up_interruptible(&tsdev->wait);
|
||||
list_for_each_entry(list, &tsdev->list, node)
|
||||
kill_fasync(&list->fasync, SIGIO, POLL_HUP);
|
||||
list_for_each_entry(client, &tsdev->client_list, node)
|
||||
kill_fasync(&client->fasync, SIGIO, POLL_HUP);
|
||||
} else
|
||||
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_KBTAB) += kbtab.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_POWERMATE) += powermate.o
|
||||
obj-$(CONFIG_USB_WACOM) += wacom.o
|
||||
|
@ -20,7 +17,7 @@ obj-$(CONFIG_USB_ACECAD) += acecad.o
|
|||
obj-$(CONFIG_USB_YEALINK) += yealink.o
|
||||
obj-$(CONFIG_USB_XPAD) += xpad.o
|
||||
obj-$(CONFIG_USB_APPLETOUCH) += appletouch.o
|
||||
obj-$(CONFIG_USB_GTCO) += gtco.o
|
||||
obj-$(CONFIG_USB_GTCO) += gtco.o
|
||||
|
||||
ifeq ($(CONFIG_USB_DEBUG),y)
|
||||
EXTRA_CFLAGS += -DDEBUG
|
||||
|
|
|
@ -111,7 +111,7 @@ static void usb_acecad_irq(struct urb *urb)
|
|||
|
||||
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;
|
||||
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)
|
||||
{
|
||||
struct usb_acecad *acecad = dev->private;
|
||||
struct usb_acecad *acecad = input_get_drvdata(dev);
|
||||
|
||||
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 input_dev *input_dev;
|
||||
int pipe, maxp;
|
||||
int err = -ENOMEM;
|
||||
|
||||
if (interface->desc.bNumEndpoints != 1)
|
||||
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);
|
||||
input_dev = input_allocate_device();
|
||||
if (!acecad || !input_dev)
|
||||
if (!acecad || !input_dev) {
|
||||
err = -ENOMEM;
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
acecad->data = usb_buffer_alloc(dev, 8, GFP_KERNEL, &acecad->data_dma);
|
||||
if (!acecad->data)
|
||||
if (!acecad->data) {
|
||||
err= -ENOMEM;
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
acecad->irq = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!acecad->irq)
|
||||
if (!acecad->irq) {
|
||||
err = -ENOMEM;
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
acecad->usbdev = 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->phys = acecad->phys;
|
||||
usb_to_input_id(dev, &input_dev->id);
|
||||
input_dev->cdev.dev = &intf->dev;
|
||||
input_dev->private = acecad;
|
||||
input_dev->dev.parent = &intf->dev;
|
||||
|
||||
input_set_drvdata(input_dev, acecad);
|
||||
|
||||
input_dev->open = usb_acecad_open;
|
||||
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_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);
|
||||
|
||||
|
@ -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);
|
||||
fail1: input_free_device(input_dev);
|
||||
kfree(acecad);
|
||||
return -ENOMEM;
|
||||
return err;
|
||||
}
|
||||
|
||||
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