Commit | Line | Data |
---|---|---|
a09e091a JB |
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 | } |