~ubuntu-branches/ubuntu/intrepid/xserver-xgl/intrepid

« back to all changes in this revision

Viewing changes to hw/dmx/input/lnx-ps2.c

  • Committer: Bazaar Package Importer
  • Author(s): Matthew Garrett
  • Date: 2006-02-13 14:21:43 UTC
  • Revision ID: james.westby@ubuntu.com-20060213142143-mad6z9xzem7hzxz9
Tags: upstream-7.0.0
ImportĀ upstreamĀ versionĀ 7.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $XFree86$ */
 
2
/* Portions of this file were derived from the following files:
 
3
 *
 
4
 **********************************************************************
 
5
 *
 
6
 * Xserver/hw/kdrive/linux/ps2.c
 
7
 *
 
8
 * Copyright (c) 1999 by Keith Packard
 
9
 *
 
10
 * Permission to use, copy, modify, distribute, and sell this software and its
 
11
 * documentation for any purpose is hereby granted without fee, provided that
 
12
 * the above copyright notice appear in all copies and that both that
 
13
 * copyright notice and this permission notice appear in supporting
 
14
 * documentation, and that the name of Keith Packard not be used in
 
15
 * advertising or publicity pertaining to distribution of the software without
 
16
 * specific, written prior permission.  Keith Packard makes no
 
17
 * representations about the suitability of this software for any purpose.  It
 
18
 * is provided "as is" without express or implied warranty.
 
19
 *
 
20
 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 
21
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 
22
 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 
23
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 
24
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 
25
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 
26
 * PERFORMANCE OF THIS SOFTWARE.
 
27
 *
 
28
 */
 
29
 
 
30
/*
 
31
 * Copyright 2001,2003 Red Hat Inc., Durham, North Carolina.
 
32
 *
 
33
 * All Rights Reserved.
 
34
 *
 
35
 * Permission is hereby granted, free of charge, to any person obtaining
 
36
 * a copy of this software and associated documentation files (the
 
37
 * "Software"), to deal in the Software without restriction, including
 
38
 * without limitation on the rights to use, copy, modify, merge,
 
39
 * publish, distribute, sublicense, and/or sell copies of the Software,
 
40
 * and to permit persons to whom the Software is furnished to do so,
 
41
 * subject to the following conditions:
 
42
 *
 
43
 * The above copyright notice and this permission notice (including the
 
44
 * next paragraph) shall be included in all copies or substantial
 
45
 * portions of the Software.
 
46
 *
 
47
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 
48
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 
49
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 
50
 * NON-INFRINGEMENT.  IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
 
51
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 
52
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 
53
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 
54
 * SOFTWARE.
 
55
 */
 
56
 
 
57
/*
 
58
 * Authors:
 
59
 *   Rickard E. (Rik) Faith <faith@redhat.com>
 
60
 *
 
61
 */
 
62
 
 
63
/** \file
 
64
 *
 
65
 * This code implements a low-level device driver for a serial MS mouse.
 
66
 * The code is derived from code by Keith Packard (see the source code
 
67
 * for complete references). */
 
68
 
 
69
#ifdef HAVE_DMX_CONFIG_H
 
70
#include <dmx-config.h>
 
71
#endif
 
72
 
 
73
#include "inputstr.h"
 
74
#include <X11/Xos.h>
 
75
#include <errno.h>
 
76
#include <termios.h>
 
77
 
 
78
/*****************************************************************************/
 
79
/* Define some macros to make it easier to move this file to another
 
80
 * part of the Xserver tree.  All calls to the dmx* layer are #defined
 
81
 * here for the .c file.  The .h file will also have to be edited. */
 
82
#include "dmxinputinit.h"
 
83
#include "lnx-ps2.h"
 
84
 
 
85
#define GETPRIV       myPrivate *priv                            \
 
86
                      = ((DMXLocalInputInfoPtr)(pDev->devicePrivate))->private
 
87
 
 
88
#define LOG0(f)       dmxLog(dmxDebug,f)
 
89
#define LOG1(f,a)     dmxLog(dmxDebug,f,a)
 
90
#define LOG2(f,a,b)   dmxLog(dmxDebug,f,a,b)
 
91
#define LOG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c)
 
92
#define FATAL0(f)     dmxLog(dmxFatal,f)
 
93
#define FATAL1(f,a)   dmxLog(dmxFatal,f,a)
 
