diff options
author | Peter Osterlund <petero2@telia.com> | 2004-04-22 23:32:25 +0200 |
---|---|---|
committer | Peter Osterlund <petero2@telia.com> | 2006-04-09 04:02:14 +0200 |
commit | a4ba6e264a52d475ccecf381e9b9acc63190d4f4 (patch) | |
tree | b012ab81692c2b4b424d9b48b12162b03aa7efb2 | |
parent | f1146f67f7e377d1f6f32a26bb833fc2b0ed2ed6 (diff) |
Added (untested) support for ALPS touchpads using the 2.4
linux kernel.
-rw-r--r-- | Makefile | 7 | ||||
-rw-r--r-- | alpscomm.c | 187 | ||||
-rw-r--r-- | alpscomm.h | 27 | ||||
-rw-r--r-- | ps2comm.c | 4 | ||||
-rw-r--r-- | ps2comm.h | 3 | ||||
-rw-r--r-- | synaptics.c | 5 | ||||
-rw-r--r-- | synproto.h | 4 |
7 files changed, 231 insertions, 6 deletions
@@ -52,8 +52,8 @@ CC = gcc LDCOMBINEFLAGS = -r -SRCS = synaptics.c ps2comm.c eventcomm.c psmcomm.c -OBJS = synaptics.o ps2comm.o eventcomm.o psmcomm.o +SRCS = synaptics.c ps2comm.c eventcomm.c psmcomm.c alpscomm.c +OBJS = synaptics.o ps2comm.o eventcomm.o psmcomm.o alpscomm.o .c.o: $(RM) $@ @@ -100,6 +100,7 @@ synaptics.o : synaptics.h synproto.h Makefile ps2comm.o : ps2comm.h synproto.h synaptics.h eventcomm.o : eventcomm.h linux_input.h synproto.h synaptics.h psmcomm.o : freebsd_mouse.h psmcomm.h synproto.h synaptics.h ps2comm.h +alpscomm.o : alpscomm.h ps2comm.h synproto.h synaptics.h synclient.o : synaptics.h syndaemon.o : synaptics.h @@ -117,7 +118,7 @@ distribution : synaptics-$(VERSION).tar.bz2 ALLFILES = COMPATIBILITY FILES INSTALL INSTALL.DE INSTALL.FR LICENSE Makefile \ NEWS README README.alps TODO Xincludes/ alps.patch linux_input.h \ pc_keyb.c.diff.2.4.3 \ - synproto.h ps2comm.c ps2comm.h eventcomm.c eventcomm.h \ + synproto.h ps2comm.c ps2comm.h eventcomm.c eventcomm.h alpscomm.c alpscomm.h \ psmcomm.c psmcomm.h freebsd_mouse.h \ synaptics.c synaptics.h synaptics.spec \ synclient.c syndaemon.c diff --git a/alpscomm.c b/alpscomm.c new file mode 100644 index 0000000..34cacf6 --- /dev/null +++ b/alpscomm.c @@ -0,0 +1,187 @@ +/* Copyright (C) 2001 Stefan Gmeiner <riddlebox@freesurf.ch> + * + * Copyright (c) 2003 Neil Brown <neilb@cse.unsw.edu.au> + * Copyright (c) 2003-2004 Peter Osterlund <petero2@telia.com> + * + * 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. + * + */ + +#include "alpscomm.h" +#include "synproto.h" +#include "synaptics.h" +#include <xf86.h> + +/* + * send the ALPSinit sequence, ie 4 consecutive "disable"s before the "enable" + */ +static void +ALPS_initialize(int fd) +{ + ps2_synaptics_disable_device(fd); + ps2_synaptics_disable_device(fd); + ps2_synaptics_disable_device(fd); + ps2_synaptics_disable_device(fd); + ps2_synaptics_enable_device(fd); +} + +static void +ALPSDeviceOnHook(LocalDevicePtr local) +{ +} + +static void +ALPSDeviceOffHook(LocalDevicePtr local) +{ +} + +static Bool +ALPSQueryHardware(LocalDevicePtr local, struct SynapticsHwInfo *synhw) +{ + ALPS_initialize(local->fd); + return TRUE; +} + +static Bool +ALPS_packet_ok(struct CommData *comm) +{ + /* ALPS absolute mode packets start with 0b11111mrl */ + if ((comm->protoBuf[0] & 0xf8) == 0xf8) + return TRUE; + return FALSE; +} + +static Bool +ALPS_get_packet(struct CommData *comm) +{ + int c; + + while ((c = XisbRead(comm->buffer)) >= 0) { + unsigned char u = (unsigned char)c; + + comm->protoBuf[comm->protoBufTail++] = u; + + /* Check that we have a valid packet. If not, we are out of sync, + so we throw away the first byte in the packet.*/ + if (comm->protoBufTail >= 6) { + if (!ALPS_packet_ok(comm)) { + int i; + for (i = 0; i < comm->protoBufTail - 1; i++) + comm->protoBuf[i] = comm->protoBuf[i + 1]; + comm->protoBufTail--; + } + } + + if (comm->protoBufTail >= 6) { /* Full packet received */ + comm->protoBufTail = 0; + return TRUE; + } + } + + return FALSE; +} + +/* + * 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. + * + * 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(unsigned char *packet, struct SynapticsHwState *hw) +{ + int x, y, z; + int left = 0, right = 0, middle = 0; + + x = (packet[1] & 0x7f) | ((packet[2] & 0x78)<<(7-3)); + y = (packet[4] & 0x7f) | ((packet[3] & 0x70)<<(7-4)); + z = packet[5]; + + if (z > 0) { + hw->x = x; + hw->y = y; + } + hw->z = z; + hw->numFingers = (z > 0) ? 1 : 0; + hw->fingerWidth = 5; + + 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; + } + hw->down = back; + hw->up = forward; + } else { + left |= (packet[0] ) & 1; + right |= (packet[0] >> 1) & 1; + middle |= (packet[0] >> 2) & 1; + middle |= (packet[3] >> 2) & 1; + } + + hw->left = left; + hw->right = right; + hw->middle = middle; +} + +static Bool +ALPSReadHwState(LocalDevicePtr local, struct SynapticsHwInfo *synhw, + struct SynapticsProtocolOperations *proto_ops, + struct CommData *comm, struct SynapticsHwState *hwRet) +{ + unsigned char *buf = comm->protoBuf; + struct SynapticsHwState *hw = &(comm->hwState); + + if (!ALPS_get_packet(comm)) + return FALSE; + + memset(hw, 0, sizeof(*hw)); + + ALPS_process_packet(buf, hw); + + *hwRet = *hw; + return TRUE; +} + +static Bool +ALPSAutoDevProbe(LocalDevicePtr local) +{ + return FALSE; +} + +struct SynapticsProtocolOperations alps_proto_operations = { + ALPSDeviceOnHook, + ALPSDeviceOffHook, + ALPSQueryHardware, + ALPSReadHwState, + ALPSAutoDevProbe +}; diff --git a/alpscomm.h b/alpscomm.h new file mode 100644 index 0000000..52ec8ba --- /dev/null +++ b/alpscomm.h @@ -0,0 +1,27 @@ +/* + * ALPS touchpad PS/2 mouse driver + * + * Copyright (c) 2004 Peter Osterlund <petero2@telia.com> + * + * 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. + */ + +#ifndef _ALPSCOMM_H_ +#define _ALPSCOMM_H_ + +#include "ps2comm.h" + + +#endif /* _ALPSCOMM_H_ */ @@ -380,13 +380,13 @@ ps2_synaptics_identify(int fd, struct SynapticsHwInfo *synhw) return FALSE; } -static Bool +Bool ps2_synaptics_enable_device(int fd) { return ps2_putbyte(fd, PS2_CMD_ENABLE); } -static Bool +Bool ps2_synaptics_disable_device(int fd) { xf86FlushInput(fd); @@ -51,6 +51,9 @@ typedef unsigned char byte; +Bool ps2_synaptics_enable_device(int fd); +Bool ps2_synaptics_disable_device(int fd); + struct SynapticsHwInfo; void ps2_print_ident(const struct SynapticsHwInfo *synhw); diff --git a/synaptics.c b/synaptics.c index 35dcc00..df62d1a 100644 --- a/synaptics.c +++ b/synaptics.c @@ -177,6 +177,8 @@ SetDeviceAndProtocol(LocalDevicePtr local) proto = SYN_PROTO_EVENT; } else if (str_par && !strcmp(str_par, "psm")) { proto = SYN_PROTO_PSM; + } else if (str_par && !strcmp(str_par, "alps")) { + proto = SYN_PROTO_ALPS; } else { /* default to auto-dev */ if (event_proto_operations.AutoDevProbe(local)) proto = SYN_PROTO_EVENT; @@ -191,6 +193,9 @@ SetDeviceAndProtocol(LocalDevicePtr local) case SYN_PROTO_PSM: priv->proto_ops = &psm_proto_operations; break; + case SYN_PROTO_ALPS: + priv->proto_ops = &alps_proto_operations; + break; } } @@ -67,7 +67,8 @@ struct CommData { enum SynapticsProtocol { SYN_PROTO_PSAUX, /* Raw psaux device */ SYN_PROTO_EVENT, /* Linux kernel event interface */ - SYN_PROTO_PSM /* FreeBSD psm driver */ + SYN_PROTO_PSM, /* FreeBSD psm driver */ + SYN_PROTO_ALPS /* ALPS touchpad protocol */ }; struct SynapticsHwInfo; @@ -86,6 +87,7 @@ struct SynapticsProtocolOperations { extern struct SynapticsProtocolOperations psaux_proto_operations; extern struct SynapticsProtocolOperations event_proto_operations; extern struct SynapticsProtocolOperations psm_proto_operations; +extern struct SynapticsProtocolOperations alps_proto_operations; #endif /* _SYNPROTO_H_ */ |