ChangeSet@1.1907, 2004-04-23 02:22:22-05:00, dtor_core@ameritech.net ALPS driver Makefile | 2 alps.c | 185 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ alps.h | 17 +++++ psmouse-base.c | 19 +++++ psmouse.h | 3 5 files changed, 224 insertions(+), 2 deletions(-) diff -Nru a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile --- a/drivers/input/mouse/Makefile Fri Apr 23 02:24:19 2004 +++ b/drivers/input/mouse/Makefile Fri Apr 23 02:24:19 2004 @@ -15,4 +15,4 @@ obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o -psmouse-objs := psmouse-base.o logips2pp.o synaptics.o +psmouse-objs := psmouse-base.o alps.o logips2pp.o synaptics.o diff -Nru a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/input/mouse/alps.c Fri Apr 23 02:24:19 2004 @@ -0,0 +1,185 @@ +/* + * ALPS touchpad PS/2 mouse driver + * + * Copyright (c) 2003 Neil Brown + * Copyright (c) 2003 Peter Osterlund + * Copyright (c) 2004 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 +#include + +#include "psmouse.h" +#include "alps.h" + +/* + * ALPS abolute Mode + * byte 0: 1 1 1 1 1 mid0 rig0 lef0 + * byte 1: 0 x6 x5 x4 x3 x2 x1 x0 + * byte 2: 0 x10 x9 x8 x7 up1 fin ges + * byte 3: 0 y9 y8 y7 1 mid1 rig1 lef1 + * byte 4: 0 y6 y5 y4 y3 y2 y1 y0 + * byte 5: 0 z6 z5 z4 z3 z2 z1 z0 + * + * On a dualpoint, {mid,rig,lef}0 are the stick, 1 are the pad. + * We just 'or' them together for now. + * + * We used to send 'ges'tures as BTN_TOUCH but this made it impossible + * to disable tap events in the synaptics driver since the driver + * was unable to distinguish a gesture tap from an actual button click. + * A tap gesture now creates an emulated touch that the synaptics + * driver can interpret as a tap event, if MaxTapTime=0 and + * MaxTapMove=0 then the driver will ignore taps. + * + * The touchpad on an 'Acer Aspire' has 4 buttons: + * left,right,up,down. + * This device always sets {mid,rig,lef}0 to 1 and + * reflects left,right,down,up in lef1,rig1,mid1,up1. + */ + +static void alps_process_packet(struct psmouse *psmouse, struct pt_regs *regs) +{ + unsigned char *packet = psmouse->packet; + struct input_dev *dev = &psmouse->dev; + int x, y, z; + int left = 0, right = 0, middle = 0; + + input_regs(dev, regs); + + x = (packet[1] & 0x7f) | ((packet[2] & 0x78)<<(7-3)); + y = (packet[4] & 0x7f) | ((packet[3] & 0x70)<<(7-4)); + z = packet[5]; + + if (z > 30) input_report_key(dev, BTN_TOUCH, 1); + if (z < 25) input_report_key(dev, BTN_TOUCH, 0); + + if (z > 0) { + input_report_abs(dev, ABS_X, x); + input_report_abs(dev, ABS_Y, y); + } + input_report_abs(dev, ABS_PRESSURE, z); + input_report_key(dev, BTN_TOOL_FINGER, z > 0); + + left |= (packet[2] ) & 1; + left |= (packet[3] ) & 1; + right |= (packet[3] >> 1) & 1; + if (packet[0] == 0xff) { + int back = (packet[3] >> 2) & 1; + int forward = (packet[2] >> 2) & 1; + if (back && forward) { + middle = 1; + back = 0; + forward = 0; + } + input_report_key(dev, BTN_BACK, back); + input_report_key(dev, BTN_FORWARD, forward); + } else { + left |= (packet[0] ) & 1; + right |= (packet[0] >> 1) & 1; + middle |= (packet[0] >> 2) & 1; + middle |= (packet[3] >> 2) & 1; + } + + input_report_key(dev, BTN_LEFT, left); + input_report_key(dev, BTN_RIGHT, right); + input_report_key(dev, BTN_MIDDLE, middle); + + input_sync(dev); +} + +static psmouse_ret_t alps_process_byte(struct psmouse *psmouse, struct pt_regs *regs) +{ + /* ALPS absolute mode packets start with 0b11111mrl */ + if ((psmouse->packet[0] & 0xf8) != 0xf8) + return PSMOUSE_BAD_DATA; + + /* Bytes 2 - 6 should have 0 in the highest bit */ + if (psmouse->pktcnt > 1 && psmouse->pktcnt <= 6 && + (psmouse->packet[psmouse->pktcnt] & 0x80)) + return PSMOUSE_BAD_DATA; + + if (psmouse->pktcnt == 6) { + alps_process_packet(psmouse, regs); + return PSMOUSE_FULL_PACKET; + } + + return PSMOUSE_GOOD_DATA; +} + +int alps_detect(struct psmouse *psmouse) +{ + unsigned char param[4]; + + /* First try "E6 report". ALPS should return 0x00 0x00 0x0a */ + param[0] = 0; + if (psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES) || + psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11) || + psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11) || + psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11)) + return 0; + + param[0] = param[1] = param[2] = 0xff; + if (psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO)) + return 0; + + printk(KERN_INFO "alps.c: E6 report: %2.2x %2.2x %2.2x\n", + param[0], param[1], param[2]); + + if (param[0] != 0x00 || param[1] != 0x00 || param[2] != 0x0a) + return 0; + + /* Now try "E7 report". ALPS should return 0x33 in byte 1 */ + param[0] = 0; + if (psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES) || + psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE21) || + psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE21) || + psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE21)) + return 0; + + param[0] = param[1] = param[2] = 0xff; + if (psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO)) + return 0; + + printk(KERN_INFO "alps.c: E7 report: %2.2x %2.2x %2.2x\n", + param[0], param[1], param[2]); + + return param[0] != 0x33; +} + +static void alps_disconnect(struct psmouse *psmouse) +{ + psmouse_reset(psmouse); +} + +int alps_init(struct psmouse *psmouse) +{ + /* Try ALPS magic knock */ + if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_DISABLE) || + psmouse_command(psmouse, NULL, PSMOUSE_CMD_DISABLE) || + psmouse_command(psmouse, NULL, PSMOUSE_CMD_DISABLE) || + psmouse_command(psmouse, NULL, PSMOUSE_CMD_DISABLE)) + return -1; + + psmouse->dev.evbit[LONG(EV_REL)] &= ~BIT(EV_REL); + psmouse->dev.relbit[LONG(REL_X)] &= ~BIT(REL_X); + psmouse->dev.relbit[LONG(REL_X)] &= ~BIT(REL_X); + + psmouse->dev.evbit[LONG(EV_ABS)] |= BIT(EV_ABS); + input_set_abs_params(&psmouse->dev, ABS_X, 0, 0, 0, 0); + input_set_abs_params(&psmouse->dev, ABS_Y, 0, 0, 0, 0); + input_set_abs_params(&psmouse->dev, ABS_PRESSURE, 0, 127, 0, 0); + + psmouse->dev.keybit[LONG(BTN_TOUCH)] |= BIT(BTN_TOUCH); + psmouse->dev.keybit[LONG(BTN_TOOL_FINGER)] |= BIT(BTN_TOOL_FINGER); + psmouse->dev.keybit[LONG(BTN_FORWARD)] |= BIT(BTN_FORWARD); + psmouse->dev.keybit[LONG(BTN_BACK)] |= BIT(BTN_BACK); + + psmouse->protocol_handler = alps_process_byte; + psmouse->disconnect = alps_disconnect; + + return 0; +} diff -Nru a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/input/mouse/alps.h Fri Apr 23 02:24:19 2004 @@ -0,0 +1,17 @@ +/* + * ALPS touchpad PS/2 mouse driver + * + * Copyright (c) 2003 Peter Osterlund + * + * 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 _ALPS_H +#define _ALPS_H + +int alps_detect(struct psmouse *psmouse); +int alps_init(struct psmouse *psmouse); + +#endif diff -Nru a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c --- a/drivers/input/mouse/psmouse-base.c Fri Apr 23 02:24:19 2004 +++ b/drivers/input/mouse/psmouse-base.c Fri Apr 23 02:24:19 2004 @@ -2,6 +2,7 @@ * PS/2 mouse driver * * Copyright (c) 1999-2002 Vojtech Pavlik + * Copyright (c) 2003-2004 Dmitry Torokhov */ /* @@ -21,6 +22,7 @@ #include "psmouse.h" #include "synaptics.h" #include "logips2pp.h" +#include "alps.h" MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("PS/2 mouse driver"); @@ -53,7 +55,7 @@ __obsolete_setup("psmouse_resetafter="); __obsolete_setup("psmouse_rate="); -static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "PS2T++", "GenPS/2", "ImPS/2", "ImExPS/2", "SynPS/2"}; +static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "PS2T++", "GenPS/2", "ImPS/2", "ImExPS/2", "SynPS/2", "AlpsPS/2" }; /* * psmouse_process_byte() analyzes the PS/2 data stream and reports @@ -440,6 +442,21 @@ * Make sure that touchpad is in relative mode, gestures (taps) are enabled */ synaptics_reset(psmouse); + } + +/* + * Try ALPS TouchPad + */ + if (max_proto > PSMOUSE_PS2 && alps_detect(psmouse)) { + + if (set_properties) { + psmouse->vendor = "ALPS"; + psmouse->name = "TouchPad"; + } + + if (max_proto > PSMOUSE_IMEX) + if (alps_detect(psmouse) == 0) + return PSMOUSE_ALPS; } if (max_proto > PSMOUSE_IMEX && genius_detect(psmouse)) { diff -Nru a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h --- a/drivers/input/mouse/psmouse.h Fri Apr 23 02:24:19 2004 +++ b/drivers/input/mouse/psmouse.h Fri Apr 23 02:24:19 2004 @@ -2,6 +2,7 @@ #define _PSMOUSE_H #define PSMOUSE_CMD_SETSCALE11 0x00e6 +#define PSMOUSE_CMD_SETSCALE21 0x00e7 #define PSMOUSE_CMD_SETRES 0x10e8 #define PSMOUSE_CMD_GETINFO 0x03e9 #define PSMOUSE_CMD_SETSTREAM 0x00ea @@ -9,6 +10,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 @@ -72,6 +74,7 @@ #define PSMOUSE_IMPS 5 #define PSMOUSE_IMEX 6 #define PSMOUSE_SYNAPTICS 7 +#define PSMOUSE_ALPS 8 int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command); int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command); - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/