16aab59a7Smrg
26aab59a7Smrg/*
36aab59a7Smrg * Copyright 1999 by The XFree86 Project, Inc.
46aab59a7Smrg */
56aab59a7Smrg
66aab59a7Smrg#ifdef HAVE_CONFIG_H
76aab59a7Smrg#include "config.h"
86aab59a7Smrg#endif
96aab59a7Smrg
10b73be646Smrg#include <xorg-server.h>
116aab59a7Smrg#include <X11/X.h>
126aab59a7Smrg#include "xf86.h"
136aab59a7Smrg#include "xf86Xinput.h"
14bd3a1963Smrg#include "mouse.h"
156aab59a7Smrg#include "xf86_OSlib.h"
166aab59a7Smrg#include <sys/types.h>
176aab59a7Smrg#include <sys/stat.h>
186aab59a7Smrg#include <unistd.h>
196aab59a7Smrg
206aab59a7Smrgstatic int
216aab59a7SmrgSupportedInterfaces(void)
226aab59a7Smrg{
236aab59a7Smrg    return MSE_SERIAL | MSE_BUS | MSE_PS2 | MSE_XPS2 | MSE_AUTO;
246aab59a7Smrg}
256aab59a7Smrg
266aab59a7Smrgstatic const char *
276aab59a7SmrgDefaultProtocol(void)
286aab59a7Smrg{
296aab59a7Smrg    return "Auto";
306aab59a7Smrg}
316aab59a7Smrg
32a73597f9Smrg#define DEFAULT_MOUSE_DEV               "/dev/input/mice"
33a73597f9Smrg#define DEFAULT_PS2_DEV                 "/dev/psaux"
34a73597f9Smrg#define DEFAULT_GPM_DATA_DEV            "/dev/gpmdata"
35a73597f9Smrg#define DEFAULT_GPM_CTL_DEV             "/dev/gpmdata"
366aab59a7Smrg
376aab59a7Smrgstatic const char *mouseDevs[] = {
38a73597f9Smrg        DEFAULT_MOUSE_DEV,
39a73597f9Smrg        DEFAULT_PS2_DEV,
40a73597f9Smrg        DEFAULT_GPM_DATA_DEV,
41a73597f9Smrg        NULL
426aab59a7Smrg};
436aab59a7Smrg
446aab59a7Smrgtypedef enum {
45a73597f9Smrg        MOUSE_PROTO_UNKNOWN = 0,
46a73597f9Smrg        MOUSE_PROTO_SERIAL,
47a73597f9Smrg        MOUSE_PROTO_PS2,
48a73597f9Smrg        MOUSE_PROTO_MSC,
49a73597f9Smrg        MOUSE_PROTO_GPM,
50a73597f9Smrg        MOUSE_PROTO_EXPPS2,
516aab59a7Smrg} protocolTypes;
526aab59a7Smrg
536aab59a7Smrgstatic struct {
54a73597f9Smrg        protocolTypes proto;
55a73597f9Smrg        const char *name;
566aab59a7Smrg} devproto[] = {
57a73597f9Smrg        { MOUSE_PROTO_UNKNOWN,  NULL },
58a73597f9Smrg        { MOUSE_PROTO_PS2,      "PS/2" },
59a73597f9Smrg        { MOUSE_PROTO_MSC,      "MouseSystems" },
60a73597f9Smrg        { MOUSE_PROTO_GPM,      "GPM" },
61a73597f9Smrg        { MOUSE_PROTO_EXPPS2,   "ExplorerPS/2" },
626aab59a7Smrg};
636aab59a7Smrg
646aab59a7Smrgstatic const char *
656aab59a7SmrgFindDevice(InputInfoPtr pInfo, const char *protocol, int flags)
666aab59a7Smrg{
676aab59a7Smrg    int fd = -1;
686aab59a7Smrg    const char **pdev;
696aab59a7Smrg
706aab59a7Smrg    for (pdev = mouseDevs; *pdev; pdev++) {
71a73597f9Smrg        SYSCALL (fd = open(*pdev, O_RDWR | O_NONBLOCK | O_EXCL));
72a73597f9Smrg        if (fd == -1) {
736aab59a7Smrg#ifdef DEBUG
74a73597f9Smrg            ErrorF("Cannot open %s (%s)\n", *pdev, strerror(errno));
756aab59a7Smrg#endif
76a73597f9Smrg        } else
77a73597f9Smrg            break;
786aab59a7Smrg    }
796aab59a7Smrg
806aab59a7Smrg    if (*pdev) {
81a73597f9Smrg        close(fd);
82a73597f9Smrg        /* Set the Device option. */
83a73597f9Smrg        pInfo->options =
84a73597f9Smrg            xf86AddNewOption(pInfo->options, "Device", *pdev);
85a73597f9Smrg        xf86Msg(X_INFO, "%s: Setting Device option to \"%s\"\n",
86a73597f9Smrg                pInfo->name, *pdev);
876aab59a7Smrg    }
886aab59a7Smrg
896aab59a7Smrg    return *pdev;
906aab59a7Smrg}
916aab59a7Smrg
926aab59a7Smrgstatic const char *
936aab59a7SmrglnxMouseMagic(InputInfoPtr pInfo)
946aab59a7Smrg{
956aab59a7Smrg    int fd = -1;
966aab59a7Smrg    const char *dev;
976aab59a7Smrg    char *realdev;
986aab59a7Smrg    struct stat sbuf;
996aab59a7Smrg    int i;
1006aab59a7Smrg    int proto = MOUSE_PROTO_UNKNOWN;
1016aab59a7Smrg
102bd3a1963Smrg    dev = xf86SetStrOption(pInfo->options, "Device", NULL);
1036aab59a7Smrg    if (!dev) {
1046aab59a7Smrg#ifdef DEBUG
105a73597f9Smrg        ErrorF("xf86SetStrOption failed to return the device name\n");
1066aab59a7Smrg#endif
107a73597f9Smrg        return NULL;
1086aab59a7Smrg    }
1096aab59a7Smrg    /* Look at the device name to guess the protocol. */
1106aab59a7Smrg    realdev = NULL;
1116aab59a7Smrg    if (strcmp(dev, DEFAULT_MOUSE_DEV) == 0) {
112a73597f9Smrg        if (lstat(dev, &sbuf) != 0) {
1136aab59a7Smrg#ifdef DEBUG
114a73597f9Smrg            ErrorF("lstat failed for %s (%s)\n", dev, strerror(errno));
1156aab59a7Smrg#endif
116a73597f9Smrg            return NULL;
117a73597f9Smrg        }
118a73597f9Smrg        if (S_ISLNK(sbuf.st_mode)) {
119a73597f9Smrg            realdev = xnfalloc(PATH_MAX + 1);
120a73597f9Smrg            i = readlink(dev, realdev, PATH_MAX);
121a73597f9Smrg            if (i <= 0) {
1226aab59a7Smrg#ifdef DEBUG
123a73597f9Smrg                ErrorF("readlink failed for %s (%s)\n", dev, strerror(errno));
1246aab59a7Smrg#endif
125a73597f9Smrg                free(realdev);
126a73597f9Smrg                return NULL;
127a73597f9Smrg            }
128a73597f9Smrg            realdev[i] = '\0';
129a73597f9Smrg        }
1306aab59a7Smrg    }
1316aab59a7Smrg    if (!realdev)
132a73597f9Smrg        realdev = xnfstrdup(dev);
1336aab59a7Smrg    else {
134a73597f9Smrg        /* If realdev doesn't contain a '/' then prepend "/dev/" */
135a73597f9Smrg        if (!strchr(realdev, '/')) {
136a73597f9Smrg            char *tmp = xnfalloc(strlen(realdev) + 5 + 1);
137a73597f9Smrg            sprintf(tmp, "/dev/%s", realdev);
138a73597f9Smrg            free(realdev);
139a73597f9Smrg            realdev = tmp;
140a73597f9Smrg        }
1416aab59a7Smrg    }
1426aab59a7Smrg
1436aab59a7Smrg    if (strcmp(realdev, DEFAULT_MOUSE_DEV) == 0)
144a73597f9Smrg        proto = MOUSE_PROTO_EXPPS2;
1456aab59a7Smrg    else if (strcmp(realdev, DEFAULT_PS2_DEV) == 0)
146a73597f9Smrg        proto = MOUSE_PROTO_EXPPS2;
1476aab59a7Smrg    else if (strcmp(realdev, DEFAULT_GPM_DATA_DEV) == 0)
148a73597f9Smrg        proto = MOUSE_PROTO_MSC;
1496aab59a7Smrg    else if (strcmp(realdev, DEFAULT_GPM_CTL_DEV) == 0)
150a73597f9Smrg        proto = MOUSE_PROTO_GPM;
151bd3a1963Smrg    free(realdev);
1526aab59a7Smrg    /*
1536aab59a7Smrg     * If the protocol can't be guessed from the device name,
1546aab59a7Smrg     * try to characterise it.
1556aab59a7Smrg     */
1566aab59a7Smrg    if (proto == MOUSE_PROTO_UNKNOWN) {
157a73597f9Smrg        SYSCALL (fd = open(dev, O_RDWR | O_NONBLOCK | O_EXCL));
158a73597f9Smrg        if (isatty(fd)) {
159a73597f9Smrg            /* Serial PnP has already failed, so give up. */
160a73597f9Smrg        } else {
161a73597f9Smrg            if (fstat(fd, &sbuf) != 0) {
1626aab59a7Smrg#ifdef DEBUG
163a73597f9Smrg                ErrorF("fstat failed for %s (%s)\n", dev, strerror(errno));
1646aab59a7Smrg#endif
165a73597f9Smrg                close(fd);
166a73597f9Smrg                return NULL;
167a73597f9Smrg            }
168a73597f9Smrg            if (S_ISFIFO(sbuf.st_mode)) {
169a73597f9Smrg                /* Assume GPM data in MSC format. */
170a73597f9Smrg                proto = MOUSE_PROTO_MSC;
171a73597f9Smrg            } else {
172a73597f9Smrg                /* Default to PS/2 */
173a73597f9Smrg                proto = MOUSE_PROTO_PS2;
174a73597f9Smrg            }
175a73597f9Smrg        }
176a73597f9Smrg        close(fd);
1776aab59a7Smrg    }
1786aab59a7Smrg    if (proto == MOUSE_PROTO_UNKNOWN) {
179a73597f9Smrg        xf86Msg(X_ERROR, "%s: Cannot find mouse protocol.\n",
180a73597f9Smrg                pInfo->name);
181a73597f9Smrg        return NULL;
1826aab59a7Smrg    } else {
183a73597f9Smrg        for (i = 0; i < sizeof(devproto)/sizeof(devproto[0]); i++) {
184a73597f9Smrg            if (devproto[i].proto == proto) {
185a73597f9Smrg                xf86Msg(X_INFO,
186a73597f9Smrg                        "%s: Setting mouse protocol to \"%s\"\n",
187a73597f9Smrg                        pInfo->name, devproto[i].name);
188a73597f9Smrg                return devproto[i].name;
189a73597f9Smrg            }
190a73597f9Smrg        }
1916aab59a7Smrg    }
1926aab59a7Smrg    return NULL;
1936aab59a7Smrg}
1946aab59a7Smrg
1956aab59a7Smrgstatic const char *
1966aab59a7SmrgGuessProtocol(InputInfoPtr pInfo, int flags)
1976aab59a7Smrg{
1986aab59a7Smrg    return lnxMouseMagic(pInfo);
1996aab59a7Smrg}
2006aab59a7Smrg
2016aab59a7Smrgstatic const char *
2026aab59a7SmrgSetupAuto(InputInfoPtr pInfo, int *protoPara)
2036aab59a7Smrg{
2046aab59a7Smrg    return lnxMouseMagic(pInfo);
2056aab59a7Smrg}
2066aab59a7Smrg
207bd3a1963SmrgOSMouseInfoPtr
208bd3a1963SmrgOSMouseInit(int flags)
2096aab59a7Smrg{
2106aab59a7Smrg    OSMouseInfoPtr p;
2116aab59a7Smrg
212bd3a1963Smrg    p = calloc(sizeof(OSMouseInfoRec), 1);
2136aab59a7Smrg    if (!p)
214a73597f9Smrg        return NULL;
2156aab59a7Smrg    p->SupportedInterfaces = SupportedInterfaces;
2166aab59a7Smrg    p->DefaultProtocol = DefaultProtocol;
2176aab59a7Smrg    p->FindDevice = FindDevice;
2186aab59a7Smrg    p->GuessProtocol = GuessProtocol;
2196aab59a7Smrg    p->SetupAuto = SetupAuto;
2206aab59a7Smrg    return p;
2216aab59a7Smrg}
2226aab59a7Smrg
223