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

« back to all changes in this revision

Viewing changes to hw/dmx/input/lnx-ms.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/ms.c
 
7
 *
 
8
 * Copyright (c) 2001 by Juliusz Chroboczek
 
9
 * Copyright (c) 1999 by Keith Packard
 
10
 *
 
11
 * Permission is hereby granted, free of charge, to any person obtaining
 
12
 * a copy of this software and associated documentation files (the
 
13
 * "Software"), to deal in the Software without restriction, including
 
14
 * without limitation the rights to use, copy, modify, merge, publish,
 
15
 * distribute, sublicense, and/or sell copies of the Software, and to
 
16
 * permit persons to whom the Software is furnished to do so, subject to
 
17
 * the following conditions:
 
18
 *
 
19
 * The above copyright notice and this permission notice shall be
 
20
 * included in all copies or substantial portions of the Software.
 
21
 * 
 
22
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 
23
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 
24
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 
25
 * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 
26
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 
27
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 
28
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 
29
 * SOFTWARE.
 
30
 *
 
31
 */
 
32
 
 
33
/*
 
34
 * Copyright 2001-2003 Red Hat Inc., Durham, North Carolina.
 
35
 *
 
36
 * All Rights Reserved.
 
37
 *
 
38
 * Permission is hereby granted, free of charge, to any person obtaining
 
39
 * a copy of this software and associated documentation files (the
 
40
 * "Software"), to deal in the Software without restriction, including
 
41
 * without limitation on the rights to use, copy, modify, merge,
 
42
 * publish, distribute, sublicense, and/or sell copies of the Software,
 
43
 * and to permit persons to whom the Software is furnished to do so,
 
44
 * subject to the following conditions:
 
45
 *
 
46
 * The above copyright notice and this permission notice (including the
 
47
 * next paragraph) shall be included in all copies or substantial
 
48
 * portions of the Software.
 
49
 *
 
50
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 
51
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 
52
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 
53
 * NON-INFRINGEMENT.  IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
 
54
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 
55
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 
56
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 
57
 * SOFTWARE.
 
58
 */
 
59
 
 
60
/*
 
61
 * Authors:
 
62
 *   Rickard E. (Rik) Faith <faith@redhat.com>
 
63
 *
 
64
 */
 
65
 
 
66
/** \file
 
67
 *
 
68
 * This code implements a low-level device driver for a serial MS mouse.
 
69
 * The code is derived from code by Juliusz Chroboczek and Keith Packard
 
70
 * (see the source code for complete references). */
 
71
 
 
72
#ifdef HAVE_DMX_CONFIG_H
 
73
#include <dmx-config.h>
 
74
#endif
 
75
 
 
76
#include "inputstr.h"
 
77
#include <X11/Xos.h>
 
78
#include <errno.h>
 
79
#include <termios.h>
 
80
 
 
81
/*****************************************************************************/
 
82
/* Define some macros to make it easier to move this file to another
 
83
 * part of the Xserver tree.  All calls to the dmx* layer are #defined
 
84
 * here for the .c file.  The .h file will also have to be edited. */
 
85
#include "dmxinputinit.h"
 
86
#include "lnx-ms.h"
 
87
 
 
88
#define GETPRIV       myPrivate *priv                            \
 
89
                      = ((DMXLocalInputInfoPtr)(pDev->devicePrivate))->private
 
90
 
 
91
#define LOG0(f)       dmxLog(dmxDebug,f)
 
92
#define LOG1(f,a)     dmxLog(dmxDebug,f,a)
 
93
#define LOG2(f,a,b)   dmxLog(dmxDebug,f,a,b)
 
94
#define LOG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c)
 
95
#define FATAL0(f)     dmxLog(dmxFatal,f)
 
96
#define FATAL1(f,a)   dmxLog(dmxFatal,f,a)
 
97
#define FATAL2(f,a,b) dmxLog(dmxFatal,f,a,b)
 
98
#define MOTIONPROC    dmxMotionProcPtr
 
99
#define ENQUEUEPROC   dmxEnqueueProcPtr
 
100
#define CHECKPROC     dmxCheckSpecialProcPtr
 
101
#define BLOCK         DMXBlockType
 
102
 
 
103
/* End of interface definitions. */
 
104
/*****************************************************************************/
 
105
 
 
106
/* Private area for MS mouse devices. */
 
107
typedef struct _myPrivate {
 
108
    DeviceIntPtr   pMouse;
 
109
    int            fd;
 
110
    struct termios tty;
 
111
    enum {
 
112
        button1 = 0x0001,
 
113
        button2 = 0x0002,
 
114
        button3 = 0x0004,
 
115
        button4 = 0x0008,
 
116
        button5 = 0x0010
 
117
    }              buttons;
 
118
} myPrivate;
 
