alpscomm.c revision 302b15bd
1/* 2 * Copyright © 2001 Stefan Gmeiner 3 * Copyright © 2003 Neil Brown 4 * Copyright © 2003-2005,2007 Peter Osterlund 5 * 6 * Permission to use, copy, modify, distribute, and sell this software 7 * and its documentation for any purpose is hereby granted without 8 * fee, provided that the above copyright notice appear in all copies 9 * and that both that copyright notice and this permission notice 10 * appear in supporting documentation, and that the name of Red Hat 11 * not be used in advertising or publicity pertaining to distribution 12 * of the software without specific, written prior permission. Red 13 * Hat makes no representations about the suitability of this software 14 * for any purpose. It is provided "as is" without express or implied 15 * warranty. 16 * 17 * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 18 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN 19 * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 20 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 21 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 22 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 23 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 24 * 25 * Authors: 26 * Stefan Gmeiner (riddlebox@freesurf.ch) 27 * Neil Brown (neilb@cse.unsw.edu.au) 28 * Peter Osterlund (petero2@telia.com) 29 */ 30 31#ifdef HAVE_CONFIG_H 32#include "config.h" 33#endif 34 35#include <xorg-server.h> 36#include "alpscomm.h" 37#include "synproto.h" 38#include "synaptics.h" 39#include "synapticsstr.h" 40#include <xf86.h> 41 42 43/* Wait for the channel to go silent, which means we're in sync */ 44static void 45ALPS_sync(int fd) 46{ 47 byte buffer[64]; 48 while (xf86WaitForInput(fd, 250000) > 0) { 49 xf86ReadSerial(fd, &buffer, 64); 50 } 51} 52 53/* 54 * send the ALPS init sequence, ie 4 consecutive "disable"s before the "enable" 55 * This "magic knock" is performed both for the trackpad and for the pointing 56 * stick. Not all models have a pointing stick, but trying to initialize it 57 * anyway doesn't seem to hurt. 58 */ 59static void 60ALPS_initialize(int fd) 61{ 62 xf86FlushInput(fd); 63 ps2_putbyte(fd, PS2_CMD_SET_DEFAULT); 64 ps2_putbyte(fd, PS2_CMD_SET_SCALING_2_1); 65 ps2_putbyte(fd, PS2_CMD_SET_SCALING_2_1); 66 ps2_putbyte(fd, PS2_CMD_SET_SCALING_2_1); 67 ps2_putbyte(fd, PS2_CMD_DISABLE); 68 69 ps2_putbyte(fd, PS2_CMD_DISABLE); 70 ps2_putbyte(fd, PS2_CMD_DISABLE); 71 ps2_putbyte(fd, PS2_CMD_DISABLE); 72 ps2_putbyte(fd, PS2_CMD_DISABLE); 73 ps2_putbyte(fd, PS2_CMD_ENABLE); 74 75 ps2_putbyte(fd, PS2_CMD_SET_SCALING_1_1); 76 ps2_putbyte(fd, PS2_CMD_SET_SCALING_1_1); 77 ps2_putbyte(fd, PS2_CMD_SET_SCALING_1_1); 78 ps2_putbyte(fd, PS2_CMD_DISABLE); 79 80 ps2_putbyte(fd, PS2_CMD_DISABLE); 81 ps2_putbyte(fd, PS2_CMD_DISABLE); 82 ps2_putbyte(fd, PS2_CMD_DISABLE); 83 ps2_putbyte(fd, PS2_CMD_DISABLE); 84 ps2_putbyte(fd, PS2_CMD_ENABLE); 85 86 ALPS_sync(fd); 87} 88 89static Bool 90ALPSQueryHardware(InputInfoPtr pInfo) 91{ 92 ALPS_initialize(pInfo->fd); 93 return TRUE; 94} 95 96static Bool 97ALPS_packet_ok(struct CommData *comm) 98{ 99 /* ALPS absolute mode packets start with 0b11111mrl */ 100 if ((comm->protoBuf[0] & 0xf8) == 0xf8) 101 return TRUE; 102 return FALSE; 103} 104 105static Bool 106ALPS_get_packet(struct CommData *comm, InputInfoPtr pInfo) 107{ 108 int c; 109 110 while ((c = XisbRead(comm->buffer)) >= 0) { 111 unsigned char u = (unsigned char)c; 112 113 comm->protoBuf[comm->protoBufTail++] = u; 114 115 if (comm->protoBufTail == 3) { /* PS/2 packet received? */ 116 if ((comm->protoBuf[0] & 0xc8) == 0x08) { 117 comm->protoBufTail = 0; 118 return TRUE; 119 } 120 } 121 122 if (comm->protoBufTail >= 6) { /* Full packet received */ 123 comm->protoBufTail = 0; 124 if (ALPS_packet_ok(comm)) 125 return TRUE; 126 while ((c = XisbRead(comm->buffer)) >= 0) 127 ; /* If packet is invalid, re-sync */ 128 } 129 } 130 131 return FALSE; 132} 133 134/* 135 * ALPS abolute Mode 136 * byte 0: 1 1 1 1 1 mid0 rig0 lef0 137 * byte 1: 0 x6 x5 x4 x3 x2 x1 x0 138 * byte 2: 0 x10 x9 x8 x7 up1 fin ges 139 * byte 3: 0 y9 y8 y7 1 mid1 rig1 lef1 140 * byte 4: 0 y6 y5 y4 y3 y2 y1 y0 141 * byte 5: 0 z6 z5 z4 z3 z2 z1 z0 142 * 143 * On a dualpoint, {mid,rig,lef}0 are the stick, 1 are the pad. 144 * We just 'or' them together for now. 145 * 146 * The touchpad on an 'Acer Aspire' has 4 buttons: 147 * left,right,up,down. 148 * This device always sets {mid,rig,lef}0 to 1 and 149 * reflects left,right,down,up in lef1,rig1,mid1,up1. 150 */ 151static void 152ALPS_process_packet(unsigned char *packet, struct SynapticsHwState *hw) 153{ 154 int x = 0, y = 0, z = 0; 155 int left = 0, right = 0, middle = 0; 156 int i; 157 158 x = (packet[1] & 0x7f) | ((packet[2] & 0x78) << (7-3)); 159 y = (packet[4] & 0x7f) | ((packet[3] & 0x70) << (7-4)); 160 z = packet[5]; 161 162 if (z == 127) { /* DualPoint stick is relative, not absolute */ 163 hw->left = packet[3] & 1; 164 hw->right = (packet[3] >> 1) & 1; 165 return; 166 } 167 168 /* Handle normal packets */ 169 hw->x = hw->y = hw->z = hw->numFingers = hw->fingerWidth = 0; 170 hw->left = hw->right = hw->up = hw->down = hw->middle = FALSE; 171 for (i = 0; i < 8; i++) 172 hw->multi[i] = FALSE; 173 174 if (z > 0) { 175 hw->x = x; 176 hw->y = y; 177 } 178 hw->z = z; 179 hw->numFingers = (z > 0) ? 1 : 0; 180 hw->fingerWidth = 5; 181 182 left |= (packet[2] ) & 1; 183 left |= (packet[3] ) & 1; 184 right |= (packet[3] >> 1) & 1; 185 if (packet[0] == 0xff) { 186 int back = (packet[3] >> 2) & 1; 187 int forward = (packet[2] >> 2) & 1; 188 if (back && forward) { 189 middle = 1; 190 back = 0; 191 forward = 0; 192 } 193 hw->down = back; 194 hw->up = forward; 195 } else { 196 left |= (packet[0] ) & 1; 197 right |= (packet[0] >> 1) & 1; 198 middle |= (packet[0] >> 2) & 1; 199 middle |= (packet[3] >> 2) & 1; 200 } 201 202 hw->left = left; 203 hw->right = right; 204 hw->middle = middle; 205} 206 207static Bool 208ALPSReadHwState(InputInfoPtr pInfo, 209 struct SynapticsProtocolOperations *proto_ops, 210 struct CommData *comm, struct SynapticsHwState *hwRet) 211{ 212 unsigned char *buf = comm->protoBuf; 213 struct SynapticsHwState *hw = &(comm->hwState); 214 215 if (!ALPS_get_packet(comm, pInfo)) 216 return FALSE; 217 218 ALPS_process_packet(buf, hw); 219 220 *hwRet = *hw; 221 return TRUE; 222} 223 224static Bool 225ALPSAutoDevProbe(InputInfoPtr pInfo) 226{ 227 return FALSE; 228} 229 230struct SynapticsProtocolOperations alps_proto_operations = { 231 NULL, 232 NULL, 233 ALPSQueryHardware, 234 ALPSReadHwState, 235 ALPSAutoDevProbe, 236 SynapticsDefaultDimensions 237}; 238