usb-common.c revision 706f2543
1/* 2 * Copyright 2002-2003 Red Hat Inc., Durham, North Carolina. 3 * 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining 7 * a copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation on the rights to use, copy, modify, merge, 10 * publish, distribute, sublicense, and/or sell copies of the Software, 11 * and to permit persons to whom the Software is furnished to do so, 12 * subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial 16 * portions of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS 22 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 23 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 * SOFTWARE. 26 */ 27 28/* 29 * Authors: 30 * Rickard E. (Rik) Faith <faith@redhat.com> 31 * 32 */ 33 34/** \file 35 * 36 * Routines that are common between \a usb-keyboard.c, \a usb-mouse.c, and 37 * \a usb-other.c */ 38 39#ifdef HAVE_DMX_CONFIG_H 40#include <dmx-config.h> 41#endif 42 43#include "usb-private.h" 44 45#define USB_COMMON_DEBUG 1 46 47/*****************************************************************************/ 48/* Define some macros to make it easier to move this file to another 49 * part of the Xserver tree. All calls to the dmx* layer are #defined 50 * here for the .c file. The .h file will also have to be edited. */ 51#include "usb-mouse.h" 52 53#define GETPRIV myPrivate *priv \ 54 = ((DMXLocalInputInfoPtr)(pDev->devicePrivate))->private 55 56#define GETNAME ((DMXLocalInputInfoPtr)(pDevice->public.devicePrivate)) \ 57 ->name 58 59#define LOG0(f) dmxLog(dmxDebug,f) 60#define LOG1(f,a) dmxLog(dmxDebug,f,a) 61#define LOG2(f,a,b) dmxLog(dmxDebug,f,a,b) 62#define LOG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c) 63#define LOG1INPUT(p,f,a) dmxLogInput(p->dmxInput,f,a) 64#define LOG3INPUT(p,f,a,b,c) dmxLogInput(p->dmxInput,f,a,b,c) 65#define LOG5INPUT(p,f,a,b,c,d,e) dmxLogInput(p->dmxInput,f,a,b,c,d,e) 66#define FATAL0(f) dmxLog(dmxFatal,f) 67#define FATAL1(f,a) dmxLog(dmxFatal,f,a) 68#define FATAL2(f,a,b) dmxLog(dmxFatal,f,a,b) 69#define MOTIONPROC dmxMotionProcPtr 70#define ENQUEUEPROC dmxEnqueueProcPtr 71#define CHECKPROC dmxCheckSpecialProcPtr 72#define BLOCK DMXBlockType 73 74/* End of interface definitions. */ 75/*****************************************************************************/ 76 77 78/** Read an event from the \a pDev device. If the event is a motion 79 * event, enqueue it with the \a motion function. Otherwise, enqueue 80 * the event with the \a enqueue function. The \a block type is passed 81 * to the functions so that they may block SIGIO handling as appropriate 82 * to the caller of this function. 83 * 84 * Since USB devices return EV_KEY events for buttons and keys, \a 85 * minButton is used to decide if a Button or Key event should be 86 * queued.*/ 87void usbRead(DevicePtr pDev, 88 MOTIONPROC motion, 89 ENQUEUEPROC enqueue, 90 int minButton, 91 BLOCK block) 92{ 93 GETPRIV; 94 struct input_event raw; 95 int v[DMX_MAX_AXES]; 96 int axis; 97 98#define PRESS(b) \ 99 do { \ 100 enqueue(pDev, ButtonPress, 0, 0, NULL, block); \ 101 } while (0) 102 103#define RELEASE(b) \ 104 do { \ 105 enqueue(pDev, ButtonRelease, 0, 0, NULL, block); \ 106 } while (0) 107 108 while (read(priv->fd, &raw, sizeof(raw)) > 0) { 109#if USB_COMMON_DEBUG > 1 110 LOG3("USB: type = %d, code = 0x%02x, value = %d\n", 111 raw.type, raw.code, raw.value); 112#endif 113 switch (raw.type) { 114 case EV_KEY: 115 /* raw.value = 1 for first, 2 for repeat */ 116 if (raw.code > minButton) { 117 if (raw.value) PRESS((raw.code & 0x0f) + 1); 118 else RELEASE((raw.code & 0x0f) + 1); 119 } else { 120 enqueue(pDev, raw.value ? KeyPress : KeyRelease, 121 0, 0, NULL, block); 122 } 123 break; 124 case EV_REL: 125 switch (raw.code) { 126 case REL_X: 127 v[0] = -raw.value; 128 v[1] = 0; 129 motion(pDev, v, 0, 2, DMX_RELATIVE, block); 130 break; 131 case REL_Y: 132 v[0] = 0; 133 v[1] = -raw.value; 134 motion(pDev, v, 0, 2, DMX_RELATIVE, block); 135 break; 136 case REL_WHEEL: 137 if ((int)raw.value > 0) { 138 PRESS(4); 139 RELEASE(4); 140 } else if ((int)raw.value < 0) { 141 PRESS(5); 142 RELEASE(5); 143 } 144 break; 145 default: 146 memset(v, 0, sizeof(v)); 147 axis = priv->relmap[raw.code]; 148 v[axis] = raw.value; 149 motion(pDev, v, axis, 1, DMX_RELATIVE, block); 150 } 151 break; 152 case EV_ABS: 153 memset(v, 0, sizeof(v)); 154 axis = priv->absmap[raw.code]; 155 v[axis] = raw.value; 156 motion(pDev, v, axis, 1, DMX_ABSOLUTE, block); 157 break; 158 } 159 } 160} 161 162#define test_bit(bit) (priv->mask[(bit)/8] & (1 << ((bit)%8))) 163#define test_bits(bit) (bits[(bit)/8] & (1 << ((bit)%8))) 164 165static void usbPrint(myPrivate *priv, 166 const char *filename, const char *devname, int fd) 167{ 168 int j, k; 169 DeviceIntPtr pDevice = priv->pDevice; 170 unsigned char bits[KEY_MAX/8 + 1]; /* RATS: Use ok assuming that 171 * KEY_MAX is greater than 172 * REL_MAX, ABS_MAX, SND_MAX, and 173 * LED_MAX. */ 174 175 LOG3INPUT(priv, "%s (%s) using %s\n", pDevice->name, GETNAME, filename); 176 LOG1INPUT(priv, " %s\n", devname); 177 for (j = 0; j < EV_MAX; j++) { 178 if (test_bit(j)) { 179 const char *type = "unknown"; 180 char extra[256]; /* FIXME: may cause buffer overflow */ 181 extra[0] = '\0'; 182 switch(j) { 183 case EV_KEY: type = "keys/buttons"; break; 184 case EV_REL: type = "relative"; 185 memset(bits, 0, sizeof(bits)); 186 ioctl(priv->fd, EVIOCGBIT(EV_REL, sizeof(bits)), bits); 187 for (k = 0; k < REL_MAX; k++) { 188 if (test_bits(k)) switch (k) { 189 case REL_X: strcat(extra, " X"); break; 190 case REL_Y: strcat(extra, " Y"); break; 191 case REL_Z: strcat(extra, " Z"); break; 192 case REL_HWHEEL: strcat(extra, " HWheel"); break; 193 case REL_DIAL: strcat(extra, " Dial"); break; 194 case REL_WHEEL: strcat(extra, " Wheel"); break; 195 case REL_MISC: strcat(extra, " Misc"); break; 196 } 197 } 198 break; 199 case EV_ABS: type = "absolute"; 200 memset(bits, 0, sizeof(bits)); 201 ioctl(priv->fd, EVIOCGBIT(EV_ABS, sizeof(bits)), bits); 202 for (k = 0; k < ABS_MAX; k++) { 203 if (test_bits(k)) switch (k) { 204 case ABS_X: strcat(extra," X"); break; 205 case ABS_Y: strcat(extra," Y"); break; 206 case ABS_Z: strcat(extra," Z"); break; 207 case ABS_RX: strcat(extra," RX"); break; 208 case ABS_RY: strcat(extra," RY"); break; 209 case ABS_RZ: strcat(extra," RZ"); break; 210 case ABS_THROTTLE: strcat(extra," Throttle");break; 211 case ABS_RUDDER: strcat(extra," Rudder"); break; 212 case ABS_WHEEL: strcat(extra," Wheel"); break; 213 case ABS_GAS: strcat(extra," Gas"); break; 214 case ABS_BRAKE: strcat(extra," Break"); break; 215 case ABS_HAT0X: strcat(extra," Hat0X"); break; 216 case ABS_HAT0Y: strcat(extra," Hat0Y"); break; 217 case ABS_HAT1X: strcat(extra," Hat1X"); break; 218 case ABS_HAT1Y: strcat(extra," Hat1Y"); break; 219 case ABS_HAT2X: strcat(extra," Hat2X"); break; 220 case ABS_HAT2Y: strcat(extra," Hat2Y"); break; 221 case ABS_HAT3X: strcat(extra," Hat3X"); break; 222 case ABS_HAT3Y: strcat(extra," Hat3Y"); break; 223 case ABS_PRESSURE: strcat(extra," Pressure");break; 224 case ABS_DISTANCE: strcat(extra," Distance");break; 225 case ABS_TILT_X: strcat(extra," TiltX"); break; 226 case ABS_TILT_Y: strcat(extra," TiltY"); break; 227 case ABS_MISC: strcat(extra," Misc"); break; 228 } 229 } 230 break; 231 case EV_MSC: type = "reserved"; break; 232 case EV_LED: type = "leds"; 233 memset(bits, 0, sizeof(bits)); 234 ioctl(priv->fd, EVIOCGBIT(EV_LED, sizeof(bits)), bits); 235 for (k = 0; k < LED_MAX; k++) { 236 if (test_bits(k)) switch (k) { 237 case LED_NUML: strcat(extra," NumLock"); break; 238 case LED_CAPSL: strcat(extra," CapsLock"); break; 239 case LED_SCROLLL: strcat(extra," ScrlLock"); break; 240 case LED_COMPOSE: strcat(extra," Compose"); break; 241 case LED_KANA: strcat(extra," Kana"); break; 242 case LED_SLEEP: strcat(extra," Sleep"); break; 243 case LED_SUSPEND: strcat(extra," Suspend"); break; 244 case LED_MUTE: strcat(extra," Mute"); break; 245 case LED_MISC: strcat(extra," Misc"); break; 246 } 247 } 248 break; 249 case EV_SND: type = "sound"; 250 memset(bits, 0, sizeof(bits)); 251 ioctl(priv->fd, EVIOCGBIT(EV_SND, sizeof(bits)), bits); 252 for (k = 0; k < SND_MAX; k++) { 253 if (test_bits(k)) switch (k) { 254 case SND_CLICK: strcat(extra," Click"); break; 255 case SND_BELL: strcat(extra," Bell"); break; 256 } 257 } 258 break; 259 case EV_REP: type = "repeat"; break; 260 case EV_FF: type = "feedback"; break; 261 } 262 LOG5INPUT(priv, " Feature 0x%02x = %s%s%s%s\n", j, type, 263 extra[0] ? " [" : "", 264 extra[0] ? extra+1 : "", 265 extra[0] ? "]" : ""); 266 } 267 } 268} 269 270/** Initialized \a pDev as a \a usbMouse, \a usbKeyboard, or \a usbOther 271device. */ 272void usbInit(DevicePtr pDev, usbType type) 273{ 274 GETPRIV; 275 char name[64]; /* RATS: Only used in XmuSnprintf */ 276 int i, j, k; 277 char buf[256] = { 0, }; /* RATS: Use ok */ 278 int version; 279 unsigned char bits[KEY_MAX/8 + 1]; /* RATS: Use ok assuming that 280 * KEY_MAX is greater than 281 * REL_MAX, ABS_MAX, SND_MAX, and 282 * LED_MAX. */ 283 284 if (priv->fd >=0) return; 285 286 for (i = 0; i < 32; i++) { 287 XmuSnprintf(name, sizeof(name), "/dev/input/event%d", i); 288 if ((priv->fd = open(name, O_RDWR | O_NONBLOCK, 0)) >= 0) { 289 ioctl(priv->fd, EVIOCGVERSION, &version); 290 ioctl(priv->fd, EVIOCGNAME(sizeof(buf)), buf); 291 memset(priv->mask, 0, sizeof(priv->mask)); 292 ioctl(priv->fd, EVIOCGBIT(0, sizeof(priv->mask)), priv->mask); 293 294 for (j = 0; j < EV_MAX; j++) { 295 if (test_bit(j)) { 296 switch(j) { 297 case EV_REL: 298 memset(bits, 0, sizeof(bits)); 299 ioctl(priv->fd, EVIOCGBIT(EV_REL, sizeof(bits)), bits); 300 for (k = 0; k < REL_MAX; k++) { 301 if (test_bits(k)) { 302 if (k == REL_X) priv->relmap[k] = 0; 303 else if (k == REL_Y) priv->relmap[k] = 1; 304 else priv->relmap[k] = 2 + priv->numAbs; 305 ++priv->numRel; 306 } 307 } 308 break; 309 case EV_ABS: 310 memset(bits, 0, sizeof(bits)); 311 ioctl(priv->fd, EVIOCGBIT(EV_ABS, sizeof(bits)), bits); 312 for (k = 0; k < ABS_MAX; k++) { 313 if (test_bits(k)) { 314 priv->absmap[k] = priv->numAbs; 315 ++priv->numAbs; 316 } 317 } 318 break; 319 case EV_LED: 320 memset(bits, 0, sizeof(bits)); 321 ioctl(priv->fd, EVIOCGBIT(EV_LED, sizeof(bits)), bits); 322 for (k = 0; k < LED_MAX; k++) { 323 if (test_bits(k)) ++priv->numLeds; 324 } 325 break; 326 } 327 } 328 } 329 switch (type) { 330 case usbMouse: 331 if (test_bit(EV_REL) && test_bit(EV_KEY)) 332 goto found; 333 break; 334 case usbKeyboard: 335 if (test_bit(EV_KEY) && test_bit(EV_LED) && !test_bit(EV_ABS)) 336 goto found; 337 break; 338 case usbOther: 339 if (!(test_bit(EV_REL) && test_bit(EV_KEY)) 340 && !(test_bit(EV_KEY) && test_bit(EV_LED) 341 && !test_bit(EV_ABS))) 342 goto found; 343 break; 344 } 345 close(priv->fd); 346 priv->fd = -1; 347 } 348 } 349 if (priv->fd < 0) 350 FATAL1("usbInit: Cannot open /dev/input/event* port (%s)\n" 351 " If you have not done so, you may need to:\n" 352 " rmmod mousedev; rmmod keybdev\n" 353 " modprobe evdev\n", 354 strerror(errno)); 355 found: 356 usbPrint(priv, name, buf, priv->fd); 357} 358 359/** Turn \a pDev off (i.e., stop taking input from \a pDev). */ 360void usbOff(DevicePtr pDev) 361{ 362 GETPRIV; 363 364 if (priv->fd >= 0) close(priv->fd); 365 priv->fd = -1; 366} 367 368/** Create a private structure for use within this file. */ 369pointer usbCreatePrivate(DeviceIntPtr pDevice) 370{ 371 myPrivate *priv = calloc(1, sizeof(*priv)); 372 priv->fd = -1; 373 priv->pDevice = pDevice; 374 return priv; 375} 376 377/** Destroy a private structure. */ 378void usbDestroyPrivate(pointer priv) 379{ 380 free(priv); 381} 382