119
 
 
120
static int msLinuxReadBytes(int fd, unsigned char *buf, int len, int min)
 
121
{
 
122
    int             n, tot;
 
123
    fd_set          set;
 
124
    struct timeval  tv;
 
125
    
 
126
    tot = 0;
 
127
    while (len) {
 
128
        n = read(fd, buf, len);
 
129
        if (n > 0) {
 
130
            tot += n;
 
131
            buf += n;
 
132
            len -= n;
 
133
        }
 
134
        if (tot % min == 0) break;
 
135
        FD_ZERO(&set);
 
136
        FD_SET(fd, &set);
 
137
        tv.tv_sec = 0;
 
138
        tv.tv_usec = 100 * 1000;
 
139
        n = select(fd + 1, &set, 0, 0, &tv);
 
140
        if (n <= 0) break;
 
141
    }
 
142
    return tot;
 
143
}
 
144
 
 
145
static void msLinuxButton(DevicePtr pDev, ENQUEUEPROC enqueue, int buttons,
 
146
                          BLOCK block)
 
147
{
 
148
    GETPRIV;
 
149
 
 
150
#define PRESS(b)                                         \
 
151
    do {                                                 \
 
152
        enqueue(pDev, ButtonPress, 0, 0, NULL, block);   \
 
153
    } while (0)
 
154
 
 
155
#define RELEASE(b)                                       \
 
156
    do {                                                 \
 
157
        enqueue(pDev, ButtonRelease, 0, 0, NULL, block); \
 
158
    } while (0)
 
159
          
 
160
    if ((buttons & button1) && !(priv->buttons & button1)) PRESS(1);
 
161
    if (!(buttons & button1) && (priv->buttons & button1)) RELEASE(1);
 
162
 
 
163
    if ((buttons & button2) && !(priv->buttons & button2)) PRESS(2);
 
164
    if (!(buttons & button2) && (priv->buttons & button2)) RELEASE(2);
 
165
 
 
166
    if ((buttons & button3) && !(priv->buttons & button3)) PRESS(3);
 
167
    if (!(buttons & button3) && (priv->buttons & button3)) RELEASE(3);
 
168
 
 
169
    if ((buttons & button4) && !(priv->buttons & button4)) PRESS(4);
 
170
    if (!(buttons & button4) && (priv->buttons & button4)) RELEASE(4);
 
171
    
 
172
    if ((buttons & button5) && !(priv->buttons & button5)) PRESS(5);
 
173
    if (!(buttons & button5) && (priv->buttons & button5)) RELEASE(5);
 
174
 
 
175
    priv->buttons = buttons;
 
176
}
 
177
 
 
178
/** Read an event from the \a pDev device.  If the event is a motion
 
179
 * event, enqueue it with the \a motion function.  Otherwise, check for
 
180
 * special keys with the \a checkspecial function and enqueue the event
 
181
 * with the \a enqueue function.  The \a block type is passed to the
 
182
 * functions so that they may block SIGIO handling as appropriate to the
 
183
 * caller of this function. */
 
184
void msLinuxRead(DevicePtr pDev,
 
185
                 MOTIONPROC motion,
 
186
                 ENQUEUEPROC enqueue,
 
187
                 CHECKPROC checkspecial,
 
188
                 BLOCK block)
 
189
{
 
190
    GETPRIV;
 
191
    unsigned char   buf[3 * 200]; /* RATS: Use ok */
 
192
    unsigned char   *b;
 
193
    int             n;
 
194
    int             dx, dy, v[2];
 
195
 
 
196
    while ((n = msLinuxReadBytes(priv->fd, buf, sizeof(buf), 3)) > 0) {
 
197
        b = buf;
 
198
        while (n >= 3) {
 
199
            dx   = (char)(((b[0] & 0x03) << 6) | (b[1] & 0x3f));
 
200
            dy   = (char)(((b[0] & 0x0c) << 4) | (b[2] & 0x3f));
 
201
            v[0] = -dx;
 
202
            v[1] = -dy;
 
203
            
 
204
            motion(pDev, v, 0, 2, 1, block);
 
205
            msLinuxButton(pDev, enqueue, (((b[0] & 0x10) ? button3 : 0)
 
206
                                          | ((b[0] & 0x20) ? button1 : 0)),
 
207
                          block);
 
208
            n -= 3;
 
209
            b += 3;
 
210
        }
 
211
    }
 
212
}
 
213
 
 
214
/** Initialize \a pDev. */
 
215
void msLinuxInit(DevicePtr pDev)
 