94
#define FATAL2(f,a,b) dmxLog(dmxFatal,f,a,b)
 
95
#define MOTIONPROC    dmxMotionProcPtr
 
96
#define ENQUEUEPROC   dmxEnqueueProcPtr
 
97
#define CHECKPROC     dmxCheckSpecialProcPtr
 
98
#define BLOCK         DMXBlockType
 
99
 
 
100
/* End of interface definitions. */
 
101
/*****************************************************************************/
 
102
 
 
103
/* Private area for PS/2 devices. */
 
104
typedef struct _myPrivate {
 
105
    DeviceIntPtr   pMouse;
 
106
    int            fd;
 
107
    enum {
 
108
        button1 = 0x0001,
 
109
        button2 = 0x0002,
 
110
        button3 = 0x0004,
 
111
        button4 = 0x0008,
 
112
        button5 = 0x0010
 
113
    }              buttons;
 
114
} myPrivate;
 
115
 
 
116
static int ps2LinuxReadBytes(int fd, unsigned char *buf, int len, int min)
 
117
{
 
118
    int             n, tot;
 
119
    fd_set          set;
 
120
    struct timeval  tv;
 
121
    
 
122
    tot = 0;
 
123
    while (len) {
 
124
        n = read(fd, buf, len);
 
125
        if (n > 0) {
 
126
            tot += n;
 
127
            buf += n;
 
128
            len -= n;
 
129
        }
 
130
        if (tot % min == 0) break;
 
131
        FD_ZERO(&set);
 
132
        FD_SET(fd, &set);
 
133
        tv.tv_sec = 0;
 
134
        tv.tv_usec = 100 * 1000;
 
135
        n = select(fd + 1, &set, 0, 0, &tv);
 
136
        if (n <= 0) break;
 
137
    }
 
138
    return tot;
 
139
}
 
140
 
 
141
static void ps2LinuxButton(DevicePtr pDev, ENQUEUEPROC enqueue,
 
142
                           int buttons, BLOCK block)
 
143
{
 
144
    GETPRIV;
 
145
    
 
146
#define PRESS(b)                                         \
 
147
    do {                                                 \
 
148
        enqueue(pDev, ButtonPress, 0, 0, NULL, block);   \
 
149
    } while (0)
 
150
 
 
151
#define RELEASE(b)                                       \
 
152
    do {                                                 \
 
153
        enqueue(pDev, ButtonRelease, 0, 0, NULL, block); \
 
154
    } while (0)
 
155
          
 
156
    if ((buttons & button1) && !(priv->buttons & button1)) PRESS(1);
 
157
    if (!(buttons & button1) && (priv->buttons & button1)) RELEASE(1);
 
158
 
 
159
    if ((buttons & button2) && !(priv->buttons & button2)) PRESS(2);
 
160
    if (!(buttons & button2) && (priv->buttons & button2)) RELEASE(2);
 
161
 
 
162
    if ((buttons & button3) && !(priv->buttons & button3)) PRESS(3);
 
163
    if (!(buttons & button3) && (priv->buttons & button3)) RELEASE(3);
 
164
 
 
165
    if ((buttons & button4) && !(priv->buttons & button4)) PRESS(4);
 
166
    if (!(buttons & button4) && (priv->buttons & button4)) RELEASE(4);
 
167
    
 
168
    if ((buttons & button5) && !(priv->buttons & button5)) PRESS(5);
 
169
    if (!(buttons & button5) && (priv->buttons & button5)) RELEASE(5);
 
170
 
 
171
    priv->buttons = buttons;
 
172
}
 
173
 
 
174
/** Read an event from the \a pDev device.  If the event is a motion
 
175
 * event, enqueue it with the \a motion function.  Otherwise, check for
 
176
 * special keys with the \a checkspecial function and enqueue the event
 
177
 * with the \a enqueue function.  The \a block type is passed to the
 
178
 * functions so that they may block SIGIO handling as appropriate to the
 
179
 * caller of this function. */
 
180
void ps2LinuxRead(DevicePtr pDev, MOTIONPROC motion,
 
181
                  ENQUEUEPROC enqueue, CHECKPROC checkspecial, BLOCK block)
 
