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