216
{
 
217
    GETPRIV;
 
218
    const char *names[] = { "/dev/serialmouse", "/dev/mouse", NULL };
 
219
    int        i;
 
220
 
 
221
    if (priv->fd >=0) return;
 
222
 
 
223
    for (i = 0; names[i]; i++) {
 
224
        if ((priv->fd = open(names[i], O_RDWR | O_NONBLOCK, 0)) >= 0) break;
 
225
    }
 
226
    if (priv->fd < 0)
 
227
        FATAL1("msLinuxInit: Cannot open mouse port (%s)\n",
 
228
               strerror(errno));
 
229
    
 
230
    if (!isatty(priv->fd))
 
231
        FATAL1("msLinuxInit: Mouse port %s is not a tty\n", names[i]);
 
232
 
 
233
    if (tcgetattr(priv->fd, &priv->tty) < 0)
 
234
        FATAL1("msLinuxInit: tcgetattr failed (%s)\n", strerror(errno));
 
235
 
 
236
    write(priv->fd, "*n", 2);   /* 1200 baud */
 
237
    usleep(100000);
 
238
}
 
239
 
 
240
/** Turn \a pDev on (i.e., take input from \a pDev). */
 
241
int msLinuxOn(DevicePtr pDev)
 
242
{
 
243
    GETPRIV;
 
244
    struct termios nTty;
 
245
 
 
246
    if (priv->fd < 0) msLinuxInit(pDev);
 
247
    
 
248
    nTty             = priv->tty;
 
249
    nTty.c_iflag    &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR
 
250
                         | IGNCR | ICRNL | IXON | IXOFF);
 
251
    nTty.c_oflag    &= ~OPOST;
 
252
    nTty.c_lflag    &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
 
253
    nTty.c_cflag    &= ~(CSIZE | PARENB);
 
254
    nTty.c_cflag    |= CS8 | CLOCAL | CSTOPB;
 
255
    nTty.c_cc[VTIME] = 0;
 
256
    nTty.c_cc[VMIN]  = 1;
 
257
    cfsetispeed (&nTty, B1200);
 
258
    cfsetospeed (&nTty, B1200);
 
259
    if (tcsetattr(priv->fd, TCSANOW, &nTty) < 0)
 
260
        FATAL1("msLinuxInit: tcsetattr failed (%s)\n", strerror(errno));
 
261
    write(priv->fd, "*V", 2);   /* 2 button 3 byte protocol */
 
262
    return priv->fd;
 
263
}
 
264
 
 
265
/** Turn \a pDev off (i.e., stop taking input from \a pDev). */
 
266
void msLinuxOff(DevicePtr pDev)
 
267
{
 
268
    GETPRIV;
 
269
 
 
270
    tcsetattr(priv->fd, TCSANOW, &priv->tty);
 
271
    close(priv->fd);
 
272
    priv->fd = -1;
 
273
}
 
274
 
 
275
static void msLinuxGetMap(DevicePtr pDev, unsigned char *map, int *nButtons)
 
276
{
 
277
    int i;
 
278
    
 
279
    if (nButtons) *nButtons = 3;
 
280
    if (map) for (i = 0; i <= *nButtons; i++) map[i] = i;
 
281
}
 
282
 
 
283
/** Currently unused hook called prior to an VT switch. */
 
284
void msLinuxVTPreSwitch(pointer p)
 
285
{
 
286
}
 
287
 
 
288
/** Currently unused hook called after returning from a VT switch. */
 
289
void msLinuxVTPostSwitch(pointer p)
 
290
{
 
291
}
 
292
 
 
293
/** Create a private structure for use within this file. */
 
294
pointer msLinuxCreatePrivate(DeviceIntPtr pMouse)
 
295
{
 
296
    myPrivate *priv = xalloc(sizeof(*priv));
 
297
    memset(priv, 0, sizeof(*priv));
 
298
    priv->fd     = -1;
 
299
    priv->pMouse = pMouse;
 
300
    return priv;
 
301
}
 
302
 
 
303
/** Destroy a private structure. */
 
304
void msLinuxDestroyPrivate(pointer priv)
 
305
{
 
306
    if (priv) xfree(priv);
 
307
}
 
308
 
 
309
/** Fill the \a info structure with information needed to initialize \a
 
310
 * pDev. */ 
 
311
void msLinuxGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info)
 
312
{
 
313
    info->buttonClass      = 1;
 
314
    msLinuxGetMap(pDev, info->map, &info->numButtons);
 
315
    info->valuatorClass    = 1;
 
316
    info->numRelAxes       = 2;
 
317
    info->minval[0]        = 0;
 
318
    info->maxval[0]        = 0;
 
319
    info->res[0]           = 1;
 
320
    info->minres[0]        = 0;
 
321
    info->maxres[0]        = 1;
 
322
    info->ptrFeedbackClass = 1;
 
323
}