1/*
2 * Copyright � 1999 Keith Packard
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of Keith Packard not be used in
9 * advertising or publicity pertaining to distribution of the software without
10 * specific, written prior permission.  Keith Packard makes no
11 * representations about the suitability of this software for any purpose.  It
12 * is provided "as is" without express or implied warranty.
13 *
14 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
21 */
22
23#ifdef HAVE_CONFIG_H
24#include <kdrive-config.h>
25#endif
26#include <X11/X.h>
27#include <X11/Xproto.h>
28#include <X11/Xpoll.h>
29#include "inputstr.h"
30#include "scrnintstr.h"
31#include "kdrive.h"
32
33static int
34Ps2ReadBytes (int fd, char *buf, int len, int min)
35{
36    int		    n, tot;
37    fd_set	    set;
38    struct timeval  tv;
39
40    tot = 0;
41    while (len)
42    {
43	n = read (fd, buf, len);
44	if (n > 0)
45	{
46	    tot += n;
47	    buf += n;
48	    len -= n;
49	}
50	if (tot % min == 0)
51	    break;
52	FD_ZERO (&set);
53	FD_SET (fd, &set);
54	tv.tv_sec = 0;
55	tv.tv_usec = 100 * 1000;
56	n = select (fd + 1, &set, 0, 0, &tv);
57	if (n <= 0)
58	    break;
59    }
60    return tot;
61}
62
63char	*Ps2Names[] = {
64    "/dev/psaux",
65/*    "/dev/mouse", */
66    "/dev/input/mice",
67};
68
69#define NUM_PS2_NAMES	(sizeof (Ps2Names) / sizeof (Ps2Names[0]))
70
71static void
72Ps2Read (int ps2Port, void *closure)
73{
74    unsigned char   buf[3 * 200];
75    unsigned char   *b;
76    int		    n;
77    int		    dx, dy;
78    unsigned long   flags;
79    unsigned long   left_button = KD_BUTTON_1;
80    unsigned long   right_button = KD_BUTTON_3;
81
82#undef SWAP_USB
83#ifdef SWAP_USB
84    if (id == 2)
85    {
86	left_button = KD_BUTTON_3;
87	right_button = KD_BUTTON_1;
88    }
89#endif
90    while ((n = Ps2ReadBytes (ps2Port, (char *) buf, sizeof (buf), 3)) > 0)
91    {
92	b = buf;
93	while (n >= 3)
94	{
95	    flags = KD_MOUSE_DELTA;
96	    if (b[0] & 4)
97		flags |= KD_BUTTON_2;
98	    if (b[0] & 2)
99		flags |= right_button;
100	    if (b[0] & 1)
101		flags |= left_button;
102
103	    dx = b[1];
104	    if (b[0] & 0x10)
105		dx -= 256;
106	    dy = b[2];
107	    if (b[0] & 0x20)
108		dy -= 256;
109	    dy = -dy;
110	    n -= 3;
111	    b += 3;
112	    KdEnqueuePointerEvent (closure, flags, dx, dy, 0);
113	}
114    }
115}
116
117static Status
118Ps2Init (KdPointerInfo *pi)
119{
120    int	ps2Port, i;
121
122    if (!pi->path) {
123        for (i = 0; i < NUM_PS2_NAMES; i++) {
124            ps2Port = open (Ps2Names[i], 0);
125            if (ps2Port >= 0) {
126                pi->path = strdup (Ps2Names[i]);
127                break;
128            }
129	}
130    }
131    else {
132        ps2Port = open (pi->path, 0);
133    }
134
135    if (ps2Port < 0)
136        return BadMatch;
137
138    close(ps2Port);
139    if (!pi->name)
140        pi->name = strdup ("PS/2 Mouse");
141
142    return Success;
143}
144
145static Status
146Ps2Enable (KdPointerInfo *pi)
147{
148    int fd;
149
150    if (!pi)
151        return BadImplementation;
152
153    fd = open (pi->path, 0);
154    if (fd < 0)
155        return BadMatch;
156
157    if (!KdRegisterFd (fd, Ps2Read, pi)) {
158        close(fd);
159        return BadAlloc;
160    }
161
162    pi->driverPrivate = (void *)(intptr_t)fd;
163
164    return Success;
165}
166
167
168static void
169Ps2Disable (KdPointerInfo *pi)
170{
171    KdUnregisterFd (pi, (int)(intptr_t)pi->driverPrivate, TRUE);
172}
173
174static void
175Ps2Fini (KdPointerInfo *pi)
176{
177}
178
179KdPointerDriver Ps2MouseDriver = {
180    "ps2",
181    Ps2Init,
182    Ps2Enable,
183    Ps2Disable,
184    Ps2Fini,
185    NULL,
186};
187