| 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 | /** Read an event from the \a pDev device. If the event is a motion |
| 78 | * event, enqueue it with the \a motion function. Otherwise, enqueue |
| 79 | * the event with the \a enqueue function. The \a block type is passed |
| 80 | * to the functions so that they may block SIGIO handling as appropriate |
| 81 | * to the caller of this function. |
| 82 | * |
| 83 | * Since USB devices return EV_KEY events for buttons and keys, \a |
| 84 | * minButton is used to decide if a Button or Key event should be |
| 85 | * queued.*/ |
| 86 | void |
| 87 | usbRead(DevicePtr pDev, |
| 88 | MOTIONPROC motion, ENQUEUEPROC enqueue, int minButton, BLOCK block) |
| 89 | { |
| 90 | GETPRIV; |
| 91 | struct input_event raw; |
| 92 | int v[DMX_MAX_AXES]; |
| 93 | int axis; |
| 94 | |
| 95 | #define PRESS(b) \ |
| 96 | do { \ |
| 97 | enqueue(pDev, ButtonPress, 0, 0, NULL, block); \ |
| 98 | } while (0) |
| 99 | |
| 100 | #define RELEASE(b) \ |
| 101 | do { \ |
| 102 | enqueue(pDev, ButtonRelease, 0, 0, NULL, block); \ |
| 103 | } while (0) |
| 104 | |
| 105 | while (read(priv->fd, &raw, sizeof(raw)) > 0) { |
| 106 | #if USB_COMMON_DEBUG > 1 |
| 107 | LOG3("USB: type = %d, code = 0x%02x, value = %d\n", |
| 108 | raw.type, raw.code, raw.value); |
| 109 | #endif |
| 110 | switch (raw.type) { |
| 111 | case EV_KEY: |
| 112 | /* raw.value = 1 for first, 2 for repeat */ |
| 113 | if (raw.code > minButton) { |
| 114 | if (raw.value) |
| 115 | PRESS((raw.code & 0x0f) + 1); |
| 116 | else |
| 117 | RELEASE((raw.code & 0x0f) + 1); |
| 118 | } |
| 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 | } |
| 141 | else if ((int) raw.value < 0) { |
| 142 | PRESS(5); |
| 143 | RELEASE(5); |
| 144 | } |
| 145 | break; |
| 146 | default: |
| 147 | memset(v, 0, sizeof(v)); |
| 148 | axis = priv->relmap[raw.code]; |
| 149 | v[axis] = raw.value; |
| 150 | motion(pDev, v, axis, 1, DMX_RELATIVE, block); |
| 151 | } |
| 152 | break; |
| 153 | case EV_ABS: |
| 154 | memset(v, 0, sizeof(v)); |
| 155 | axis = priv->absmap[raw.code]; |
| 156 | v[axis] = raw.value; |
| 157 | motion(pDev, v, axis, 1, DMX_ABSOLUTE, block); |
| 158 | break; |
| 159 | } |
| 160 | } |
| 161 | } |
| 162 | |
| 163 | #define test_bit(bit) (priv->mask[(bit)/8] & (1 << ((bit)%8))) |
| 164 | #define test_bits(bit) (bits[(bit)/8] & (1 << ((bit)%8))) |
| 165 | |
| 166 | static void |
| 167 | usbPrint(myPrivate * priv, const char *filename, const char *devname, int fd) |
| 168 | { |
| 169 | int j, k; |
| 170 | DeviceIntPtr pDevice = priv->pDevice; |
| 171 | unsigned char bits[KEY_MAX / 8 + 1]; /* RATS: Use ok assuming that |
| 172 | * KEY_MAX is greater than |
| 173 | * REL_MAX, ABS_MAX, SND_MAX, and |
| 174 | * LED_MAX. */ |
| 175 | |
| 176 | LOG3INPUT(priv, "%s (%s) using %s\n", pDevice->name, GETNAME, filename); |
| 177 | LOG1INPUT(priv, " %s\n", devname); |
| 178 | for (j = 0; j < EV_MAX; j++) { |
| 179 | if (test_bit(j)) { |
| 180 | const char *type = "unknown"; |
| 181 | char extra[256]; /* FIXME: may cause buffer overflow */ |
| 182 | |
| 183 | extra[0] = '\0'; |
| 184 | switch (j) { |
| 185 | case EV_KEY: |
| 186 | type = "keys/buttons"; |
| 187 | break; |
| 188 | case EV_REL: |
| 189 | type = "relative"; |
| 190 | memset(bits, 0, sizeof(bits)); |
| 191 | ioctl(priv->fd, EVIOCGBIT(EV_REL, sizeof(bits)), bits); |
| 192 | for (k = 0; k < REL_MAX; k++) { |
| 193 | if (test_bits(k)) |
| 194 | switch (k) { |
| 195 | case REL_X: |
| 196 | strcat(extra, " X"); |
| 197 | break; |
| 198 | case REL_Y: |
| 199 | strcat(extra, " Y"); |
| 200 | break; |
| 201 | case REL_Z: |
| 202 | strcat(extra, " Z"); |
| 203 | break; |
| 204 | case REL_HWHEEL: |
| 205 | strcat(extra, " HWheel"); |
| 206 | break; |
| 207 | case REL_DIAL: |
| 208 | strcat(extra, " Dial"); |
| 209 | break; |
| 210 | case REL_WHEEL: |
| 211 | strcat(extra, " Wheel"); |
| 212 | break; |
| 213 | case REL_MISC: |
| 214 | strcat(extra, " Misc"); |
| 215 | break; |
| 216 | } |
| 217 | } |
| 218 | break; |
| 219 | case EV_ABS: |
| 220 | type = "absolute"; |
| 221 | memset(bits, 0, sizeof(bits)); |
| 222 | ioctl(priv->fd, EVIOCGBIT(EV_ABS, sizeof(bits)), bits); |
| 223 | for (k = 0; k < ABS_MAX; k++) { |
| 224 | if (test_bits(k)) |
| 225 | switch (k) { |
| 226 | case ABS_X: |
| 227 | strcat(extra, " X"); |
| 228 | break; |
| 229 | case ABS_Y: |
| 230 | strcat(extra, " Y"); |
| 231 | break; |
| 232 | case ABS_Z: |
| 233 | strcat(extra, " Z"); |
| 234 | break; |
| 235 | case ABS_RX: |
| 236 | strcat(extra, " RX"); |
| 237 | break; |
| 238 | case ABS_RY: |
| 239 | strcat(extra, " RY"); |
| 240 | break; |
| 241 | case ABS_RZ: |
| 242 | strcat(extra, " RZ"); |
| 243 | break; |
| 244 | case ABS_THROTTLE: |
| 245 | strcat(extra, " Throttle"); |
| 246 | break; |
| 247 | case ABS_RUDDER: |
| 248 | strcat(extra, " Rudder"); |
| 249 | break; |
| 250 | case ABS_WHEEL: |
| 251 | strcat(extra, " Wheel"); |
| 252 | break; |
| 253 | case ABS_GAS: |
| 254 | strcat(extra, " Gas"); |
| 255 | break; |
| 256 | case ABS_BRAKE: |
| 257 | strcat(extra, " Break"); |
| 258 | break; |
| 259 | case ABS_HAT0X: |
| 260 | strcat(extra, " Hat0X"); |
| 261 | break; |
| 262 | case ABS_HAT0Y: |
| 263 | strcat(extra, " Hat0Y"); |
| 264 | break; |
| 265 | case ABS_HAT1X: |
| 266 | strcat(extra, " Hat1X"); |
| 267 | break; |
| 268 | case ABS_HAT1Y: |
| 269 | strcat(extra, " Hat1Y"); |
| 270 | break; |
| 271 | case ABS_HAT2X: |
| 272 | strcat(extra, " Hat2X"); |
| 273 | break; |
| 274 | case ABS_HAT2Y: |
| 275 | strcat(extra, " Hat2Y"); |
| 276 | break; |
| 277 | case ABS_HAT3X: |
| 278 | strcat(extra, " Hat3X"); |
| 279 | break; |
| 280 | case ABS_HAT3Y: |
| 281 | strcat(extra, " Hat3Y"); |
| 282 | break; |
| 283 | case ABS_PRESSURE: |
| 284 | strcat(extra, " Pressure"); |
| 285 | break; |
| 286 | case ABS_DISTANCE: |
| 287 | strcat(extra, " Distance"); |
| 288 | break; |
| 289 | case ABS_TILT_X: |
| 290 | strcat(extra, " TiltX"); |
| 291 | break; |
| 292 | case ABS_TILT_Y: |
| 293 | strcat(extra, " TiltY"); |
| 294 | break; |
| 295 | case ABS_MISC: |
| 296 | strcat(extra, " Misc"); |
| 297 | break; |
| 298 | } |
| 299 | } |
| 300 | break; |
| 301 | case EV_MSC: |
| 302 | type = "reserved"; |
| 303 | break; |
| 304 | case EV_LED: |
| 305 | type = "leds"; |
| 306 | memset(bits, 0, sizeof(bits)); |
| 307 | ioctl(priv->fd, EVIOCGBIT(EV_LED, sizeof(bits)), bits); |
| 308 | for (k = 0; k < LED_MAX; k++) { |
| 309 | if (test_bits(k)) |
| 310 | switch (k) { |
| 311 | case LED_NUML: |
| 312 | strcat(extra, " NumLock"); |
| 313 | break; |
| 314 | case LED_CAPSL: |
| 315 | strcat(extra, " CapsLock"); |
| 316 | break; |
| 317 | case LED_SCROLLL: |
| 318 | strcat(extra, " ScrlLock"); |
| 319 | break; |
| 320 | case LED_COMPOSE: |
| 321 | strcat(extra, " Compose"); |
| 322 | break; |
| 323 | case LED_KANA: |
| 324 | strcat(extra, " Kana"); |
| 325 | break; |
| 326 | case LED_SLEEP: |
| 327 | strcat(extra, " Sleep"); |
| 328 | break; |
| 329 | case LED_SUSPEND: |
| 330 | strcat(extra, " Suspend"); |
| 331 | break; |
| 332 | case LED_MUTE: |
| 333 | strcat(extra, " Mute"); |
| 334 | break; |
| 335 | case LED_MISC: |
| 336 | strcat(extra, " Misc"); |
| 337 | break; |
| 338 | } |
| 339 | } |
| 340 | break; |
| 341 | case EV_SND: |
| 342 | type = "sound"; |
| 343 | memset(bits, 0, sizeof(bits)); |
| 344 | ioctl(priv->fd, EVIOCGBIT(EV_SND, sizeof(bits)), bits); |
| 345 | for (k = 0; k < SND_MAX; k++) { |
| 346 | if (test_bits(k)) |
| 347 | switch (k) { |
| 348 | case SND_CLICK: |
| 349 | strcat(extra, " Click"); |
| 350 | break; |
| 351 | case SND_BELL: |
| 352 | strcat(extra, " Bell"); |
| 353 | break; |
| 354 | } |
| 355 | } |
| 356 | break; |
| 357 | case EV_REP: |
| 358 | type = "repeat"; |
| 359 | break; |
| 360 | case EV_FF: |
| 361 | type = "feedback"; |
| 362 | break; |
| 363 | } |
| 364 | LOG5INPUT(priv, " Feature 0x%02x = %s%s%s%s\n", j, type, |
| 365 | extra[0] ? " [" : "", |
| 366 | extra[0] ? extra + 1 : "", extra[0] ? "]" : ""); |
| 367 | } |
| 368 | } |
| 369 | } |
| 370 | |
| 371 | /** Initialized \a pDev as a \a usbMouse, \a usbKeyboard, or \a usbOther |
| 372 | device. */ |
| 373 | void |
| 374 | usbInit(DevicePtr pDev, usbType type) |
| 375 | { |
| 376 | GETPRIV; |
| 377 | char name[64]; /* RATS: Only used in snprintf */ |
| 378 | int i, j, k; |
| 379 | char buf[256] = { 0, }; /* RATS: Use ok */ |
| 380 | int version; |
| 381 | unsigned char bits[KEY_MAX / 8 + 1]; /* RATS: Use ok assuming that |
| 382 | * KEY_MAX is greater than |
| 383 | * REL_MAX, ABS_MAX, SND_MAX, and |
| 384 | * LED_MAX. */ |
| 385 | |
| 386 | if (priv->fd >= 0) |
| 387 | return; |
| 388 | |
| 389 | for (i = 0; i < 32; i++) { |
| 390 | snprintf(name, sizeof(name), "/dev/input/event%d", i); |
| 391 | if ((priv->fd = open(name, O_RDWR | O_NONBLOCK, 0)) >= 0) { |
| 392 | ioctl(priv->fd, EVIOCGVERSION, &version); |
| 393 | ioctl(priv->fd, EVIOCGNAME(sizeof(buf)), buf); |
| 394 | memset(priv->mask, 0, sizeof(priv->mask)); |
| 395 | ioctl(priv->fd, EVIOCGBIT(0, sizeof(priv->mask)), priv->mask); |
| 396 | |
| 397 | for (j = 0; j < EV_MAX; j++) { |
| 398 | if (test_bit(j)) { |
| 399 | switch (j) { |
| 400 | case EV_REL: |
| 401 | memset(bits, 0, sizeof(bits)); |
| 402 | ioctl(priv->fd, EVIOCGBIT(EV_REL, sizeof(bits)), bits); |
| 403 | for (k = 0; k < REL_MAX; k++) { |
| 404 | if (test_bits(k)) { |
| 405 | if (k == REL_X) |
| 406 | priv->relmap[k] = 0; |
| 407 | else if (k == REL_Y) |
| 408 | priv->relmap[k] = 1; |
| 409 | else |
| 410 | priv->relmap[k] = 2 + priv->numAbs; |
| 411 | ++priv->numRel; |
| 412 | } |
| 413 | } |
| 414 | break; |
| 415 | case EV_ABS: |
| 416 | memset(bits, 0, sizeof(bits)); |
| 417 | ioctl(priv->fd, EVIOCGBIT(EV_ABS, sizeof(bits)), bits); |
| 418 | for (k = 0; k < ABS_MAX; k++) { |
| 419 | if (test_bits(k)) { |
| 420 | priv->absmap[k] = priv->numAbs; |
| 421 | ++priv->numAbs; |
| 422 | } |
| 423 | } |
| 424 | break; |
| 425 | case EV_LED: |
| 426 | memset(bits, 0, sizeof(bits)); |
| 427 | ioctl(priv->fd, EVIOCGBIT(EV_LED, sizeof(bits)), bits); |
| 428 | for (k = 0; k < LED_MAX; k++) { |
| 429 | if (test_bits(k)) |
| 430 | ++priv->numLeds; |
| 431 | } |
| 432 | break; |
| 433 | } |
| 434 | } |
| 435 | } |
| 436 | switch (type) { |
| 437 | case usbMouse: |
| 438 | if (test_bit(EV_REL) && test_bit(EV_KEY)) |
| 439 | goto found; |
| 440 | break; |
| 441 | case usbKeyboard: |
| 442 | if (test_bit(EV_KEY) && test_bit(EV_LED) && !test_bit(EV_ABS)) |
| 443 | goto found; |
| 444 | break; |
| 445 | case usbOther: |
| 446 | if (!(test_bit(EV_REL) && test_bit(EV_KEY)) |
| 447 | && !(test_bit(EV_KEY) && test_bit(EV_LED) |
| 448 | && !test_bit(EV_ABS))) |
| 449 | goto found; |
| 450 | break; |
| 451 | } |
| 452 | close(priv->fd); |
| 453 | priv->fd = -1; |
| 454 | } |
| 455 | } |
| 456 | if (priv->fd < 0) |
| 457 | FATAL1("usbInit: Cannot open /dev/input/event* port (%s)\n" |
| 458 | " If you have not done so, you may need to:\n" |
| 459 | " rmmod mousedev; rmmod keybdev\n" |
| 460 | " modprobe evdev\n", strerror(errno)); |
| 461 | found: |
| 462 | usbPrint(priv, name, buf, priv->fd); |
| 463 | } |
| 464 | |
| 465 | /** Turn \a pDev off (i.e., stop taking input from \a pDev). */ |
| 466 | void |
| 467 | usbOff(DevicePtr pDev) |
| 468 | { |
| 469 | GETPRIV; |
| 470 | |
| 471 | if (priv->fd >= 0) |
| 472 | close(priv->fd); |
| 473 | priv->fd = -1; |
| 474 | } |
| 475 | |
| 476 | /** Create a private structure for use within this file. */ |
| 477 | pointer |
| 478 | usbCreatePrivate(DeviceIntPtr pDevice) |
| 479 | { |
| 480 | myPrivate *priv = calloc(1, sizeof(*priv)); |
| 481 | |
| 482 | priv->fd = -1; |
| 483 | priv->pDevice = pDevice; |
| 484 | return priv; |
| 485 | } |
| 486 | |
| 487 | /** Destroy a private structure. */ |
| 488 | void |
| 489 | usbDestroyPrivate(pointer priv) |
| 490 | { |
| 491 | free(priv); |
| 492 | } |