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 /alpscomm.c | |
parent | f1146f67f7e377d1f6f32a26bb833fc2b0ed2ed6 (diff) |
Added (untested) support for ALPS touchpads using the 2.4
linux kernel.
Diffstat (limited to 'alpscomm.c')
-rw-r--r-- | alpscomm.c | 187 |
1 files changed, 187 insertions, 0 deletions
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 +}; |