psmcomm.c revision b85037db
1/*
2 * Copyright � 1997 C. Scott Ananian
3 * Copyright � 1998-2000 Bruce Kalk
4 * Copyright � 2001 Stefan Gmeiner
5 * Copyright � 2002 Linuxcare Inc. David Kennedy
6 * Copyright � 2003 Fred Hucht
7 * Copyright � 2004 Arne Schwabe
8 *
9 * Permission to use, copy, modify, distribute, and sell this software
10 * and its documentation for any purpose is hereby granted without
11 * fee, provided that the above copyright notice appear in all copies
12 * and that both that copyright notice and this permission notice
13 * appear in supporting documentation, and that the name of Red Hat
14 * not be used in advertising or publicity pertaining to distribution
15 * of the software without specific, written prior permission.  Red
16 * Hat makes no representations about the suitability of this software
17 * for any purpose.  It is provided "as is" without express or implied
18 * warranty.
19 *
20 * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
21 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
22 * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
23 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
24 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
25 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
26 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
27 *
28 * Authors:
29 *      Stefan Gmeiner (riddlebox@freesurf.ch)
30 *      C. Scott Ananian (cananian@alumni.priceton.edu)
31 *      Bruce Kalk (kall@compass.com)
32 *      Linuxcare Inc. David Kennedy (dkennedy@linuxcare.com)
33 *      Fred Hucht (fred@thp.Uni-Duisburg.de)
34 *      Arne Schwabe <schwabe@uni-paderborn.de>
35 */
36
37#ifdef HAVE_CONFIG_H
38#include "config.h"
39#endif
40
41#include <xorg-server.h>
42#include <unistd.h>
43#include <sys/ioctl.h>
44#include <sys/mouse.h>
45#include <errno.h>
46#include <string.h>
47#include "synproto.h"
48#include "synaptics.h"
49#include "synapticsstr.h"
50#include "ps2comm.h"			    /* ps2_print_ident() */
51#include <xf86.h>
52
53#define SYSCALL(call) while (((call) == -1) && (errno == EINTR))
54
55struct SynapticsHwInfo {
56    unsigned int model_id;		    /* Model-ID */
57    unsigned int capabilities;		    /* Capabilities */
58    unsigned int ext_cap;		    /* Extended Capabilities */
59    unsigned int identity;		    /* Identification */
60};
61
62/*
63 * Identify Touchpad
64 * See also the SYN_ID_* macros
65 */
66static Bool
67psm_synaptics_identify(int fd, synapticshw_t *ident)
68{
69    int ret;
70
71    SYSCALL(ret = ioctl(fd, MOUSE_SYN_GETHWINFO, ident));
72    if (ret == 0)
73	return TRUE;
74    else
75	return FALSE;
76}
77
78/* This define is used in a ioctl but not in mouse.h :/ */
79#define PSM_LEVEL_NATIVE	2
80
81static Bool
82PSMQueryIsSynaptics(LocalDevicePtr local)
83{
84    int ret;
85    int level = PSM_LEVEL_NATIVE;
86    mousehw_t mhw;
87
88    /* Put the device in native protocol mode to be sure
89     * Otherwise HWINFO will not return the right id
90     * And we will need native mode anyway ...
91     */
92    SYSCALL(ret = ioctl(local->fd, MOUSE_SETLEVEL, &level));
93    if (ret != 0) {
94	xf86Msg(X_ERROR, "%s Can't set native mode\n", local->name);
95	return FALSE;
96    }
97    SYSCALL(ret = ioctl(local->fd, MOUSE_GETHWINFO, &mhw));
98    if (ret != 0) {
99	xf86Msg(X_ERROR, "%s Can't get hardware info\n", local->name);
100	return FALSE;
101    }
102
103    if (mhw.model == MOUSE_MODEL_SYNAPTICS) {
104	return TRUE;
105    } else {
106	xf86Msg(X_ERROR, "%s Found no Synaptics, found Mouse model %d instead\n",
107		local->name, mhw.model);
108	return FALSE;
109    }
110}
111
112static void
113convert_hw_info(const synapticshw_t *psm_ident, struct SynapticsHwInfo *synhw)
114{
115    memset(synhw, 0, sizeof(*synhw));
116    synhw->model_id = ((psm_ident->infoRot180 << 23) |
117		       (psm_ident->infoPortrait << 22) |
118		       (psm_ident->infoSensor << 16) |
119		       (psm_ident->infoHardware << 9) |
120		       (psm_ident->infoNewAbs << 7) |
121		       (psm_ident->capPen << 6) |
122		       (psm_ident->infoSimplC << 5) |
123		       (psm_ident->infoGeometry));
124    synhw->capabilities = ((psm_ident->capExtended << 23) |
125			   (psm_ident->capPassthrough << 7) |
126			   (psm_ident->capSleep << 4) |
127			   (psm_ident->capFourButtons << 3) |
128			   (psm_ident->capMultiFinger << 1) |
129			   (psm_ident->capPalmDetect));
130    synhw->ext_cap = 0;
131    synhw->identity = ((psm_ident->infoMajor) |
132		       (0x47 << 8) |
133		       (psm_ident->infoMinor << 16));
134}
135
136static Bool
137PSMQueryHardware(LocalDevicePtr local)
138{
139    synapticshw_t psm_ident;
140    struct SynapticsHwInfo *synhw;
141    SynapticsPrivate *priv;
142
143    priv = (SynapticsPrivate *)local->private;
144
145    if(!priv->proto_data)
146        priv->proto_data = calloc(1, sizeof(struct SynapticsHwInfo));
147    synhw = (struct SynapticsHwInfo*)priv->proto_data;
148
149    /* is the synaptics touchpad active? */
150    if (!PSMQueryIsSynaptics(local))
151	return FALSE;
152
153    xf86Msg(X_PROBED, "%s synaptics touchpad found\n", local->name);
154
155    if (!psm_synaptics_identify(local->fd, &psm_ident))
156	return FALSE;
157
158    convert_hw_info(&psm_ident, synhw);
159
160    ps2_print_ident(synhw);
161
162    return TRUE;
163}
164
165static Bool
166PSMReadHwState(LocalDevicePtr local,
167	       struct SynapticsProtocolOperations *proto_ops,
168	       struct CommData *comm, struct SynapticsHwState *hwRet)
169{
170    return psaux_proto_operations.ReadHwState(local, proto_ops, comm, hwRet);
171}
172
173static Bool PSMAutoDevProbe(LocalDevicePtr local)
174{
175    return FALSE;
176}
177
178struct SynapticsProtocolOperations psm_proto_operations = {
179    NULL,
180    NULL,
181    PSMQueryHardware,
182    PSMReadHwState,
183    PSMAutoDevProbe,
184    SynapticsDefaultDimensions
185};
186