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