182
{
 
183
    GETPRIV;
 
184
    unsigned char   buf[3 * 200]; /* RATS: Use ok */
 
185
    unsigned char   *b;
 
186
    int             n;
 
187
    int             dx, dy, v[2];
 
188
 
 
189
    while ((n = ps2LinuxReadBytes(priv->fd, buf, sizeof(buf), 3)) > 0) {
 
190
        b = buf;
 
191
        while (n >= 3) {
 
192
            dx   =  b[1] - ((b[0] & 0x10) ? 256 : 0);
 
193
            dy   = -b[2] + ((b[0] & 0x20) ? 256 : 0);
 
194
            v[0] = -dx;
 
195
            v[1] = -dy;
 
196
 
 
197
            motion(pDev, v, 0, 2, 1, block);
 
198
            ps2LinuxButton(pDev, enqueue, (((b[0] & 4) ? button2 : 0)
 
199
                                           | ((b[0] & 2) ? button3 : 0)
 
200
                                           | ((b[0] & 1) ? button1 : 0)),
 
201
                           block);
 
202
            n -= 3;
 
203
            b += 3;
 
204
        }
 
205
    }
 
206
}
 
207
 
 
208
/** Initialize \a pDev. */
 
209
void ps2LinuxInit(DevicePtr pDev)
 
210
{
 
211
    GETPRIV;
 
212
    const char *names[] = { "/dev/mouse", "/dev/psaux", NULL };
 
213
    int        i;
 
214
 
 
215
    if (priv->fd >=0) return;
 
216
 
 
217
    for (i = 0; names[i]; i++) {
 
218
        if ((priv->fd = open(names[i], O_RDWR | O_NONBLOCK, 0)) >= 0) break;
 
219
    }
 
220
    if (priv->fd < 0)
 
221
        FATAL1("ps2LinuxInit: Cannot open mouse port (%s)\n",
 
222
               strerror(errno));
 
223
}
 
224
 
 
225
/** Turn \a pDev on (i.e., take input from \a pDev). */
 
226
int ps2LinuxOn(DevicePtr pDev)
 
227
{
 
228
    GETPRIV;
 
229
 
 
230
    if (priv->fd < 0) ps2LinuxInit(pDev);
 
231
    return priv->fd;
 
232
}
 
233
 
 
234
/** Turn \a pDev off (i.e., stop taking input from \a pDev). */
 
235
void ps2LinuxOff(DevicePtr pDev)
 
236
{
 
237
    GETPRIV;
 
238
 
 
239
    close(priv->fd);
 
240
    priv->fd = -1;
 
241
}
 
242
 
 
243
static void ps2LinuxGetMap(DevicePtr pDev, unsigned char *map, int *nButtons)
 
244
{
 
245
    int i;
 
246
    
 
247
    if (nButtons) *nButtons = 3;
 
248
    if (map) for (i = 0; i <= *nButtons; i++) map[i] = i;
 
249
}
 
250
 
 
251
/** Currently unused hook called prior to an VT switch. */
 
252
void ps2LinuxVTPreSwitch(pointer p)
 
253
{
 
254
}
 
255
 
 
256
/** Currently unused hook called after returning from a VT switch. */
 
257
void ps2LinuxVTPostSwitch(pointer p)
 
258
{
 
259
}
 
260
 
 
261
/** Create a private structure for use within this file. */
 
262
pointer ps2LinuxCreatePrivate(DeviceIntPtr pMouse)
 
263
{
 
264
    myPrivate *priv = xalloc(sizeof(*priv));
 
265
    memset(priv, 0, sizeof(*priv));
 
266
    priv->fd     = -1;
 
267
    priv->pMouse = pMouse;
 
268
    return priv;
 
269
}
 
270
 
 
271
/** Destroy a private structure. */
 
272
void ps2LinuxDestroyPrivate(pointer priv)
 
273
{
 
274
    if (priv) xfree(priv);
 
275
}
 
276
 
 
277
/** Fill the \a info structure with information needed to initialize \a
 
278
 * pDev. */ 
 
279
void ps2LinuxGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info)
 
280
{
 
281
    info->buttonClass      = 1;
 
282
    ps2LinuxGetMap(pDev, info->map, &info->numButtons);
 
283
    info->valuatorClass    = 1;
 
284
    info->numRelAxes       = 2;
 
285
    info->minval[0]        = 0;
 
286
    info->maxval[0]        = 0;
 
287
    info->res[0]           = 1;
 
288
    info->minres[0]        = 0;
 
289
    info->maxres[0]        = 1;
 
290
    info->ptrFeedbackClass = 1;
 
291
}