Commit 508cf6ef authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://kernel.bkbits.net/vojtech/input

into home.transmeta.com:/home/torvalds/v2.5/linux
parents 9936b07d 44a56c6d
...@@ -146,7 +146,7 @@ static int __init button_init(void) ...@@ -146,7 +146,7 @@ static int __init button_init(void)
Note the button_used variable - we have to track how many times the open 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. function was called to know when exactly our device stops being used.
The open() callback should return a 0 in case of succes or any nonzero value The open() callback should return a 0 in case of success or any nonzero value
in case of failure. The close() callback (which is void) must always succeed. in case of failure. The close() callback (which is void) must always succeed.
1.3 Basic event types 1.3 Basic event types
...@@ -178,7 +178,7 @@ set the corresponding bits and call the ...@@ -178,7 +178,7 @@ set the corresponding bits and call the
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 However EV_ABS requires a little special care. Before calling
input_register_devices, you have to fill additional fields in the input_dev input_register_device, you have to fill additional fields in the input_dev
struct for each absolute axis your device has. If our button device had also struct for each absolute axis your device has. If our button device had also
the ABS_X axis: the ABS_X axis:
...@@ -207,11 +207,11 @@ one device. You'll need it in the open and close callbacks. ...@@ -207,11 +207,11 @@ one device. You'll need it in the open and close callbacks.
1.5 NBITS(), LONG(), BIT() 1.5 NBITS(), LONG(), BIT()
~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~
These three macros frin input.h help some bitfield computations: These three macros from input.h help some bitfield computations:
NBITS(x) - returns the length of a bitfield array in longs for x bits NBITS(x) - returns the length of a bitfield array in longs for x bits
LONG(x) - returns the index in the array in longs for bit x LONG(x) - returns the index in the array in longs for bit x
BIT(x) - returns the indes in a long for bit x BIT(x) - returns the index in a long for bit x
1.6 The number, id* and name fields 1.6 The number, id* and name fields
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
...@@ -221,7 +221,7 @@ is registered. It has no use except for identifying the device to the user ...@@ -221,7 +221,7 @@ is registered. It has no use except for identifying the device to the user
in system messages. in system messages.
The dev->name should be set before registering the input device by the input The dev->name should be set before registering the input device by the input
device driver. It's a string like 'Generic button device' containing an device driver. It's a string like 'Generic button device' containing a
user friendly name of the device. user friendly name of the device.
The id* fields contain the bus ID (PCI, USB, ...), vendor ID and device ID The id* fields contain the bus ID (PCI, USB, ...), vendor ID and device ID
...@@ -237,7 +237,7 @@ The id and name fields can be passed to userland via the evdev interface. ...@@ -237,7 +237,7 @@ The id and name fields can be passed to userland via the evdev interface.
1.7 The keycode, keycodemax, keycodesize fields 1.7 The keycode, keycodemax, keycodesize fields
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
These two fields will be used for any inpur devices that report their data 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 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 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 used to map from scancodes to input system keycodes. The keycode max will
...@@ -258,7 +258,7 @@ handled by the input system. ...@@ -258,7 +258,7 @@ handled by the input system.
The other event types up to now are: The other event types up to now are:
EV_LED - used for the keyboad LEDs. EV_LED - used for the keyboard LEDs.
EV_SND - used for keyboard beeps. EV_SND - used for keyboard beeps.
They are very similar to for example key events, but they go in the other They are very similar to for example key events, but they go in the other
...@@ -270,7 +270,7 @@ driver can handle these events, it has to set the respective bits in evbit, ...@@ -270,7 +270,7 @@ driver can handle these events, it has to set the respective bits in evbit,
int button_event(struct input_dev *dev, unsigned int type, unsigned int code, int value); int button_event(struct input_dev *dev, unsigned int type, unsigned int code, int value);
{ {
if (type == EV_SND && code == EV_BELL) { if (type == EV_SND && code == SND_BELL) {
outb(value, BUTTON_BELL); outb(value, BUTTON_BELL);
return 0; return 0;
} }
......
...@@ -52,11 +52,13 @@ extern void ctrl_alt_del(void); ...@@ -52,11 +52,13 @@ extern void ctrl_alt_del(void);
/* /*
* Some laptops take the 789uiojklm,. keys as number pad when NumLock is on. * Some laptops take the 789uiojklm,. keys as number pad when NumLock is on.
* This seems a good reason to start with NumLock off. On PC9800 however there * This seems a good reason to start with NumLock off. On PC9800 and HIL keyboards
* is no NumLock key and everyone expects the keypad to be used for numbers. * of PARISC machines however there is no NumLock key and everyone expects the keypad
* to be used for numbers.
*/ */
#ifdef CONFIG_X86_PC9800 #if defined(CONFIG_X86_PC9800) || \
defined(CONFIG_PARISC) && (defined(CONFIG_KEYBOARD_HIL) || defined(CONFIG_KEYBOARD_HIL_OLD))
#define KBD_DEFLEDS (1 << VC_NUMLOCK) #define KBD_DEFLEDS (1 << VC_NUMLOCK)
#else #else
#define KBD_DEFLEDS 0 #define KBD_DEFLEDS 0
......
...@@ -395,7 +395,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, ...@@ -395,7 +395,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
if (!perm) if (!perm)
return -EPERM; return -EPERM;
if (arg) if (arg)
arg = 1193180 / arg; arg = 1193182 / arg;
kd_mksound(arg, 0); kd_mksound(arg, 0);
return 0; return 0;
...@@ -412,7 +412,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, ...@@ -412,7 +412,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
ticks = HZ * ((arg >> 16) & 0xffff) / 1000; ticks = HZ * ((arg >> 16) & 0xffff) / 1000;
count = ticks ? (arg & 0xffff) : 0; count = ticks ? (arg & 0xffff) : 0;
if (count) if (count)
count = 1193180 / count; count = 1193182 / count;
kd_mksound(count, ticks); kd_mksound(count, ticks);
return 0; return 0;
} }
......
...@@ -29,6 +29,7 @@ struct evdev { ...@@ -29,6 +29,7 @@ struct evdev {
char name[16]; char name[16];
struct input_handle handle; struct input_handle handle;
wait_queue_head_t wait; wait_queue_head_t wait;
struct evdev_list *grab;
struct list_head list; struct list_head list;
}; };
...@@ -48,7 +49,8 @@ static void evdev_event(struct input_handle *handle, unsigned int type, unsigned ...@@ -48,7 +49,8 @@ static void evdev_event(struct input_handle *handle, unsigned int type, unsigned
struct evdev *evdev = handle->private; struct evdev *evdev = handle->private;
struct evdev_list *list; struct evdev_list *list;
list_for_each_entry(list, &evdev->list, node) { if (evdev->grab) {
list = evdev->grab;
do_gettimeofday(&list->buffer[list->head].time); do_gettimeofday(&list->buffer[list->head].time);
list->buffer[list->head].type = type; list->buffer[list->head].type = type;
...@@ -57,7 +59,17 @@ static void evdev_event(struct input_handle *handle, unsigned int type, unsigned ...@@ -57,7 +59,17 @@ static void evdev_event(struct input_handle *handle, unsigned int type, unsigned
list->head = (list->head + 1) & (EVDEV_BUFFER_SIZE - 1); list->head = (list->head + 1) & (EVDEV_BUFFER_SIZE - 1);
kill_fasync(&list->fasync, SIGIO, POLL_IN); kill_fasync(&list->fasync, SIGIO, POLL_IN);
} } else
list_for_each_entry(list, &evdev->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);
kill_fasync(&list->fasync, SIGIO, POLL_IN);
}
wake_up_interruptible(&evdev->wait); wake_up_interruptible(&evdev->wait);
} }
...@@ -88,6 +100,11 @@ static int evdev_release(struct inode * inode, struct file * file) ...@@ -88,6 +100,11 @@ static int evdev_release(struct inode * inode, struct file * file)
{ {
struct evdev_list *list = file->private_data; struct evdev_list *list = file->private_data;
if (list->evdev->grab == list) {
input_release_device(&list->evdev->handle);
list->evdev->grab = NULL;
}
evdev_fasync(-1, file, 0); evdev_fasync(-1, file, 0);
list_del(&list->node); list_del(&list->node);
...@@ -257,6 +274,22 @@ static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ...@@ -257,6 +274,22 @@ static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
return -EFAULT; return -EFAULT;
return 0; return 0;
case EVIOCGRAB:
if (arg) {
if (evdev->grab)
return -EBUSY;
if (input_grab_device(&evdev->handle))
return -EBUSY;
evdev->grab = list;
return 0;
} else {
if (evdev->grab != list)
return -EINVAL;
input_release_device(&evdev->handle);
evdev->grab = NULL;
return 0;
}
default: default:
if (_IOC_TYPE(cmd) != 'E' || _IOC_DIR(cmd) != _IOC_READ) if (_IOC_TYPE(cmd) != 'E' || _IOC_DIR(cmd) != _IOC_READ)
......
...@@ -37,7 +37,7 @@ static LIST_HEAD(gameport_dev_list); ...@@ -37,7 +37,7 @@ static LIST_HEAD(gameport_dev_list);
#ifdef __i386__ #ifdef __i386__
#define DELTA(x,y) ((y)-(x)+((y)<(x)?1193180/HZ:0)) #define DELTA(x,y) ((y)-(x)+((y)<(x)?1193182/HZ:0))
#define GET_TIME(x) do { x = get_time_pit(); } while (0) #define GET_TIME(x) do { x = get_time_pit(); } while (0)
static unsigned int get_time_pit(void) static unsigned int get_time_pit(void)
......
...@@ -33,6 +33,8 @@ EXPORT_SYMBOL(input_register_device); ...@@ -33,6 +33,8 @@ EXPORT_SYMBOL(input_register_device);
EXPORT_SYMBOL(input_unregister_device); EXPORT_SYMBOL(input_unregister_device);
EXPORT_SYMBOL(input_register_handler); EXPORT_SYMBOL(input_register_handler);
EXPORT_SYMBOL(input_unregister_handler); EXPORT_SYMBOL(input_unregister_handler);
EXPORT_SYMBOL(input_grab_device);
EXPORT_SYMBOL(input_release_device);
EXPORT_SYMBOL(input_open_device); EXPORT_SYMBOL(input_open_device);
EXPORT_SYMBOL(input_close_device); EXPORT_SYMBOL(input_close_device);
EXPORT_SYMBOL(input_accept_process); EXPORT_SYMBOL(input_accept_process);
...@@ -175,9 +177,12 @@ void input_event(struct input_dev *dev, unsigned int type, unsigned int code, in ...@@ -175,9 +177,12 @@ void input_event(struct input_dev *dev, unsigned int type, unsigned int code, in
if (type != EV_SYN) if (type != EV_SYN)
dev->sync = 0; dev->sync = 0;
list_for_each_entry(handle, &dev->h_list, d_node) if (dev->grab)
if (handle->open) dev->grab->handler->event(dev->grab, type, code, value);
handle->handler->event(handle, type, code, value); else
list_for_each_entry(handle, &dev->h_list, d_node)
if (handle->open)
handle->handler->event(handle, type, code, value);
} }
static void input_repeat_key(unsigned long data) static void input_repeat_key(unsigned long data)
...@@ -201,6 +206,21 @@ int input_accept_process(struct input_handle *handle, struct file *file) ...@@ -201,6 +206,21 @@ int input_accept_process(struct input_handle *handle, struct file *file)
return 0; return 0;
} }
int input_grab_device(struct input_handle *handle)
{
if (handle->dev->grab)
return -EBUSY;
handle->dev->grab = handle;
return 0;
}
void input_release_device(struct input_handle *handle)
{
if (handle->dev->grab == handle)
handle->dev->grab = NULL;
}
int input_open_device(struct input_handle *handle) int input_open_device(struct input_handle *handle)
{ {
if (handle->dev->pm_dev) if (handle->dev->pm_dev)
...@@ -221,6 +241,7 @@ int input_flush_device(struct input_handle* handle, struct file* file) ...@@ -221,6 +241,7 @@ int input_flush_device(struct input_handle* handle, struct file* file)
void input_close_device(struct input_handle *handle) void input_close_device(struct input_handle *handle)
{ {
input_release_device(handle);
if (handle->dev->pm_dev) if (handle->dev->pm_dev)
pm_dev_idle(handle->dev->pm_dev); pm_dev_idle(handle->dev->pm_dev);
if (handle->dev->close) if (handle->dev->close)
......
...@@ -138,7 +138,7 @@ struct analog_port { ...@@ -138,7 +138,7 @@ struct analog_port {
#ifdef __i386__ #ifdef __i386__
#define GET_TIME(x) do { if (cpu_has_tsc) rdtscl(x); else x = get_time_pit(); } while (0) #define GET_TIME(x) do { if (cpu_has_tsc) rdtscl(x); else x = get_time_pit(); } while (0)
#define DELTA(x,y) (cpu_has_tsc?((y)-(x)):((x)-(y)+((x)<(y)?1193180L/HZ:0))) #define DELTA(x,y) (cpu_has_tsc?((y)-(x)):((x)-(y)+((x)<(y)?1193182L/HZ:0)))
#define TIME_NAME (cpu_has_tsc?"TSC":"PIT") #define TIME_NAME (cpu_has_tsc?"TSC":"PIT")
static unsigned int get_time_pit(void) static unsigned int get_time_pit(void)
{ {
......
...@@ -39,7 +39,7 @@ static int atkbd_reset = 1; ...@@ -39,7 +39,7 @@ static int atkbd_reset = 1;
static unsigned char atkbd_set2_keycode[512] = { static unsigned char atkbd_set2_keycode[512] = {
0, 67, 65, 63, 61, 59, 60, 88, 0, 68, 66, 64, 62, 15, 41, 85, 0, 67, 65, 63, 61, 59, 60, 88, 0, 68, 66, 64, 62, 15, 41, 85,
0, 56, 42, 0, 29, 16, 2, 89, 0, 0, 44, 31, 30, 17, 3, 90, 0, 56, 42,182, 29, 16, 2, 89, 0, 0, 44, 31, 30, 17, 3, 90,
0, 46, 45, 32, 18, 5, 4, 91, 0, 57, 47, 33, 20, 19, 6, 0, 0, 46, 45, 32, 18, 5, 4, 91, 0, 57, 47, 33, 20, 19, 6, 0,
0, 49, 48, 35, 34, 21, 7, 0, 0, 0, 50, 36, 22, 8, 9, 0, 0, 49, 48, 35, 34, 21, 7, 0, 0, 0, 50, 36, 22, 8, 9, 0,
0, 51, 37, 23, 24, 11, 10, 0, 0, 52, 53, 38, 39, 25, 12, 0, 0, 51, 37, 23, 24, 11, 10, 0, 0, 52, 53, 38, 39, 25, 12, 0,
......
...@@ -271,7 +271,7 @@ static void sunkbd_connect(struct serio *serio, struct serio_dev *dev) ...@@ -271,7 +271,7 @@ static void sunkbd_connect(struct serio *serio, struct serio_dev *dev)
sprintf(sunkbd->name, "Sun Type %d keyboard", sunkbd->type); sprintf(sunkbd->name, "Sun Type %d keyboard", sunkbd->type);
memcpy(sunkbd->keycode, sunkbd_keycode, sizeof(sunkbd->keycode)); memcpy(sunkbd->keycode, sunkbd_keycode, sizeof(sunkbd->keycode));
for (i = 0; i < 127; i++) for (i = 0; i < 128; i++)
set_bit(sunkbd->keycode[i], sunkbd->dev.keybit); set_bit(sunkbd->keycode[i], sunkbd->dev.keybit);
clear_bit(0, sunkbd->dev.keybit); clear_bit(0, sunkbd->dev.keybit);
......
...@@ -43,7 +43,7 @@ static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int c ...@@ -43,7 +43,7 @@ static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int c
} }
if (value > 20 && value < 32767) if (value > 20 && value < 32767)
count = 1193182 / value; count = CLOCK_TICK_RATE / value;
spin_lock_irqsave(&i8253_beep_lock, flags); spin_lock_irqsave(&i8253_beep_lock, flags);
......
...@@ -28,6 +28,19 @@ config MOUSE_PS2 ...@@ -28,6 +28,19 @@ config MOUSE_PS2
The module will be called psmouse. If you want to compile it as a The module will be called psmouse. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>. module, say M here and read <file:Documentation/modules.txt>.
config MOUSE_PS2_SYNAPTICS
bool "Synaptics TouchPad"
default n
depends on INPUT && INPUT_MOUSE && SERIO && MOUSE_PS2
---help---
Say Y here if you have a Synaptics TouchPad connected to your system.
This touchpad is found on many modern laptop computers.
Note that you also need a user space driver to interpret the data
generated by the kernel. A compatible driver for XFree86 is available
from http://...
If unsure, say Y.
config MOUSE_SERIAL config MOUSE_SERIAL
tristate "Serial mouse" tristate "Serial mouse"
depends on INPUT && INPUT_MOUSE && SERIO depends on INPUT && INPUT_MOUSE && SERIO
......
...@@ -13,3 +13,8 @@ obj-$(CONFIG_MOUSE_PC110PAD) += pc110pad.o ...@@ -13,3 +13,8 @@ obj-$(CONFIG_MOUSE_PC110PAD) += pc110pad.o
obj-$(CONFIG_MOUSE_PC9800) += 98busmouse.o obj-$(CONFIG_MOUSE_PC9800) += 98busmouse.o
obj-$(CONFIG_MOUSE_PS2) += psmouse.o obj-$(CONFIG_MOUSE_PS2) += psmouse.o
obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o
psmouse-objs := psmouse-base.o
ifeq ($(CONFIG_MOUSE_PS2_SYNAPTICS),y)
psmouse-objs += synaptics.o
endif
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
#include <linux/input.h> #include <linux/input.h>
#include <linux/serio.h> #include <linux/serio.h>
#include <linux/init.h> #include <linux/init.h>
#include "psmouse.h"
#include "synaptics.h"
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_DESCRIPTION("PS/2 mouse driver"); MODULE_DESCRIPTION("PS/2 mouse driver");
...@@ -25,48 +27,7 @@ MODULE_LICENSE("GPL"); ...@@ -25,48 +27,7 @@ MODULE_LICENSE("GPL");
static int psmouse_noext; static int psmouse_noext;
#define PSMOUSE_CMD_SETSCALE11 0x00e6 static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "PS2T++", "GenPS/2", "ImPS/2", "ImExPS/2", "Synaptics"};
#define PSMOUSE_CMD_SETRES 0x10e8
#define PSMOUSE_CMD_GETINFO 0x03e9
#define PSMOUSE_CMD_SETSTREAM 0x00ea
#define PSMOUSE_CMD_POLL 0x03eb
#define PSMOUSE_CMD_GETID 0x02f2
#define PSMOUSE_CMD_SETRATE 0x10f3
#define PSMOUSE_CMD_ENABLE 0x00f4
#define PSMOUSE_CMD_RESET_DIS 0x00f6
#define PSMOUSE_CMD_RESET_BAT 0x02ff
#define PSMOUSE_RET_BAT 0xaa
#define PSMOUSE_RET_ACK 0xfa
#define PSMOUSE_RET_NAK 0xfe
struct psmouse {
struct input_dev dev;
struct serio *serio;
char *vendor;
char *name;
unsigned char cmdbuf[8];
unsigned char packet[8];
unsigned char cmdcnt;
unsigned char pktcnt;
unsigned char type;
unsigned char model;
unsigned long last;
char acking;
volatile char ack;
char error;
char devname[64];
char phys[32];
};
#define PSMOUSE_PS2 1
#define PSMOUSE_PS2PP 2
#define PSMOUSE_PS2TPP 3
#define PSMOUSE_GENPS 4
#define PSMOUSE_IMPS 5
#define PSMOUSE_IMEX 6
static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "PS2T++", "GenPS/2", "ImPS/2", "ImExPS/2" };
/* /*
* psmouse_process_packet() anlyzes the PS/2 mouse packet contents and * psmouse_process_packet() anlyzes the PS/2 mouse packet contents and
...@@ -209,6 +170,16 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, ...@@ -209,6 +170,16 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
goto out; goto out;
} }
if (psmouse->pktcnt == 1 && psmouse->type == PSMOUSE_SYNAPTICS) {
/*
* The synaptics driver has its own resync logic,
* so it needs to receive all bytes one at a time.
*/
synaptics_process_byte(psmouse, regs);
psmouse->pktcnt = 0;
goto out;
}
if (psmouse->pktcnt == 1 && psmouse->packet[0] == PSMOUSE_RET_BAT) { if (psmouse->pktcnt == 1 && psmouse->packet[0] == PSMOUSE_RET_BAT) {
serio_rescan(serio); serio_rescan(serio);
goto out; goto out;
...@@ -244,7 +215,7 @@ static int psmouse_sendbyte(struct psmouse *psmouse, unsigned char byte) ...@@ -244,7 +215,7 @@ static int psmouse_sendbyte(struct psmouse *psmouse, unsigned char byte)
* then waits for the response and puts it in the param array. * then waits for the response and puts it in the param array.
*/ */
static int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command) int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command)
{ {
int timeout = 500000; /* 500 msec */ int timeout = 500000; /* 500 msec */
int send = (command >> 12) & 0xf; int send = (command >> 12) & 0xf;
...@@ -343,12 +314,12 @@ static int psmouse_extensions(struct psmouse *psmouse) ...@@ -343,12 +314,12 @@ static int psmouse_extensions(struct psmouse *psmouse)
psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO); psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO);
if (param[1] == 0x47) { if (param[1] == 0x47) {
/* We could do more here. But it's sufficient just psmouse->vendor = "Synaptics";
to stop the subsequent probes from screwing the psmouse->name = "TouchPad";
thing up. */ if (!synaptics_init(psmouse))
psmouse->vendor = "Synaptics"; return PSMOUSE_SYNAPTICS;
psmouse->name = "TouchPad"; else
return PSMOUSE_PS2; return PSMOUSE_PS2;
} }
/* /*
...@@ -598,6 +569,7 @@ static void psmouse_disconnect(struct serio *serio) ...@@ -598,6 +569,7 @@ static void psmouse_disconnect(struct serio *serio)
struct psmouse *psmouse = serio->private; struct psmouse *psmouse = serio->private;
input_unregister_device(&psmouse->dev); input_unregister_device(&psmouse->dev);
serio_close(serio); serio_close(serio);
synaptics_disconnect(psmouse);
kfree(psmouse); kfree(psmouse);
} }
......
#ifndef _PSMOUSE_H
#define _PSMOUSE_H
#define PSMOUSE_CMD_SETSCALE11 0x00e6
#define PSMOUSE_CMD_SETRES 0x10e8
#define PSMOUSE_CMD_GETINFO 0x03e9
#define PSMOUSE_CMD_SETSTREAM 0x00ea
#define PSMOUSE_CMD_POLL 0x03eb
#define PSMOUSE_CMD_GETID 0x02f2
#define PSMOUSE_CMD_SETRATE 0x10f3
#define PSMOUSE_CMD_ENABLE 0x00f4
#define PSMOUSE_CMD_RESET_DIS 0x00f6
#define PSMOUSE_CMD_RESET_BAT 0x02ff
#define PSMOUSE_RET_BAT 0xaa
#define PSMOUSE_RET_ACK 0xfa
#define PSMOUSE_RET_NAK 0xfe
struct psmouse {
void *private;
struct input_dev dev;
struct serio *serio;
char *vendor;
char *name;
unsigned char cmdbuf[8];
unsigned char packet[8];
unsigned char cmdcnt;
unsigned char pktcnt;
unsigned char type;
unsigned char model;
unsigned long last;
char acking;
volatile char ack;
char error;
char devname[64];
char phys[32];
};
#define PSMOUSE_PS2 1
#define PSMOUSE_PS2PP 2
#define PSMOUSE_PS2TPP 3
#define PSMOUSE_GENPS 4
#define PSMOUSE_IMPS 5
#define PSMOUSE_IMEX 6
#define PSMOUSE_SYNAPTICS 7
int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command);
#endif /* _PSMOUSE_H */
/*
* Synaptics TouchPad PS/2 mouse driver
*
* 2003 Peter Osterlund <petero2@telia.com>
* Ported to 2.5 input device infrastructure.
*
* Copyright (C) 2001 Stefan Gmeiner <riddlebox@freesurf.ch>
* start merging tpconfig and gpm code to a xfree-input module
* adding some changes and extensions (ex. 3rd and 4th button)
*
* Copyright (c) 1997 C. Scott Ananian <cananian@alumni.priceton.edu>
* Copyright (c) 1998-2000 Bruce Kalk <kall@compass.com>
* code for the special synaptics commands (from the tpconfig-source)
*
* 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.
*
* Trademarks are the property of their respective owners.
*/
#include <linux/module.h>
#include <linux/input.h>
#include "psmouse.h"
#include "synaptics.h"
/*****************************************************************************
* Synaptics communications functions
****************************************************************************/
/*
* Use the Synaptics extended ps/2 syntax to write a special command byte.
* special command: 0xE8 rr 0xE8 ss 0xE8 tt 0xE8 uu where (rr*64)+(ss*16)+(tt*4)+uu
* is the command. A 0xF3 or 0xE9 must follow (see synaptics_send_cmd
* and synaptics_set_mode)
*/
static int synaptics_special_cmd(struct psmouse *psmouse, unsigned char command)
{
int i;
if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11))
return -1;
for (i = 6; i >= 0; i -= 2) {
unsigned char d = (command >> i) & 3;
if (psmouse_command(psmouse, &d, PSMOUSE_CMD_SETRES))
return -1;
}
return 0;
}
/*
* 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 (synaptics_special_cmd(psmouse, c))
return -1;
if (psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO))
return -1;
return 0;
}
/*
* Set the synaptics touchpad mode byte by special commands
*/
static int synaptics_set_mode(struct psmouse *psmouse, unsigned char mode)
{
unsigned char param[1];
if (synaptics_special_cmd(psmouse, mode))
return -1;
param[0] = 0x14;
if (psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE))
return -1;
return 0;
}
static int synaptics_reset(struct psmouse *psmouse)
{
unsigned char r[2];
if (psmouse_command(psmouse, r, PSMOUSE_CMD_RESET_BAT))
return -1;
if (r[0] == 0xAA && r[1] == 0x00)
return 0;
return -1;
}
/*
* Read the model-id bytes from the touchpad
* see also SYN_MODEL_* macros
*/
static int synaptics_model_id(struct psmouse *psmouse, unsigned long int *model_id)
{
unsigned char mi[3];
if (synaptics_send_cmd(psmouse, SYN_QUE_MODEL, mi))
return -1;
*model_id = (mi[0]<<16) | (mi[1]<<8) | mi[2];
return 0;
}
/*
* Read the capability-bits from the touchpad
* see also the SYN_CAP_* macros
*/
static int synaptics_capability(struct psmouse *psmouse, unsigned long int *capability)
{
unsigned char cap[3];
if (synaptics_send_cmd(psmouse, SYN_QUE_CAPABILITIES, cap))
return -1;
*capability = (cap[0]<<16) | (cap[1]<<8) | cap[2];
if (SYN_CAP_VALID(*capability))
return 0;
return -1;
}
/*
* Identify Touchpad
* See also the SYN_ID_* macros
*/
static int synaptics_identify(struct psmouse *psmouse, unsigned long int *ident)
{
unsigned char id[3];
if (synaptics_send_cmd(psmouse, SYN_QUE_IDENTIFY, id))
return -1;
*ident = (id[0]<<16) | (id[1]<<8) | id[2];
if (SYN_ID_IS_SYNAPTICS(*ident))
return 0;
return -1;
}
static int synaptics_enable_device(struct psmouse *psmouse)
{
if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_ENABLE))
return -1;
return 0;
}
static void print_ident(struct synaptics_data *priv)
{
printk(KERN_INFO "Synaptics Touchpad, model: %ld\n", SYN_ID_MODEL(priv->identity));
printk(KERN_INFO " Firware: %ld.%ld\n", SYN_ID_MAJOR(priv->identity),
SYN_ID_MINOR(priv->identity));
if (SYN_MODEL_ROT180(priv->model_id))
printk(KERN_INFO " 180 degree mounted touchpad\n");
if (SYN_MODEL_PORTRAIT(priv->model_id))
printk(KERN_INFO " portrait touchpad\n");
printk(KERN_INFO " Sensor: %ld\n", SYN_MODEL_SENSOR(priv->model_id));
if (SYN_MODEL_NEWABS(priv->model_id))
printk(KERN_INFO " new absolute packet format\n");
if (SYN_MODEL_PEN(priv->model_id))
printk(KERN_INFO " pen detection\n");
if (SYN_CAP_EXTENDED(priv->capabilities)) {
printk(KERN_INFO " Touchpad has extended capability bits\n");
if (SYN_CAP_FOUR_BUTTON(priv->capabilities))
printk(KERN_INFO " -> four buttons\n");
if (SYN_CAP_MULTIFINGER(priv->capabilities))
printk(KERN_INFO " -> multifinger detection\n");
if (SYN_CAP_PALMDETECT(priv->capabilities))
printk(KERN_INFO " -> palm detection\n");
}
}
static int query_hardware(struct psmouse *psmouse)
{
struct synaptics_data *priv = psmouse->private;
int retries = 3;
while ((retries++ <= 3) && synaptics_reset(psmouse))
printk(KERN_ERR "synaptics reset failed\n");
if (synaptics_identify(psmouse, &priv->identity))
return -1;
if (synaptics_model_id(psmouse, &priv->model_id))
return -1;
if (synaptics_capability(psmouse, &priv->capabilities))
return -1;
if (synaptics_set_mode(psmouse, (SYN_BIT_ABSOLUTE_MODE |
SYN_BIT_HIGH_RATE |
SYN_BIT_DISABLE_GESTURE |
SYN_BIT_W_MODE)))
return -1;
synaptics_enable_device(psmouse);
print_ident(priv);
return 0;
}
/*****************************************************************************
* Driver initialization/cleanup functions
****************************************************************************/
static inline void set_abs_params(struct input_dev *dev, int axis, int min, int max, int fuzz, int flat)
{
dev->absmin[axis] = min;
dev->absmax[axis] = max;
dev->absfuzz[axis] = fuzz;
dev->absflat[axis] = flat;
set_bit(axis, dev->absbit);
}
int synaptics_init(struct psmouse *psmouse)
{
struct synaptics_data *priv;
psmouse->private = priv = kmalloc(sizeof(struct synaptics_data), GFP_KERNEL);
if (!priv)
return -1;
memset(priv, 0, sizeof(struct synaptics_data));
priv->inSync = 1;
if (query_hardware(psmouse)) {
printk(KERN_ERR "Unable to query/initialize Synaptics hardware.\n");
goto init_fail;
}
/*
* The x/y limits are taken from the Synaptics TouchPad interfacing Guide,
* which says that they should be valid regardless of the actual size of
* the senser.
*/
set_bit(EV_ABS, psmouse->dev.evbit);
set_abs_params(&psmouse->dev, ABS_X, 1472, 5472, 0, 0);
set_abs_params(&psmouse->dev, ABS_Y, 1408, 4448, 0, 0);
set_abs_params(&psmouse->dev, ABS_PRESSURE, 0, 255, 0, 0);
set_bit(EV_MSC, psmouse->dev.evbit);
set_bit(MSC_GESTURE, psmouse->dev.mscbit);
set_bit(EV_KEY, psmouse->dev.evbit);
set_bit(BTN_LEFT, psmouse->dev.keybit);
set_bit(BTN_RIGHT, psmouse->dev.keybit);
set_bit(BTN_FORWARD, psmouse->dev.keybit);
set_bit(BTN_BACK, psmouse->dev.keybit);
clear_bit(EV_REL, psmouse->dev.evbit);
clear_bit(REL_X, psmouse->dev.relbit);
clear_bit(REL_Y, psmouse->dev.relbit);
return 0;
init_fail:
kfree(priv);
return -1;
}
void synaptics_disconnect(struct psmouse *psmouse)
{
struct synaptics_data *priv = psmouse->private;
kfree(priv);
}
/*****************************************************************************
* Functions to interpret the absolute mode packets
****************************************************************************/
static void synaptics_parse_hw_state(struct synaptics_data *priv,
struct synaptics_hw_state *hw)
{
unsigned char *buf = priv->proto_buf;
hw->x = (((buf[3] & 0x10) << 8) |
((buf[1] & 0x0f) << 8) |
buf[4]);
hw->y = (((buf[3] & 0x20) << 7) |
((buf[1] & 0xf0) << 4) |
buf[5]);
hw->z = buf[2];
hw->w = (((buf[0] & 0x30) >> 2) |
((buf[0] & 0x04) >> 1) |
((buf[3] & 0x04) >> 2));
hw->left = (buf[0] & 0x01) ? 1 : 0;
hw->right = (buf[0] & 0x2) ? 1 : 0;
hw->up = 0;
hw->down = 0;
if (SYN_CAP_EXTENDED(priv->capabilities) &&
(SYN_CAP_FOUR_BUTTON(priv->capabilities))) {
hw->up = ((buf[3] & 0x01)) ? 1 : 0;
if (hw->left)
hw->up = !hw->up;
hw->down = ((buf[3] & 0x02)) ? 1 : 0;
if (hw->right)
hw->down = !hw->down;
}
}
/*
* called for each full received packet from the touchpad
*/
static void synaptics_process_packet(struct psmouse *psmouse)
{
struct input_dev *dev = &psmouse->dev;
struct synaptics_data *priv = psmouse->private;
struct synaptics_hw_state hw;
synaptics_parse_hw_state(priv, &hw);
if (hw.z > 0) {
int w_ok = 0;
/*
* Use capability bits to decide if the w value is valid.
* If not, set it to 5, which corresponds to a finger of
* normal width.
*/
if (SYN_CAP_EXTENDED(priv->capabilities)) {
switch (hw.w) {
case 0 ... 1:
w_ok = SYN_CAP_MULTIFINGER(priv->capabilities);
break;
case 2:
w_ok = SYN_MODEL_PEN(priv->model_id);
break;
case 4 ... 15:
w_ok = SYN_CAP_PALMDETECT(priv->capabilities);
break;
}
}
if (!w_ok)
hw.w = 5;
}
/* Post events */
input_report_abs(dev, ABS_X, hw.x);
input_report_abs(dev, ABS_Y, hw.y);
input_report_abs(dev, ABS_PRESSURE, hw.z);
if (hw.w != priv->old_w) {
input_event(dev, EV_MSC, MSC_GESTURE, hw.w);
priv->old_w = hw.w;
}
input_report_key(dev, BTN_LEFT, hw.left);
input_report_key(dev, BTN_RIGHT, hw.right);
input_report_key(dev, BTN_FORWARD, hw.up);
input_report_key(dev, BTN_BACK, hw.down);
input_sync(dev);
}
void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
{
struct input_dev *dev = &psmouse->dev;
struct synaptics_data *priv = psmouse->private;
unsigned char *pBuf = priv->proto_buf;
unsigned char u = psmouse->packet[0];
input_regs(dev, regs);
pBuf[priv->proto_buf_tail++] = u;
/* check first byte */
if ((priv->proto_buf_tail == 1) && ((u & 0xC8) != 0x80)) {
priv->inSync = 0;
priv->proto_buf_tail = 0;
printk(KERN_WARNING "Synaptics driver lost sync at 1st byte\n");
return;
}
/* check 4th byte */
if ((priv->proto_buf_tail == 4) && ((u & 0xc8) != 0xc0)) {
priv->inSync = 0;
priv->proto_buf_tail = 0;
printk(KERN_WARNING "Synaptics driver lost sync at 4th byte\n");
return;
}
if (priv->proto_buf_tail >= 6) { /* Full packet received */
if (!priv->inSync) {
priv->inSync = 1;
printk(KERN_NOTICE "Synaptics driver resynced.\n");
}
synaptics_process_packet(psmouse);
priv->proto_buf_tail = 0;
}
}
/*
* Synaptics TouchPad PS/2 mouse driver
*
* 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 _SYNAPTICS_H
#define _SYNAPTICS_H
#ifdef CONFIG_MOUSE_PS2_SYNAPTICS
extern void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs);
extern int synaptics_init(struct psmouse *psmouse);
extern void synaptics_disconnect(struct psmouse *psmouse);
#else
static inline void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs) {}
static inline int synaptics_init(struct psmouse *psmouse) { return -1; }
static inline void synaptics_disconnect(struct psmouse *psmouse) {}
#endif
/* synaptics queries */
#define SYN_QUE_IDENTIFY 0x00
#define SYN_QUE_MODES 0x01
#define SYN_QUE_CAPABILITIES 0x02
#define SYN_QUE_MODEL 0x03
#define SYN_QUE_SERIAL_NUMBER_PREFIX 0x06
#define SYN_QUE_SERIAL_NUMBER_SUFFIX 0x07
#define SYN_QUE_RESOLUTION 0x08
/* synatics modes */
#define SYN_BIT_ABSOLUTE_MODE (1 << 7)
#define SYN_BIT_HIGH_RATE (1 << 6)
#define SYN_BIT_SLEEP_MODE (1 << 3)
#define SYN_BIT_DISABLE_GESTURE (1 << 2)
#define SYN_BIT_W_MODE (1 << 0)
/* synaptics model ID bits */
#define SYN_MODEL_ROT180(m) ((m) & (1 << 23))
#define SYN_MODEL_PORTRAIT(m) ((m) & (1 << 22))
#define SYN_MODEL_SENSOR(m) (((m) >> 16) & 0x3f)
#define SYN_MODEL_HARDWARE(m) (((m) >> 9) & 0x7f)
#define SYN_MODEL_NEWABS(m) ((m) & (1 << 7))
#define SYN_MODEL_PEN(m) ((m) & (1 << 6))
#define SYN_MODEL_SIMPLIC(m) ((m) & (1 << 5))
#define SYN_MODEL_GEOMETRY(m) ((m) & 0x0f)
/* synaptics capability bits */
#define SYN_CAP_EXTENDED(c) ((c) & (1 << 23))
#define SYN_CAP_SLEEP(c) ((c) & (1 << 4))
#define SYN_CAP_FOUR_BUTTON(c) ((c) & (1 << 3))
#define SYN_CAP_MULTIFINGER(c) ((c) & (1 << 1))
#define SYN_CAP_PALMDETECT(c) ((c) & (1 << 0))
#define SYN_CAP_VALID(c) ((((c) & 0x00ff00) >> 8) == 0x47)
/* synaptics modes query bits */
#define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7))
#define SYN_MODE_RATE(m) ((m) & (1 << 6))
#define SYN_MODE_BAUD_SLEEP(m) ((m) & (1 << 3))
#define SYN_MODE_DISABLE_GESTURE(m) ((m) & (1 << 2))
#define SYN_MODE_PACKSIZE(m) ((m) & (1 << 1))
#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_IS_SYNAPTICS(i) ((((i) >> 8) & 0xff) == 0x47)
/*
* A structure to describe the state of the touchpad hardware (buttons and pad)
*/
struct synaptics_hw_state {
int x;
int y;
int z;
int w;
int left;
int right;
int up;
int down;
};
struct synaptics_data {
/* Data read from the touchpad */
unsigned long int model_id; /* Model-ID */
unsigned long int capabilities; /* Capabilities */
unsigned long int identity; /* Identification */
/* Data for normal processing */
unsigned char proto_buf[6]; /* Buffer for Packet */
unsigned char last_byte; /* last received byte */
int inSync; /* Packets in sync */
int proto_buf_tail;
int old_w; /* Previous w value */
};
#endif /* _SYNAPTICS_H */
...@@ -119,3 +119,14 @@ config SERIO_98KBD ...@@ -119,3 +119,14 @@ config SERIO_98KBD
The module will be called rpckbd.o. If you want to compile it as a The module will be called rpckbd.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>. module, say M here and read <file:Documentation/modules.txt>.
config SERIO_PCIPS2
tristate "PCI PS/2 keyboard and PS/2 mouse controller"
depends on PCI && SERIO
help
Say Y here if you have a Mobility Docking station with PS/2
keyboard and mice ports.
This driver is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called rpckbd. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
...@@ -14,3 +14,4 @@ obj-$(CONFIG_SERIO_SA1111) += sa1111ps2.o ...@@ -14,3 +14,4 @@ obj-$(CONFIG_SERIO_SA1111) += sa1111ps2.o
obj-$(CONFIG_SERIO_AMBAKMI) += ambakmi.o obj-$(CONFIG_SERIO_AMBAKMI) += ambakmi.o
obj-$(CONFIG_SERIO_Q40KBD) += q40kbd.o obj-$(CONFIG_SERIO_Q40KBD) += q40kbd.o
obj-$(CONFIG_SERIO_98KBD) += 98kbd-io.o obj-$(CONFIG_SERIO_98KBD) += 98kbd-io.o
obj-$(CONFIG_SERIO_PCIPS2) += pcips2.o
...@@ -20,11 +20,14 @@ ...@@ -20,11 +20,14 @@
*/ */
#ifdef __alpha__ #ifdef __alpha__
#define I8042_KBD_IRQ 1 # define I8042_KBD_IRQ 1
#define I8042_AUX_IRQ (RTC_PORT(0) == 0x170 ? 9 : 12) /* Jensen is special */ # define I8042_AUX_IRQ (RTC_PORT(0) == 0x170 ? 9 : 12) /* Jensen is special */
#elif defined(__ia64__)
# define I8042_KBD_IRQ isa_irq_to_vector(1)
# define I8042_AUX_IRQ isa_irq_to_vector(12)
#else #else
#define I8042_KBD_IRQ 1 # define I8042_KBD_IRQ 1
#define I8042_AUX_IRQ 12 # define I8042_AUX_IRQ 12
#endif #endif
/* /*
......
/*
* linux/drivers/input/serio/pcips2.c
*
* Copyright (C) 2003 Russell King, All Rights Reserved.
*
* 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.
*
* I'm not sure if this is a generic PS/2 PCI interface or specific to
* the Mobility Electronics docking station.
*/
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/input.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/serio.h>
#include <linux/delay.h>
#include <asm/io.h>
#define PS2_CTRL (0)
#define PS2_STATUS (1)
#define PS2_DATA (2)
#define PS2_CTRL_CLK (1<<0)
#define PS2_CTRL_DAT (1<<1)
#define PS2_CTRL_TXIRQ (1<<2)
#define PS2_CTRL_ENABLE (1<<3)
#define PS2_CTRL_RXIRQ (1<<4)
#define PS2_STAT_CLK (1<<0)
#define PS2_STAT_DAT (1<<1)
#define PS2_STAT_PARITY (1<<2)
#define PS2_STAT_RXFULL (1<<5)
#define PS2_STAT_TXBUSY (1<<6)
#define PS2_STAT_TXEMPTY (1<<7)
struct pcips2_data {
struct serio io;
unsigned int base;
struct pci_dev *dev;
};
static int pcips2_write(struct serio *io, unsigned char val)
{
struct pcips2_data *ps2if = io->driver;
unsigned int stat;
do {
stat = inb(ps2if->base + PS2_STATUS);
cpu_relax();
} while (!(stat & PS2_STAT_TXEMPTY));
outb(val, ps2if->base + PS2_DATA);
return 0;
}
static void pcips2_interrupt(int irq, void *devid, struct pt_regs *regs)
{
struct pcips2_data *ps2if = devid;
unsigned char status, scancode;
do {
unsigned int flag;
status = inb(ps2if->base + PS2_STATUS);
if (!(status & PS2_STAT_RXFULL))
break;
scancode = inb(ps2if->base + PS2_DATA);
if (status == 0xff && scancode == 0xff)
break;
flag = (status & PS2_STAT_PARITY) ? 0 : SERIO_PARITY;
if (hweight8(scancode) & 1)
flag ^= SERIO_PARITY;
serio_interrupt(&ps2if->io, scancode, flag, regs);
} while (1);
}
static void pcips2_flush_input(struct pcips2_data *ps2if)
{
unsigned char status, scancode;
do {
status = inb(ps2if->base + PS2_STATUS);
if (!(status & PS2_STAT_RXFULL))
break;
scancode = inb(ps2if->base + PS2_DATA);
if (status == 0xff && scancode == 0xff)
break;
} while (1);
}
static int pcips2_open(struct serio *io)
{
struct pcips2_data *ps2if = io->driver;
int ret, val = 0;
outb(PS2_CTRL_ENABLE, ps2if->base);
pcips2_flush_input(ps2if);
ret = request_irq(ps2if->dev->irq, pcips2_interrupt, SA_SHIRQ,
"pcips2", ps2if);
if (ret == 0)
val = PS2_CTRL_ENABLE | PS2_CTRL_RXIRQ;
outb(val, ps2if->base);
return ret;
}
static void pcips2_close(struct serio *io)
{
struct pcips2_data *ps2if = io->driver;
outb(0, ps2if->base);
free_irq(ps2if->dev->irq, ps2if);
}
static int __devinit pcips2_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
struct pcips2_data *ps2if;
int ret;
ret = pci_enable_device(dev);
if (ret)
return ret;
if (!request_region(pci_resource_start(dev, 0),
pci_resource_len(dev, 0), "pcips2")) {
ret = -EBUSY;
goto disable;
}
ps2if = kmalloc(sizeof(struct pcips2_data), GFP_KERNEL);
if (!ps2if) {
ret = -ENOMEM;
goto release;
}
memset(ps2if, 0, sizeof(struct pcips2_data));
ps2if->io.type = SERIO_8042;
ps2if->io.write = pcips2_write;
ps2if->io.open = pcips2_open;
ps2if->io.close = pcips2_close;
ps2if->io.name = dev->dev.name;
ps2if->io.phys = dev->dev.bus_id;
ps2if->io.driver = ps2if;
ps2if->dev = dev;
ps2if->base = pci_resource_start(dev, 0);
pci_set_drvdata(dev, ps2if);
serio_register_port(&ps2if->io);
return 0;
release:
release_region(pci_resource_start(dev, 0),
pci_resource_len(dev, 0));
disable:
pci_disable_device(dev);
return ret;
}
static void __devexit pcips2_remove(struct pci_dev *dev)
{
struct pcips2_data *ps2if = pci_get_drvdata(dev);
serio_unregister_port(&ps2if->io);
release_region(pci_resource_start(dev, 0),
pci_resource_len(dev, 0));
pci_set_drvdata(dev, NULL);
kfree(ps2if);
pci_disable_device(dev);
}
static struct pci_device_id pcips2_ids[] = {
{
.vendor = 0x14f2, /* MOBILITY */
.device = 0x0123, /* Keyboard */
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.class = PCI_CLASS_INPUT_KEYBOARD << 8,
.class_mask = 0xffff00,
},
{
.vendor = 0x14f2, /* MOBILITY */
.device = 0x0124, /* Mouse */
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.class = PCI_CLASS_INPUT_MOUSE << 8,
.class_mask = 0xffff00,
},
{ 0, }
};
static struct pci_driver pcips2_driver = {
.name = "pcips2",
.id_table = pcips2_ids,
.probe = pcips2_probe,
.remove = __devexit_p(pcips2_remove),
.driver = {
.devclass = &input_devclass,
},
};
static int __init pcips2_init(void)
{
return pci_module_init(&pcips2_driver);
}
static void __exit pcips2_exit(void)
{
pci_unregister_driver(&pcips2_driver);
}
module_init(pcips2_init);
module_exit(pcips2_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
MODULE_DESCRIPTION("PCI PS/2 keyboard/mouse driver");
MODULE_DEVICE_TABLE(pci, pcips2_ids);
...@@ -957,6 +957,10 @@ static void hid_output_field(struct hid_field *field, __u8 *data) ...@@ -957,6 +957,10 @@ static void hid_output_field(struct hid_field *field, __u8 *data)
void hid_output_report(struct hid_report *report, __u8 *data) void hid_output_report(struct hid_report *report, __u8 *data)
{ {
unsigned n; unsigned n;
if (report->id > 0)
*data++ = report->id;
for (n = 0; n < report->maxfield; n++) for (n = 0; n < report->maxfield; n++)
hid_output_field(report->field[n], data); hid_output_field(report->field[n], data);
} }
...@@ -1051,7 +1055,7 @@ static int hid_submit_out(struct hid_device *hid) ...@@ -1051,7 +1055,7 @@ static int hid_submit_out(struct hid_device *hid)
report = hid->out[hid->outtail]; report = hid->out[hid->outtail];
hid_output_report(report, hid->outbuf); hid_output_report(report, hid->outbuf);
hid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 1; hid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + (report->id > 0);
hid->urbout->dev = hid->dev; hid->urbout->dev = hid->dev;
dbg("submitting out urb"); dbg("submitting out urb");
...@@ -1075,7 +1079,7 @@ static int hid_submit_ctrl(struct hid_device *hid) ...@@ -1075,7 +1079,7 @@ static int hid_submit_ctrl(struct hid_device *hid)
if (dir == USB_DIR_OUT) if (dir == USB_DIR_OUT)
hid_output_report(report, hid->ctrlbuf); hid_output_report(report, hid->ctrlbuf);
hid->urbctrl->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + ((report->id > 0) && (dir != USB_DIR_OUT)); hid->urbctrl->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + (report->id > 0);
hid->urbctrl->pipe = (dir == USB_DIR_OUT) ? usb_sndctrlpipe(hid->dev, 0) : usb_rcvctrlpipe(hid->dev, 0); hid->urbctrl->pipe = (dir == USB_DIR_OUT) ? usb_sndctrlpipe(hid->dev, 0) : usb_rcvctrlpipe(hid->dev, 0);
hid->urbctrl->dev = hid->dev; hid->urbctrl->dev = hid->dev;
...@@ -1351,6 +1355,9 @@ void hid_init_reports(struct hid_device *hid) ...@@ -1351,6 +1355,9 @@ void hid_init_reports(struct hid_device *hid)
#define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f #define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f
#define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100 #define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100
#define USB_VENDOR_ID_A4TECH 0x09DA
#define USB_DEVICE_ID_A4TECH_WCP32PU 0x0006
struct hid_blacklist { struct hid_blacklist {
__u16 idVendor; __u16 idVendor;
__u16 idProduct; __u16 idProduct;
...@@ -1398,6 +1405,7 @@ struct hid_blacklist { ...@@ -1398,6 +1405,7 @@ struct hid_blacklist {
{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 500, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 500, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_TANGTOP, USB_DEVICE_ID_TANGTOP_USBPS2, HID_QUIRK_NOGET }, { USB_VENDOR_ID_TANGTOP, USB_DEVICE_ID_TANGTOP_USBPS2, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK },
{ 0, 0 } { 0, 0 }
}; };
......
...@@ -376,6 +376,11 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel ...@@ -376,6 +376,11 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
} }
set_bit(usage->type, input->evbit); set_bit(usage->type, input->evbit);
if ((usage->type == EV_REL)
&& (device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK)
&& (usage->code == REL_WHEEL)) {
set_bit(REL_HWHEEL, bit);
}
while (usage->code <= max && test_and_set_bit(usage->code, bit)) { while (usage->code <= max && test_and_set_bit(usage->code, bit)) {
usage->code = find_next_zero_bit(bit, max + 1, usage->code); usage->code = find_next_zero_bit(bit, max + 1, usage->code);
...@@ -426,6 +431,20 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct ...@@ -426,6 +431,20 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
input_regs(input, regs); input_regs(input, regs);
if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK)
&& (usage->code == BTN_BACK)) {
if (value)
hid->quirks |= HID_QUIRK_2WHEEL_MOUSE_HACK_ON;
else
hid->quirks &= ~HID_QUIRK_2WHEEL_MOUSE_HACK_ON;
return;
}
if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_ON)
&& (usage->code == REL_WHEEL)) {
input_event(input, usage->type, REL_HWHEEL, value);
return;
}
if (usage->hat_min != usage->hat_max) { if (usage->hat_min != usage->hat_max) {
value = (value - usage->hat_min) * 8 / (usage->hat_max - usage->hat_min + 1) + 1; value = (value - usage->hat_min) * 8 / (usage->hat_max - usage->hat_min + 1) + 1;
if (value < 0 || value > 8) value = 0; if (value < 0 || value > 8) value = 0;
......
...@@ -201,13 +201,15 @@ struct hid_item { ...@@ -201,13 +201,15 @@ struct hid_item {
* HID device quirks. * HID device quirks.
*/ */
#define HID_QUIRK_INVERT 0x01 #define HID_QUIRK_INVERT 0x001
#define HID_QUIRK_NOTOUCH 0x02 #define HID_QUIRK_NOTOUCH 0x002
#define HID_QUIRK_IGNORE 0x04 #define HID_QUIRK_IGNORE 0x004
#define HID_QUIRK_NOGET 0x08 #define HID_QUIRK_NOGET 0x008
#define HID_QUIRK_HIDDEV 0x10 #define HID_QUIRK_HIDDEV 0x010
#define HID_QUIRK_BADPAD 0x20 #define HID_QUIRK_BADPAD 0x020
#define HID_QUIRK_MULTI_INPUT 0x40 #define HID_QUIRK_MULTI_INPUT 0x040
#define HID_QUIRK_2WHEEL_MOUSE_HACK 0x080
#define HID_QUIRK_2WHEEL_MOUSE_HACK_ON 0x100
/* /*
* This is the global environment of the parser. This information is * This is the global environment of the parser. This information is
......
...@@ -442,10 +442,14 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd ...@@ -442,10 +442,14 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
if (copy_to_user((void *) arg, &dinfo, sizeof(dinfo))) if (copy_to_user((void *) arg, &dinfo, sizeof(dinfo)))
return -EFAULT; return -EFAULT;
return 0;
case HIDIOCGFLAG: case HIDIOCGFLAG:
if (put_user(list->flags, (int *) arg)) if (put_user(list->flags, (int *) arg))
return -EFAULT; return -EFAULT;
return 0;
case HIDIOCSFLAG: case HIDIOCSFLAG:
{ {
int newflags; int newflags;
...@@ -533,6 +537,8 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd ...@@ -533,6 +537,8 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
if (copy_to_user((void *) arg, &rinfo, sizeof(rinfo))) if (copy_to_user((void *) arg, &rinfo, sizeof(rinfo)))
return -EFAULT; return -EFAULT;
return 0;
case HIDIOCGFIELDINFO: case HIDIOCGFIELDINFO:
if (copy_from_user(&finfo, (void *) arg, sizeof(finfo))) if (copy_from_user(&finfo, (void *) arg, sizeof(finfo)))
return -EFAULT; return -EFAULT;
...@@ -564,6 +570,8 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd ...@@ -564,6 +570,8 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
if (copy_to_user((void *) arg, &finfo, sizeof(finfo))) if (copy_to_user((void *) arg, &finfo, sizeof(finfo)))
return -EFAULT; return -EFAULT;
return 0;
case HIDIOCGUCODE: case HIDIOCGUCODE:
if (copy_from_user(&uref, (void *) arg, sizeof(uref))) if (copy_from_user(&uref, (void *) arg, sizeof(uref)))
return -EFAULT; return -EFAULT;
...@@ -585,6 +593,8 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd ...@@ -585,6 +593,8 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
if (copy_to_user((void *) arg, &uref, sizeof(uref))) if (copy_to_user((void *) arg, &uref, sizeof(uref)))
return -EFAULT; return -EFAULT;
return 0;
case HIDIOCGUSAGE: case HIDIOCGUSAGE:
case HIDIOCSUSAGE: case HIDIOCSUSAGE:
case HIDIOCGCOLLECTIONINDEX: case HIDIOCGCOLLECTIONINDEX:
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
#ifdef CONFIG_MELAN #ifdef CONFIG_MELAN
# define CLOCK_TICK_RATE 1189200 /* AMD Elan has different frequency! */ # define CLOCK_TICK_RATE 1189200 /* AMD Elan has different frequency! */
#else #else
# define CLOCK_TICK_RATE 1193180 /* Underlying HZ */ # define CLOCK_TICK_RATE 1193182 /* Underlying HZ */
#endif #endif
#endif #endif
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
#include <asm/msr.h> #include <asm/msr.h>
#include <asm/vsyscall.h> #include <asm/vsyscall.h>
#define CLOCK_TICK_RATE 1193180 /* Underlying HZ */ #define CLOCK_TICK_RATE 1193182 /* Underlying HZ */
#define CLOCK_TICK_FACTOR 20 /* Factor of both 1000000 and CLOCK_TICK_RATE */ #define CLOCK_TICK_FACTOR 20 /* Factor of both 1000000 and CLOCK_TICK_RATE */
#define FINETUNE ((((((int)LATCH * HZ - CLOCK_TICK_RATE) << SHIFT_HZ) * \ #define FINETUNE ((((((int)LATCH * HZ - CLOCK_TICK_RATE) << SHIFT_HZ) * \
(1000000/CLOCK_TICK_FACTOR) / (CLOCK_TICK_RATE/CLOCK_TICK_FACTOR)) \ (1000000/CLOCK_TICK_FACTOR) / (CLOCK_TICK_RATE/CLOCK_TICK_FACTOR)) \
......
...@@ -77,6 +77,8 @@ struct input_absinfo { ...@@ -77,6 +77,8 @@ struct input_absinfo {
#define EVIOCRMFF _IOW('E', 0x81, int) /* Erase a force effect */ #define EVIOCRMFF _IOW('E', 0x81, int) /* Erase a force effect */
#define EVIOCGEFFECTS _IOR('E', 0x84, int) /* Report number of effects playable at the same time */ #define EVIOCGEFFECTS _IOR('E', 0x84, int) /* Report number of effects playable at the same time */
#define EVIOCGRAB _IOW('E', 0x90, int) /* Grab/Release device */
/* /*
* Event types * Event types
*/ */
...@@ -471,6 +473,11 @@ struct input_absinfo { ...@@ -471,6 +473,11 @@ struct input_absinfo {
#define KEY_TEEN 0x19e #define KEY_TEEN 0x19e
#define KEY_TWEN 0x19f #define KEY_TWEN 0x19f
#define KEY_DEL_EOL 0x1c0
#define KEY_DEL_EOS 0x1c1
#define KEY_INS_LINE 0x1c2
#define KEY_DEL_LINE 0x1c3
#define KEY_MAX 0x1ff #define KEY_MAX 0x1ff
/* /*
...@@ -523,6 +530,7 @@ struct input_absinfo { ...@@ -523,6 +530,7 @@ struct input_absinfo {
#define MSC_SERIAL 0x00 #define MSC_SERIAL 0x00
#define MSC_PULSELED 0x01 #define MSC_PULSELED 0x01
#define MSC_GESTURE 0x02
#define MSC_MAX 0x07 #define MSC_MAX 0x07
/* /*
...@@ -798,6 +806,8 @@ struct input_dev { ...@@ -798,6 +806,8 @@ struct input_dev {
int (*upload_effect)(struct input_dev *dev, struct ff_effect *effect); int (*upload_effect)(struct input_dev *dev, struct ff_effect *effect);
int (*erase_effect)(struct input_dev *dev, int effect_id); int (*erase_effect)(struct input_dev *dev, int effect_id);
struct input_handle *grab;
struct list_head h_list; struct list_head h_list;
struct list_head node; struct list_head node;
}; };
...@@ -888,6 +898,9 @@ void input_unregister_device(struct input_dev *); ...@@ -888,6 +898,9 @@ void input_unregister_device(struct input_dev *);
void input_register_handler(struct input_handler *); void input_register_handler(struct input_handler *);
void input_unregister_handler(struct input_handler *); void input_unregister_handler(struct input_handler *);
int input_grab_device(struct input_handle *);
void input_release_device(struct input_handle *);
int input_open_device(struct input_handle *); int input_open_device(struct input_handle *);
void input_close_device(struct input_handle *); void input_close_device(struct input_handle *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment