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