2 * Copyright 2002-2003 Red Hat Inc., Durham, North Carolina.
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:
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.
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
30 * Rickard E. (Rik) Faith <faith@redhat.com>
36 * Routines that are common between #usb-keyboard.c, #usb-mouse.c, and
39 #ifdef HAVE_DMX_CONFIG_H
40 #include <dmx-config.h>
43 #include "usb-private.h"
45 #define USB_COMMON_DEBUG 1
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"
53 #define GETPRIV myPrivate *priv \
54 = ((DMXLocalInputInfoPtr)(pDev->devicePrivate))->private
56 #define GETNAME ((DMXLocalInputInfoPtr)(pDevice->public.devicePrivate)) \
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
74 /* End of interface definitions. */
75 /*****************************************************************************/
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.
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
87 void usbRead(DevicePtr pDev
,
94 struct input_event raw
;
100 enqueue(pDev, ButtonPress, 0, 0, NULL, block); \
105 enqueue(pDev, ButtonRelease, 0, 0, NULL, block); \
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
);
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);
120 enqueue(pDev
, raw
.value
? KeyPress
: KeyRelease
,
129 motion(pDev
, v
, 0, 2, DMX_RELATIVE
, block
);
134 motion(pDev
, v
, 0, 2, DMX_RELATIVE
, block
);
137 if ((int)raw
.value
> 0) {
140 } else if ((int)raw
.value
< 0) {
146 memset(v
, 0, sizeof(v
));
147 axis
= priv
->relmap
[raw
.code
];
149 motion(pDev
, v
, axis
, 1, DMX_RELATIVE
, block
);
153 memset(v
, 0, sizeof(v
));
154 axis
= priv
->absmap
[raw
.code
];
156 motion(pDev
, v
, axis
, 1, DMX_ABSOLUTE
, block
);
162 #define test_bit(bit) (priv->mask[(bit)/8] & (1 << ((bit)%8)))
163 #define test_bits(bit) (bits[(bit)/8] & (1 << ((bit)%8)))
165 static void usbPrint(myPrivate
*priv
,
166 const char *filename
, const char *devname
, int fd
)
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
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
++) {
179 const char *type
= "unknown";
180 char extra
[256]; /* FIXME: may cause buffer overflow */
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;
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;
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;
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;
259 case EV_REP
: type
= "repeat"; break;
260 case EV_FF
: type
= "feedback"; break;
262 LOG5INPUT(priv
, " Feature 0x%02x = %s%s%s%s\n", j
, type
,
263 extra
[0] ? " [" : "",
264 extra
[0] ? extra
+1 : "",
265 extra
[0] ? "]" : "");
270 /** Initialized \a pDev as a \a usbMouse, \a usbKeyboard, or \a usbOther
272 void usbInit(DevicePtr pDev
, usbType type
)
275 char name
[64]; /* RATS: Only used in XmuSnprintf */
277 char buf
[256] = { 0, }; /* RATS: Use ok */
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
284 if (priv
->fd
>=0) return;
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
);
294 for (j
= 0; j
< EV_MAX
; j
++) {
298 memset(bits
, 0, sizeof(bits
));
299 ioctl(priv
->fd
, EVIOCGBIT(EV_REL
, sizeof(bits
)), bits
);
300 for (k
= 0; k
< REL_MAX
; 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
;
310 memset(bits
, 0, sizeof(bits
));
311 ioctl(priv
->fd
, EVIOCGBIT(EV_ABS
, sizeof(bits
)), bits
);
312 for (k
= 0; k
< ABS_MAX
; k
++) {
314 priv
->absmap
[k
] = priv
->numAbs
;
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
;
331 if (test_bit(EV_REL
) && test_bit(EV_KEY
))
335 if (test_bit(EV_KEY
) && test_bit(EV_LED
) && !test_bit(EV_ABS
))
339 if (!(test_bit(EV_REL
) && test_bit(EV_KEY
))
340 && !(test_bit(EV_KEY
) && test_bit(EV_LED
)
341 && !test_bit(EV_ABS
)))
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"
356 usbPrint(priv
, name
, buf
, priv
->fd
);
359 /** Turn \a pDev off (i.e., stop taking input from \a pDev). */
360 void usbOff(DevicePtr pDev
)
364 if (priv
->fd
>= 0) close(priv
->fd
);
368 /** Create a private structure for use within this file. */
369 pointer
usbCreatePrivate(DeviceIntPtr pDevice
)
371 myPrivate
*priv
= xalloc(sizeof(*priv
));
372 memset(priv
, 0, sizeof(*priv
));
374 priv
->pDevice
= pDevice
;
378 /** Destroy a private structure. */
379 void usbDestroyPrivate(pointer priv
)
381 if (priv
) xfree(priv
);