Imported Upstream version 1.15.1
[deb_xorg-server.git] / hw / dmx / input / usb-common.c
CommitLineData
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.*/
86void
87usbRead(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
166static void
167usbPrint(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
372device. */
373void
374usbInit(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). */
466void
467usbOff(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. */
477pointer
478usbCreatePrivate(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. */
488void
489usbDestroyPrivate(pointer priv)
490{
491 free(priv);
492}