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