lnx_mouse.c revision bd3a1963
1
2/*
3 * Copyright 1999 by The XFree86 Project, Inc.
4 */
5
6#ifdef HAVE_CONFIG_H
7#include "config.h"
8#endif
9
10#include <xorg-server.h>
11#include <X11/X.h>
12#include "xf86.h"
13#include "xf86Xinput.h"
14#include "mouse.h"
15#include "xf86_OSlib.h"
16#include <sys/types.h>
17#include <sys/stat.h>
18#include <unistd.h>
19
20static int
21SupportedInterfaces(void)
22{
23    return MSE_SERIAL | MSE_BUS | MSE_PS2 | MSE_XPS2 | MSE_AUTO;
24}
25
26static const char *
27DefaultProtocol(void)
28{
29    return "Auto";
30}
31
32#define DEFAULT_MOUSE_DEV		"/dev/input/mice"
33#define DEFAULT_PS2_DEV			"/dev/psaux"
34#define DEFAULT_GPM_DATA_DEV		"/dev/gpmdata"
35#define DEFAULT_GPM_CTL_DEV		"/dev/gpmdata"
36
37static const char *mouseDevs[] = {
38	DEFAULT_MOUSE_DEV,
39	DEFAULT_PS2_DEV,
40	DEFAULT_GPM_DATA_DEV,
41	NULL
42};
43
44typedef enum {
45	MOUSE_PROTO_UNKNOWN = 0,
46	MOUSE_PROTO_SERIAL,
47	MOUSE_PROTO_PS2,
48	MOUSE_PROTO_MSC,
49	MOUSE_PROTO_GPM,
50	MOUSE_PROTO_EXPPS2,
51} protocolTypes;
52
53static struct {
54	protocolTypes proto;
55	const char *name;
56} devproto[] = {
57	{ MOUSE_PROTO_UNKNOWN,	NULL },
58	{ MOUSE_PROTO_PS2,	"PS/2" },
59	{ MOUSE_PROTO_MSC,	"MouseSystems" },
60	{ MOUSE_PROTO_GPM,	"GPM" },
61	{ MOUSE_PROTO_EXPPS2,   "ExplorerPS/2" },
62};
63
64static const char *
65FindDevice(InputInfoPtr pInfo, const char *protocol, int flags)
66{
67    int fd = -1;
68    const char **pdev;
69
70    for (pdev = mouseDevs; *pdev; pdev++) {
71	SYSCALL (fd = open(*pdev, O_RDWR | O_NONBLOCK | O_EXCL));
72	if (fd == -1) {
73#ifdef DEBUG
74	    ErrorF("Cannot open %s (%s)\n", *pdev, strerror(errno));
75#endif
76	} else
77	    break;
78    }
79
80    if (*pdev) {
81	close(fd);
82	/* Set the Device option. */
83	pInfo->options =
84	    xf86AddNewOption(pInfo->options, "Device", *pdev);
85	xf86Msg(X_INFO, "%s: Setting Device option to \"%s\"\n",
86		pInfo->name, *pdev);
87    }
88
89    return *pdev;
90}
91
92static const char *
93lnxMouseMagic(InputInfoPtr pInfo)
94{
95    int fd = -1;
96    const char *dev;
97    char *realdev;
98    struct stat sbuf;
99    int i;
100    int proto = MOUSE_PROTO_UNKNOWN;
101
102    dev = xf86SetStrOption(pInfo->options, "Device", NULL);
103    if (!dev) {
104#ifdef DEBUG
105	ErrorF("xf86SetStrOption failed to return the device name\n");
106#endif
107	return NULL;
108    }
109    /* Look at the device name to guess the protocol. */
110    realdev = NULL;
111    if (strcmp(dev, DEFAULT_MOUSE_DEV) == 0) {
112	if (lstat(dev, &sbuf) != 0) {
113#ifdef DEBUG
114	    ErrorF("lstat failed for %s (%s)\n", dev, strerror(errno));
115#endif
116	    return NULL;
117	}
118	if (S_ISLNK(sbuf.st_mode)) {
119	    realdev = xnfalloc(PATH_MAX + 1);
120	    i = readlink(dev, realdev, PATH_MAX);
121	    if (i <= 0) {
122#ifdef DEBUG
123		ErrorF("readlink failed for %s (%s)\n", dev, strerror(errno));
124#endif
125		free(realdev);
126		return NULL;
127	    }
128	    realdev[i] = '\0';
129	}
130    }
131    if (!realdev)
132	realdev = xnfstrdup(dev);
133    else {
134	/* If realdev doesn't contain a '/' then prepend "/dev/" */
135	if (!strchr(realdev, '/')) {
136	    char *tmp = xnfalloc(strlen(realdev) + 5 + 1);
137	    sprintf(tmp, "/dev/%s", realdev);
138	    free(realdev);
139	    realdev = tmp;
140	}
141    }
142
143    if (strcmp(realdev, DEFAULT_MOUSE_DEV) == 0)
144	proto = MOUSE_PROTO_EXPPS2;
145    else if (strcmp(realdev, DEFAULT_PS2_DEV) == 0)
146	proto = MOUSE_PROTO_EXPPS2;
147    else if (strcmp(realdev, DEFAULT_GPM_DATA_DEV) == 0)
148	proto = MOUSE_PROTO_MSC;
149    else if (strcmp(realdev, DEFAULT_GPM_CTL_DEV) == 0)
150	proto = MOUSE_PROTO_GPM;
151    free(realdev);
152    /*
153     * If the protocol can't be guessed from the device name,
154     * try to characterise it.
155     */
156    if (proto == MOUSE_PROTO_UNKNOWN) {
157	SYSCALL (fd = open(dev, O_RDWR | O_NONBLOCK | O_EXCL));
158	if (isatty(fd)) {
159	    /* Serial PnP has already failed, so give up. */
160	} else {
161	    if (fstat(fd, &sbuf) != 0) {
162#ifdef DEBUG
163		ErrorF("fstat failed for %s (%s)\n", dev, strerror(errno));
164#endif
165		close(fd);
166		return NULL;
167	    }
168	    if (S_ISFIFO(sbuf.st_mode)) {
169		/* Assume GPM data in MSC format. */
170		proto = MOUSE_PROTO_MSC;
171	    } else {
172		/* Default to PS/2 */
173		proto = MOUSE_PROTO_PS2;
174	    }
175	}
176	close(fd);
177    }
178    if (proto == MOUSE_PROTO_UNKNOWN) {
179	xf86Msg(X_ERROR, "%s: Cannot find mouse protocol.\n",
180		pInfo->name);
181	return NULL;
182    } else {
183	for (i = 0; i < sizeof(devproto)/sizeof(devproto[0]); i++) {
184	    if (devproto[i].proto == proto) {
185		xf86Msg(X_INFO,
186			"%s: Setting mouse protocol to \"%s\"\n",
187			pInfo->name, devproto[i].name);
188		return devproto[i].name;
189	    }
190	}
191    }
192    return NULL;
193}
194
195static const char *
196GuessProtocol(InputInfoPtr pInfo, int flags)
197{
198    return lnxMouseMagic(pInfo);
199}
200
201static const char *
202SetupAuto(InputInfoPtr pInfo, int *protoPara)
203{
204    return lnxMouseMagic(pInfo);
205}
206
207OSMouseInfoPtr
208OSMouseInit(int flags)
209{
210    OSMouseInfoPtr p;
211
212    p = calloc(sizeof(OSMouseInfoRec), 1);
213    if (!p)
214	return NULL;
215    p->SupportedInterfaces = SupportedInterfaces;
216    p->DefaultProtocol = DefaultProtocol;
217    p->FindDevice = FindDevice;
218    p->GuessProtocol = GuessProtocol;
219    p->SetupAuto = SetupAuto;
220    return p;
221}
222
223