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:
Linus Torvalds 2007-05-04 18:13:17 -07:00
commit a3d52136ee
120 changed files with 4349 additions and 3265 deletions

View File

@ -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);
{

View File

@ -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

View File

@ -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);

View File

@ -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);
}

View File

@ -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/

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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];

View File

@ -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);
}

View File

@ -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 };

View File

@ -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;

View File

@ -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++)

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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++)

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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;
}

View File

@ -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.
*/

View File

@ -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);

View File

@ -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.
*/

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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) |

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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))) {

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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");

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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) {

View File

@ -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

View File

@ -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);

View File

@ -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, &param, 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, &param, 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;

View File

@ -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

View File

@ -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) {
/*

View File

@ -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

View File

@ -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);

View File

@ -87,6 +87,7 @@ enum psmouse_type {
PSMOUSE_ALPS,
PSMOUSE_LIFEBOOK,
PSMOUSE_TRACKPOINT,
PSMOUSE_TOUCHKIT_PS2,
PSMOUSE_AUTO /* This one should always be last */
};

View File

@ -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);

View File

@ -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 */

View File

@ -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 */

View File

@ -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;
}

View File

@ -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

View File

@ -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 */

View File

@ -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);

View File

@ -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;

View File

@ -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");

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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 },

View File

@ -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.
*/

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);
}

View File

@ -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

View File

@ -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