--- psmouse.ORIG 2003-04-21 20:03:25.000000000 -0400 +++ psmouse.c 2003-04-21 22:42:19.000000000 -0400 @@ -10,6 +10,11 @@ * the Free Software Foundation. */ +/* + * Initial Snaptics support by Solomon Peachy (pizza@shaftnet.org) + */ +#define SYNAPTICS + #include #include #include @@ -25,6 +30,11 @@ static int psmouse_noext; +#ifdef SYNAPTICS +static int synaptics_tap = 0; +MODULE_PARM(synaptics_tap, "1i"); +#endif + #define PSMOUSE_CMD_SETSCALE11 0x00e6 #define PSMOUSE_CMD_SETRES 0x10e8 #define PSMOUSE_CMD_GETINFO 0x03e9 @@ -33,6 +43,7 @@ #define PSMOUSE_CMD_GETID 0x02f2 #define PSMOUSE_CMD_SETRATE 0x10f3 #define PSMOUSE_CMD_ENABLE 0x00f4 +#define PSMOUSE_CMD_DISABLE 0x00f5 #define PSMOUSE_CMD_RESET_DIS 0x00f6 #define PSMOUSE_CMD_RESET_BAT 0x02ff @@ -40,6 +51,52 @@ #define PSMOUSE_RET_ACK 0xfa #define PSMOUSE_RET_NAK 0xfe +#ifdef SYNAPTICS + +/* Synaptics special queries */ +#define STP_QRY_IDENTIFY 0x00 +#define STP_QRY_READ_MODES 0x01 +#define STP_QRY_READ_CAPS 0x02 +#define STP_QRY_READ_MODEL_ID 0x03 +#define STP_QRY_READ_SN_PREFIX 0x06 +#define STP_QRY_READ_SN_SUFFIX 0x07 +#define STP_QRY_READ_RES 0x08 + +/* Model ID bits */ +#define STP_INFO_ROT180(id) (((id) & 0x800000) >> 23) +#define STP_INFO_PORTRAIT(id) (((id) & 0x400000) >> 22) +#define STP_INFO_SENSOR(id) (((id) & 0x3F0000) >> 16) +#define STP_INFO_HARDWARE(id) (((id) & 0x00FE00) >> 9) +#define STP_INFO_NEW_ABS(id) (((id) & 0x000080) >> 7) +#define STP_INFO_CAP_PEN(id) (((id) & 0x000040) >> 6) +#define STP_INFO_SIMPLE_CMD(id) (((id) & 0x000020) >> 5) +#define STP_INFO_GEOMETRY(id) ((id) & 0x00000F) + +#define STP_SET_MODE_ABSOLUTE(m, a) (((m) &~ 0x80) | ((a) << 7)) +#define STP_SET_MODE_RATE(m, a) (((m) &~ 0x40) | ((a) << 6)) +#define STP_SET_MODE_SLEEP(m, a) (((m) &~ 0x08) | ((a) << 3)) +#define STP_SET_MODE_GESTURE(m, a) (((m) &~ 0x04) | ((!a) << 2)) +#define STP_SET_MODE_PACKSIZE(m, a) (((m) &~ 0x02) | ((a) << 1)) +#define STP_SET_MODE_WMODE(m, a) (((m) &~ 0x01) | (a)) + +#define STP_SET_OMODE_CORNER(m, a) (((m) &~ 0x80000000) | ((a) << 31)) +#define STP_SET_OMODE_Z_THRESH(m, a) (((m) &~ 0x70000000) | ((a) << 28)) +#define STP_SET_OMODE_TAP_MODE(m, a) (((m) &~ 0x0C000000) | ((a) << 26)) +#define STP_SET_OMODE_EDGE_MOTN(m, a) (((m) &~ 0x03000000) | ((a) << 24)) +#define STP_SET_OMODE_ABSOLUTE(m, a) (((m) &~ 0x00800000) | ((a) << 23)) +#define STP_SET_OMODE_RATE(m, a) (((m) &~ 0x00400000) | ((a) << 22)) +#define STP_SET_OMODE_BAUD(m, a) (((m) &~ 0x00080000) | ((a) << 19)) +#define STP_SET_OMODE_3_BUTTON(m, a) (((m) &~ 0x00040000) | ((a) << 18)) +#define STP_SET_OMODE_MIDDLE(m, a) (((m) &~ 0x00020000) | ((a) << 17)) +#define STP_SET_OMODE_HOP(m, a) (((m) &~ 0x00010000) | ((a) << 16)) +#define STP_SET_OMODE_RIGHT_MGN(m, a) (((m) &~ 0x0000F000) | ((a) << 12)) +#define STP_SET_OMODE_LEFT_MGN(m, a) (((m) &~ 0x00000F00) | ((a) << 8)) +#define STP_SET_OMODE_TOP_MGN(m, a) (((m) &~ 0x000000F0) | ((a) << 4)) +#define STP_SET_OMODE_BOTTOM_MGN(m, a) (((m) &~ 0x0000000F) | (a)) +#define QUAD_MODE_BYTE 0x0302 + +#endif + struct psmouse { struct input_dev dev; struct serio *serio; @@ -57,8 +114,22 @@ char error; char devname[64]; char phys[32]; + +#ifdef SYNAPTICS + unsigned int fw_version; + unsigned int single_mode_byte; + unsigned int model_id; + unsigned int modes; + unsigned int caps; +#endif }; +#ifdef SYNAPTICS +static void synaptics_command(struct psmouse *psmouse, unsigned char cmd); +static void synaptics_set_mode(struct psmouse *psmouse, unsigned int mode); +unsigned int synaptics_get_mode(struct psmouse *psmouse); +#endif + #define PSMOUSE_PS2 1 #define PSMOUSE_PS2PP 2 #define PSMOUSE_PS2TPP 3 @@ -345,6 +416,54 @@ thing up. */ psmouse->vendor = "Synaptics"; psmouse->name = "TouchPad"; + +#ifdef SYNAPTICS + param[0] = 0; + synaptics_command(psmouse, STP_QRY_IDENTIFY); + psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO); + psmouse->fw_version = ((param[2] & 0x0f) << 8) | param[0]; + + synaptics_command(psmouse, STP_QRY_READ_MODEL_ID); + psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO); + + psmouse->model_id = ((param[1] & 0x1) ? 0x1 : + (((unsigned int) param[0] << 16) | + ((unsigned int) param[1] << 8) | + ((unsigned int) param[2]))); + + psmouse->single_mode_byte = STP_INFO_SIMPLE_CMD (psmouse->model_id); + /* Fetch capabilities */ + synaptics_command(psmouse, STP_QRY_READ_MODEL_ID); + psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO); + psmouse->caps = (((unsigned int) param[0] << 8) | + (unsigned int) param[2]); + + printk(KERN_INFO "Found Synaptics Touchpad rev %d.%d\n", + (psmouse->fw_version >> 8) & 0x0f, + (psmouse->fw_version & 0xff)); + + /* pull the modes down */ + psmouse->modes = synaptics_get_mode(psmouse); + + /* Now, disable tap-to-click and enable high rate. */ + + if (psmouse->single_mode_byte) { + psmouse->modes = STP_SET_MODE_GESTURE(psmouse->modes, synaptics_tap); + psmouse->modes = STP_SET_MODE_RATE(psmouse->modes, 1); + + synaptics_set_mode(psmouse, psmouse->modes); + } else { + psmouse->modes = STP_SET_OMODE_TAP_MODE(psmouse->modes, synaptics_tap); + psmouse->modes = STP_SET_OMODE_RATE(psmouse->modes, 1); + + synaptics_set_mode(psmouse, psmouse->modes); + } + + psmouse->modes = synaptics_get_mode(psmouse); +#else + printk(KERN_INFO "Found Synaptics touchpad, support disabled\n"); +#endif + return PSMOUSE_PS2; } @@ -682,5 +801,78 @@ serio_unregister_device(&psmouse_dev); } +#ifdef SYNAPTICS +void synaptics_command(struct psmouse *psmouse, unsigned char cmd) +{ + unsigned char param[4]; + + param[0] = (cmd & 0xC0) >> 6; + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); + param[0] = (cmd & 0x30) >> 4; + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); + param[0] = (cmd & 0x0C) >> 2; + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); + param[0] = (cmd & 0x03); + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); +} + +void synaptics_set_mode(struct psmouse *psmouse, unsigned int mode) +{ + unsigned char param[4]; +// printk(KERN_INFO "Synaptics set mode: %08x\n", mode); + + psmouse_command(psmouse, param, PSMOUSE_CMD_DISABLE); + + if (psmouse->single_mode_byte) { + synaptics_command(psmouse, mode & 0xff); + param[0] = 20; + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE); + } else { + synaptics_command(psmouse, (mode >> 24) & 0xff); + param[0] = 10; + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE); + synaptics_command(psmouse, (mode >> 16) & 0xff); + param[0] = 20; + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE); + if (psmouse->fw_version < QUAD_MODE_BYTE) { + synaptics_command(psmouse, (mode >> 8) & 0xff); + param[0] = 40; + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE); + synaptics_command(psmouse, mode & 0xff); + param[0] = 60; + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE); + } + } + + psmouse_command(psmouse, param, PSMOUSE_CMD_ENABLE); +} + +unsigned int synaptics_get_mode(struct psmouse *psmouse) +{ + unsigned char param[4]; + unsigned int retval = 0; + + synaptics_command(psmouse, STP_QRY_READ_MODES); + psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO); + + param[1] = 0; + + if (psmouse->single_mode_byte) { + retval = param[2]; + } else { + retval = ((param[0] << 24) | + (param[2] << 16)); + + if (psmouse->fw_version < QUAD_MODE_BYTE) { + synaptics_command(psmouse, STP_QRY_READ_CAPS); + psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO); + retval |= ((param[0] << 8) | + (param[2])); + } + } + return retval; +} +#endif + module_init(psmouse_init); module_exit(psmouse_exit);