Commit 2e92db0d authored by Peter Osterlund's avatar Peter Osterlund Committed by Vojtech Pavlik

Input: Big Synaptics update:

	Restore synaptics pad mode on module unload.
	Support Synaptics touchpads with multiple buttons.
	Make Synaptics touchpad support optional.
	Add passthrough support for Synaptics touchpads. [Dmitry]
	Add support for old Synaptics protocol.
	Set mode byte correctly for old Synaptics pads.
	Fix multibutton support of Synaptics pads.
parent 7443bce4
......@@ -788,6 +788,10 @@ running once the system is up.
psmouse_noext [HW,MOUSE] Disable probing for PS2 mouse protocol extensions
psmouse_resetafter=
[HW,MOUSE] Try to reset Synaptics Touchpad after so many
bad packets (0 = never).
pss= [HW,OSS] Personal Sound System (ECHO ESC614)
Format: <io>,<mss_io>,<mss_irq>,<mss_dma>,<mpu_io>,<mpu_irq>
......
......@@ -19,9 +19,7 @@ config MOUSE_PS2
Say Y here if you have a PS/2 mouse connected to your system. This
includes the standard 2 or 3-button PS/2 mouse, as well as PS/2
mice with wheels and extra buttons, Microsoft, Logitech or Genius
compatible. Support for Synaptics TouchPads is also included.
For Synaptics TouchPad support in XFree86 you'll need this XFree86
driver: http://w1.894.telia.com/~u89404340/touchpad/index.html
compatible.
If unsure, say Y.
......@@ -30,6 +28,22 @@ config MOUSE_PS2
The module will be called psmouse. If you want to compile it as a
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://w1.894.telia.com/~u89404340/touchpad/index.html
The gpm program is not yet able to interpret the data from this
driver, so if you need to use the touchpad in the console, you have to
say N for now.
config MOUSE_SERIAL
tristate "Serial mouse"
depends on INPUT && INPUT_MOUSE && SERIO
......
......@@ -29,6 +29,8 @@ MODULE_PARM(psmouse_resolution, "i");
MODULE_PARM_DESC(psmouse_resolution, "Resolution, in dpi.");
MODULE_PARM(psmouse_smartscroll, "i");
MODULE_PARM_DESC(psmouse_smartscroll, "Logitech Smartscroll autorepeat, 1 = enabled (default), 0 = disabled.");
MODULE_PARM(psmouse_resetafter, "i");
MODULE_PARM_DESC(psmouse_resetafter, "Reset Synaptics Touchpad after so many bad packets (0 = never).");
MODULE_LICENSE("GPL");
#define PSMOUSE_LOGITECH_SMARTSCROLL 1
......@@ -36,11 +38,12 @@ MODULE_LICENSE("GPL");
static int psmouse_noext;
int psmouse_resolution;
int psmouse_smartscroll = PSMOUSE_LOGITECH_SMARTSCROLL;
unsigned int psmouse_resetafter;
static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "PS2T++", "GenPS/2", "ImPS/2", "ImExPS/2", "Synaptics"};
/*
* psmouse_process_packet() anlyzes the PS/2 mouse packet contents and
* psmouse_process_packet() analyzes the PS/2 mouse packet contents and
* reports relevant events to the input module.
*/
......@@ -108,6 +111,9 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
{
struct psmouse *psmouse = serio->private;
if (psmouse->state == PSMOUSE_IGNORE)
goto out;
if (psmouse->acking) {
switch (data) {
case PSMOUSE_RET_ACK:
......@@ -132,31 +138,46 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
}
if (psmouse->pktcnt && time_after(jiffies, psmouse->last + HZ/2)) {
printk(KERN_WARNING "psmouse.c: Lost synchronization, throwing %d bytes away.\n", psmouse->pktcnt);
printk(KERN_WARNING "psmouse.c: %s at %s lost synchronization, throwing %d bytes away.\n",
psmouse->name, psmouse->phys, psmouse->pktcnt);
psmouse->pktcnt = 0;
}
psmouse->last = jiffies;
psmouse->packet[psmouse->pktcnt++] = data;
if (psmouse->pktcnt == 3 + (psmouse->type >= PSMOUSE_GENPS)) {
psmouse_process_packet(psmouse, regs);
psmouse->pktcnt = 0;
goto out;
if (psmouse->packet[0] == PSMOUSE_RET_BAT) {
if (psmouse->pktcnt == 1)
goto out;
if (psmouse->pktcnt == 2) {
if (psmouse->packet[1] == PSMOUSE_RET_ID) {
psmouse->state = PSMOUSE_IGNORE;
serio_rescan(serio);
goto out;
}
if (psmouse->type == PSMOUSE_SYNAPTICS) {
/* neither 0xAA nor 0x00 are valid first bytes
* for a packet in absolute mode
*/
psmouse->pktcnt = 0;
goto out;
}
}
}
if (psmouse->pktcnt == 1 && psmouse->type == PSMOUSE_SYNAPTICS) {
if (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) {
serio_rescan(serio);
if (psmouse->pktcnt == 3 + (psmouse->type >= PSMOUSE_GENPS)) {
psmouse_process_packet(psmouse, regs);
psmouse->pktcnt = 0;
goto out;
}
out:
......@@ -227,7 +248,7 @@ int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command)
for (i = 0; i < receive; i++)
param[i] = psmouse->cmdbuf[(receive - 1) - i];
if (psmouse->cmdcnt)
if (psmouse->cmdcnt)
return (psmouse->cmdcnt = 0) - 1;
return 0;
......@@ -450,14 +471,18 @@ static void psmouse_initialize(struct psmouse *psmouse)
*/
psmouse_command(psmouse, param, PSMOUSE_CMD_SETSTREAM);
}
/*
* Last, we enable the mouse so that we get reports from it.
* psmouse_activate() enables the mouse so that we get motion reports from it.
*/
static void psmouse_activate(struct psmouse *psmouse)
{
if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_ENABLE))
printk(KERN_WARNING "psmouse.c: Failed to enable mouse on %s\n", psmouse->serio->phys);
psmouse->state = PSMOUSE_ACTIVATED;
}
/*
......@@ -478,8 +503,9 @@ static void psmouse_cleanup(struct serio *serio)
static void psmouse_disconnect(struct serio *serio)
{
struct psmouse *psmouse = serio->private;
if (psmouse->type == PSMOUSE_SYNAPTICS)
synaptics_disconnect(psmouse);
psmouse->state = PSMOUSE_IGNORE;
synaptics_disconnect(psmouse);
input_unregister_device(&psmouse->dev);
serio_close(serio);
kfree(psmouse);
......@@ -494,7 +520,8 @@ static void psmouse_connect(struct serio *serio, struct serio_dev *dev)
{
struct psmouse *psmouse;
if ((serio->type & SERIO_TYPE) != SERIO_8042)
if ((serio->type & SERIO_TYPE) != SERIO_8042 &&
(serio->type & SERIO_TYPE) != SERIO_PS_PSTHRU)
return;
if (!(psmouse = kmalloc(sizeof(struct psmouse), GFP_KERNEL)))
......@@ -507,6 +534,7 @@ static void psmouse_connect(struct serio *serio, struct serio_dev *dev)
psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
psmouse->state = PSMOUSE_NEW_DEVICE;
psmouse->serio = serio;
psmouse->dev.private = psmouse;
......@@ -540,6 +568,10 @@ static void psmouse_connect(struct serio *serio, struct serio_dev *dev)
printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys);
psmouse_initialize(psmouse);
synaptics_pt_init(psmouse);
psmouse_activate(psmouse);
}
static struct serio_dev psmouse_dev = {
......@@ -568,9 +600,16 @@ static int __init psmouse_smartscroll_setup(char *str)
return 1;
}
static int __init psmouse_resetafter_setup(char *str)
{
get_option(&str, &psmouse_resetafter);
return 1;
}
__setup("psmouse_noext", psmouse_noext_setup);
__setup("psmouse_resolution=", psmouse_resolution_setup);
__setup("psmouse_smartscroll=", psmouse_smartscroll_setup);
__setup("psmouse_resetafter=", psmouse_resetafter_setup);
#endif
......
......@@ -13,9 +13,15 @@
#define PSMOUSE_CMD_RESET_BAT 0x02ff
#define PSMOUSE_RET_BAT 0xaa
#define PSMOUSE_RET_ID 0x00
#define PSMOUSE_RET_ACK 0xfa
#define PSMOUSE_RET_NAK 0xfe
/* psmouse states */
#define PSMOUSE_NEW_DEVICE 0
#define PSMOUSE_ACTIVATED 1
#define PSMOUSE_IGNORE 2
struct psmouse {
void *private;
struct input_dev dev;
......@@ -29,6 +35,7 @@ struct psmouse {
unsigned char type;
unsigned char model;
unsigned long last;
unsigned char state;
char acking;
volatile char ack;
char error;
......@@ -36,16 +43,17 @@ struct psmouse {
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
#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);
extern int psmouse_smartscroll;
extern unsigned int psmouse_resetafter;
#endif /* _PSMOUSE_H */
This diff is collapsed.
......@@ -12,6 +12,7 @@
extern void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs);
extern int synaptics_init(struct psmouse *psmouse);
extern int synaptics_pt_init(struct psmouse *psmouse);
extern void synaptics_disconnect(struct psmouse *psmouse);
/* synaptics queries */
......@@ -22,12 +23,14 @@ extern void synaptics_disconnect(struct psmouse *psmouse);
#define SYN_QUE_SERIAL_NUMBER_PREFIX 0x06
#define SYN_QUE_SERIAL_NUMBER_SUFFIX 0x07
#define SYN_QUE_RESOLUTION 0x08
#define SYN_QUE_EXT_CAPAB 0x09
/* 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_FOUR_BYTE_CLIENT (1 << 1)
#define SYN_BIT_W_MODE (1 << 0)
/* synaptics model ID bits */
......@@ -42,11 +45,14 @@ extern void synaptics_disconnect(struct psmouse *psmouse);
/* synaptics capability bits */
#define SYN_CAP_EXTENDED(c) ((c) & (1 << 23))
#define SYN_CAP_PASS_THROUGH(c) ((c) & (1 << 7))
#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)
#define SYN_EXT_CAP_REQUESTS(c) ((((c) & 0x700000) >> 20) == 1)
#define SYN_CAP_MULTI_BUTTON_NO(ec) (((ec) & 0x00f000) >> 12)
/* synaptics modes query bits */
#define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7))
......@@ -62,6 +68,10 @@ extern void synaptics_disconnect(struct psmouse *psmouse);
#define SYN_ID_MINOR(i) (((i) >> 16) & 0xff)
#define SYN_ID_IS_SYNAPTICS(i) ((((i) >> 8) & 0xff) == 0x47)
/* synaptics special commands */
#define SYN_PS_SET_MODE2 0x14
#define SYN_PS_CLIENT_CMD 0x28
/*
* A structure to describe the state of the touchpad hardware (buttons and pad)
*/
......@@ -75,21 +85,28 @@ struct synaptics_hw_state {
int right;
int up;
int down;
int b0;
int b1;
int b2;
int b3;
int b4;
int b5;
int b6;
int b7;
};
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 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;
unsigned int out_of_sync; /* # of packets out of sync */
int old_w; /* Previous w value */
struct serio *ptport; /* pass-through port */
};
#endif /* _SYNAPTICS_H */
......@@ -49,7 +49,9 @@ MODULE_LICENSE("GPL");
EXPORT_SYMBOL(serio_interrupt);
EXPORT_SYMBOL(serio_register_port);
EXPORT_SYMBOL(serio_register_slave_port);
EXPORT_SYMBOL(serio_unregister_port);
EXPORT_SYMBOL(serio_unregister_slave_port);
EXPORT_SYMBOL(serio_register_device);
EXPORT_SYMBOL(serio_unregister_device);
EXPORT_SYMBOL(serio_open);
......@@ -166,6 +168,17 @@ void serio_register_port(struct serio *serio)
up(&serio_sem);
}
/*
* Same as serio_register_port but does not try to acquire serio_sem.
* Should be used when registering a serio from other input device's
* connect() function.
*/
void serio_register_slave_port(struct serio *serio)
{
list_add_tail(&serio->node, &serio_list);
serio_find_dev(serio);
}
void serio_unregister_port(struct serio *serio)
{
down(&serio_sem);
......@@ -175,6 +188,18 @@ void serio_unregister_port(struct serio *serio)
up(&serio_sem);
}
/*
* Same as serio_unregister_port but does not try to acquire serio_sem.
* Should be used when unregistering a serio from other input device's
* disconnect() function.
*/
void serio_unregister_slave_port(struct serio *serio)
{
list_del_init(&serio->node);
if (serio->dev && serio->dev->disconnect)
serio->dev->disconnect(serio);
}
void serio_register_device(struct serio_dev *dev)
{
struct serio *serio;
......
......@@ -65,7 +65,9 @@ void serio_rescan(struct serio *serio);
irqreturn_t serio_interrupt(struct serio *serio, unsigned char data, unsigned int flags, struct pt_regs *regs);
void serio_register_port(struct serio *serio);
void serio_register_slave_port(struct serio *serio);
void serio_unregister_port(struct serio *serio);
void serio_unregister_slave_port(struct serio *serio);
void serio_register_device(struct serio_dev *dev);
void serio_unregister_device(struct serio_dev *dev);
......@@ -104,6 +106,7 @@ static __inline__ void serio_cleanup(struct serio *serio)
#define SERIO_RS232 0x02000000UL
#define SERIO_HIL_MLC 0x03000000UL
#define SERIO_PC9800 0x04000000UL
#define SERIO_PS_PSTHRU 0x05000000UL
#define SERIO_PROTO 0xFFUL
#define SERIO_MSC 0x01
......
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