1/*
2Copyright (c) 2001 by Juliusz Chroboczek
3Copyright (c) 1999 by Keith Packard
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal
7in the Software without restriction, including without limitation the rights
8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software, and to permit persons to whom the Software is
10furnished to do so, subject to the following conditions:
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
18AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21THE SOFTWARE.
22*/
23
24#ifdef HAVE_CONFIG_H
25#include <kdrive-config.h>
26#endif
27#include <errno.h>
28#include <termios.h>
29#include <X11/X.h>
30#include <X11/Xproto.h>
31#include <X11/Xpoll.h>
32#include "inputstr.h"
33#include "scrnintstr.h"
34#include "kdrive.h"
35
36static int
37MsReadBytes (int fd, char *buf, int len, int min)
38{
39    int		    n, tot;
40    fd_set	    set;
41    struct timeval  tv;
42
43    tot = 0;
44    while (len)
45    {
46	n = read (fd, buf, len);
47	if (n > 0)
48	{
49	    tot += n;
50	    buf += n;
51	    len -= n;
52	}
53	if (tot % min == 0)
54	    break;
55	FD_ZERO (&set);
56	FD_SET (fd, &set);
57	tv.tv_sec = 0;
58	tv.tv_usec = 100 * 1000;
59	n = select (fd + 1, &set, 0, 0, &tv);
60	if (n <= 0)
61	    break;
62    }
63    return tot;
64}
65
66static void
67MsRead (int port, void *closure)
68{
69    unsigned char   buf[3 * 200];
70    unsigned char   *b;
71    int		    n;
72    int		    dx, dy;
73    unsigned long   flags;
74
75    while ((n = MsReadBytes (port, (char *) buf, sizeof (buf), 3)) > 0)
76    {
77	b = buf;
78	while (n >= 3)
79	{
80	    flags = KD_MOUSE_DELTA;
81
82	    if (b[0] & 0x20)
83		flags |= KD_BUTTON_1;
84	    if (b[0] & 0x10)
85		flags |= KD_BUTTON_3;
86
87	    dx = (char)(((b[0] & 0x03) << 6) | (b[1] & 0x3F));
88	    dy = (char)(((b[0] & 0x0C) << 4) | (b[2] & 0x3F));
89            n -= 3;
90            b += 3;
91	    KdEnqueuePointerEvent (closure, flags, dx, dy, 0);
92	}
93    }
94}
95
96static Status
97MsInit (KdPointerInfo *pi)
98{
99    if (!pi)
100        return BadImplementation;
101
102    if (!pi->path || strcmp(pi->path, "auto"))
103        pi->path = strdup("/dev/mouse");
104    if (!pi->name)
105        pi->name = strdup("Microsoft protocol mouse");
106
107    return Success;
108}
109
110static Status
111MsEnable (KdPointerInfo *pi)
112{
113    int port;
114    struct termios t;
115    int ret;
116
117    port = open (pi->path, O_RDWR | O_NONBLOCK);
118    if(port < 0) {
119        ErrorF("Couldn't open %s (%d)\n", pi->path, (int)errno);
120        return 0;
121    } else if (port == 0) {
122        ErrorF("Opening %s returned 0!  Please complain to Keith.\n",
123               pi->path);
124	goto bail;
125    }
126
127    if(!isatty(port)) {
128        ErrorF("%s is not a tty\n", pi->path);
129        goto bail;
130    }
131
132    ret = tcgetattr(port, &t);
133    if(ret < 0) {
134        ErrorF("Couldn't tcgetattr(%s): %d\n", pi->path, errno);
135        goto bail;
136    }
137    t.c_iflag &= ~ (IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR |
138                   IGNCR | ICRNL | IXON | IXOFF);
139    t.c_oflag &= ~ OPOST;
140    t.c_lflag &= ~ (ECHO | ECHONL | ICANON | ISIG | IEXTEN);
141    t.c_cflag &= ~ (CSIZE | PARENB);
142    t.c_cflag |= CS8 | CLOCAL | CSTOPB;
143
144    cfsetispeed (&t, B1200);
145    cfsetospeed (&t, B1200);
146    t.c_cc[VMIN] = 1;
147    t.c_cc[VTIME] = 0;
148    ret = tcsetattr(port, TCSANOW, &t);
149    if(ret < 0) {
150        ErrorF("Couldn't tcsetattr(%s): %d\n", pi->path, errno);
151        goto bail;
152    }
153    if (KdRegisterFd (port, MsRead, pi))
154	return TRUE;
155    pi->driverPrivate = (void *)(intptr_t)port;
156
157    return Success;
158
159 bail:
160    close(port);
161    return BadMatch;
162}
163
164static void
165MsDisable (KdPointerInfo *pi)
166{
167    KdUnregisterFd (pi, (int)(intptr_t)pi->driverPrivate, TRUE);
168}
169
170static void
171MsFini (KdPointerInfo *pi)
172{
173}
174
175KdPointerDriver MsMouseDriver = {
176    "ms",
177    MsInit,
178    MsEnable,
179    MsDisable,
180    MsFini,
181    NULL,
182};
183