Commit | Line | Data |
---|---|---|
a09e091a JB |
1 | /* |
2 | * Copyright © 2004 Keith Packard | |
3 | * | |
4 | * Permission to use, copy, modify, distribute, and sell this software and its | |
5 | * documentation for any purpose is hereby granted without fee, provided that | |
6 | * the above copyright notice appear in all copies and that both that | |
7 | * copyright notice and this permission notice appear in supporting | |
8 | * documentation, and that the name of Keith Packard not be used in | |
9 | * advertising or publicity pertaining to distribution of the software without | |
10 | * specific, written prior permission. Keith Packard makes no | |
11 | * representations about the suitability of this software for any purpose. It | |
12 | * is provided "as is" without express or implied warranty. | |
13 | * | |
14 | * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, | |
15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO | |
16 | * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR | |
17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, | |
18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER | |
19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR | |
20 | * PERFORMANCE OF THIS SOFTWARE. | |
21 | */ | |
22 | ||
23 | #ifdef HAVE_CONFIG_H | |
24 | #include <kdrive-config.h> | |
25 | #endif | |
26 | #include <errno.h> | |
27 | #include <linux/input.h> | |
28 | #include <X11/X.h> | |
29 | #include <X11/Xproto.h> | |
30 | #include <X11/Xpoll.h> | |
31 | #include "inputstr.h" | |
32 | #include "scrnintstr.h" | |
33 | #include "kdrive.h" | |
34 | ||
35 | #define NUM_EVENTS 128 | |
36 | #define ABS_UNSET -65535 | |
37 | ||
38 | #define BITS_PER_LONG (sizeof(long) * 8) | |
39 | #define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1) | |
40 | #define ISBITSET(x,y) ((x)[LONG(y)] & BIT(y)) | |
41 | #define OFF(x) ((x)%BITS_PER_LONG) | |
42 | #define LONG(x) ((x)/BITS_PER_LONG) | |
43 | #define BIT(x) (1 << OFF(x)) | |
44 | ||
45 | typedef struct _kevdev { | |
46 | /* current device state */ | |
47 | int rel[REL_MAX + 1]; | |
48 | int abs[ABS_MAX + 1]; | |
49 | int prevabs[ABS_MAX + 1]; | |
50 | long key[NBITS(KEY_MAX + 1)]; | |
51 | ||
52 | /* supported device info */ | |
53 | long relbits[NBITS(REL_MAX + 1)]; | |
54 | long absbits[NBITS(ABS_MAX + 1)]; | |
55 | long keybits[NBITS(KEY_MAX + 1)]; | |
56 | struct input_absinfo absinfo[ABS_MAX + 1]; | |
57 | int max_rel; | |
58 | int max_abs; | |
59 | ||
60 | int fd; | |
61 | } Kevdev; | |
62 | ||
63 | static void | |
64 | EvdevPtrBtn(KdPointerInfo * pi, struct input_event *ev) | |
65 | { | |
66 | int flags = KD_MOUSE_DELTA | pi->buttonState; | |
67 | ||
68 | if (ev->code >= BTN_MOUSE && ev->code < BTN_JOYSTICK) { | |
69 | switch (ev->code) { | |
70 | case BTN_LEFT: | |
71 | if (ev->value == 1) | |
72 | flags |= KD_BUTTON_1; | |
73 | else | |
74 | flags &= ~KD_BUTTON_1; | |
75 | break; | |
76 | case BTN_MIDDLE: | |
77 | if (ev->value == 1) | |
78 | flags |= KD_BUTTON_2; | |
79 | else | |
80 | flags &= ~KD_BUTTON_2; | |
81 | break; | |
82 | case BTN_RIGHT: | |
83 | if (ev->value == 1) | |
84 | flags |= KD_BUTTON_3; | |
85 | else | |
86 | flags &= ~KD_BUTTON_3; | |
87 | break; | |
88 | default: | |
89 | /* Unknow button */ | |
90 | break; | |
91 | } | |
92 | ||
93 | KdEnqueuePointerEvent(pi, flags, 0, 0, 0); | |
94 | } | |
95 | } | |
96 | ||
97 | static void | |
98 | EvdevPtrMotion(KdPointerInfo * pi, struct input_event *ev) | |
99 | { | |
100 | Kevdev *ke = pi->driverPrivate; | |
101 | int i; | |
102 | int flags = KD_MOUSE_DELTA | pi->buttonState; | |
103 | ||
104 | for (i = 0; i <= ke->max_rel; i++) | |
105 | if (ke->rel[i]) { | |
106 | int a; | |
107 | ||
108 | for (a = 0; a <= ke->max_rel; a++) { | |
109 | if (ISBITSET(ke->relbits, a)) { | |
110 | if (a == 0) | |
111 | KdEnqueuePointerEvent(pi, flags, ke->rel[a], 0, 0); | |
112 | else if (a == 1) | |
113 | KdEnqueuePointerEvent(pi, flags, 0, ke->rel[a], 0); | |
114 | } | |
115 | ke->rel[a] = 0; | |
116 | } | |
117 | break; | |
118 | } | |
119 | for (i = 0; i < ke->max_abs; i++) | |
120 | if (ke->abs[i] != ke->prevabs[i]) { | |
121 | int a; | |
122 | ||
123 | ErrorF("abs"); | |
124 | for (a = 0; a <= ke->max_abs; a++) { | |
125 | if (ISBITSET(ke->absbits, a)) | |
126 | ErrorF(" %d=%d", a, ke->abs[a]); | |
127 | ke->prevabs[a] = ke->abs[a]; | |
128 | } | |
129 | ErrorF("\n"); | |
130 | break; | |
131 | } | |
132 | ||
133 | if (ev->code == REL_WHEEL) { | |
134 | for (i = 0; i < abs(ev->value); i++) { | |
135 | if (ev->value > 0) | |
136 | flags |= KD_BUTTON_4; | |
137 | else | |
138 | flags |= KD_BUTTON_5; | |
139 | ||
140 | KdEnqueuePointerEvent(pi, flags, 0, 0, 0); | |
141 | ||
142 | if (ev->value > 0) | |
143 | flags &= ~KD_BUTTON_4; | |
144 | else | |
145 | flags &= ~KD_BUTTON_5; | |
146 | ||
147 | KdEnqueuePointerEvent(pi, flags, 0, 0, 0); | |
148 | } | |
149 | } | |
150 | ||
151 | } | |
152 | ||
153 | static void | |
154 | EvdevPtrRead(int evdevPort, void *closure) | |
155 | { | |
156 | KdPointerInfo *pi = closure; | |
157 | Kevdev *ke = pi->driverPrivate; | |
158 | int i; | |
159 | struct input_event events[NUM_EVENTS]; | |
160 | int n; | |
161 | ||
162 | n = read(evdevPort, &events, NUM_EVENTS * sizeof(struct input_event)); | |
163 | if (n <= 0) { | |
164 | if (errno == ENODEV) | |
165 | DeleteInputDeviceRequest(pi->dixdev); | |
166 | return; | |
167 | } | |
168 | ||
169 | n /= sizeof(struct input_event); | |
170 | for (i = 0; i < n; i++) { | |
171 | switch (events[i].type) { | |
172 | case EV_SYN: | |
173 | break; | |
174 | case EV_KEY: | |
175 | EvdevPtrBtn(pi, &events[i]); | |
176 | break; | |
177 | case EV_REL: | |
178 | ke->rel[events[i].code] += events[i].value; | |
179 | EvdevPtrMotion(pi, &events[i]); | |
180 | break; | |
181 | case EV_ABS: | |
182 | ke->abs[events[i].code] = events[i].value; | |
183 | EvdevPtrMotion(pi, &events[i]); | |
184 | break; | |
185 | } | |
186 | } | |
187 | } | |
188 | ||
189 | const char *kdefaultEvdev[] = { | |
190 | "/dev/input/event0", | |
191 | "/dev/input/event1", | |
192 | "/dev/input/event2", | |
193 | "/dev/input/event3", | |
194 | }; | |
195 | ||
196 | #define NUM_DEFAULT_EVDEV (sizeof (kdefaultEvdev) / sizeof (kdefaultEvdev[0])) | |
197 | ||
198 | static Status | |
199 | EvdevPtrInit(KdPointerInfo * pi) | |
200 | { | |
201 | int i; | |
202 | int fd; | |
203 | ||
204 | if (!pi->path) { | |
205 | for (i = 0; i < NUM_DEFAULT_EVDEV; i++) { | |
206 | fd = open(kdefaultEvdev[i], 2); | |
207 | if (fd >= 0) { | |
208 | pi->path = strdup(kdefaultEvdev[i]); | |
209 | break; | |
210 | } | |
211 | } | |
212 | } | |
213 | else { | |
214 | fd = open(pi->path, O_RDWR); | |
215 | if (fd < 0) { | |
216 | ErrorF("Failed to open evdev device %s\n", pi->path); | |
217 | return BadMatch; | |
218 | } | |
219 | } | |
220 | ||
221 | close(fd); | |
222 | ||
223 | pi->name = strdup("Evdev mouse"); | |
224 | ||
225 | return Success; | |
226 | } | |
227 | ||
228 | static Status | |
229 | EvdevPtrEnable(KdPointerInfo * pi) | |
230 | { | |
231 | int fd; | |
232 | unsigned long ev[NBITS(EV_MAX)]; | |
233 | Kevdev *ke; | |
234 | ||
235 | if (!pi || !pi->path) | |
236 | return BadImplementation; | |
237 | ||
238 | fd = open(pi->path, 2); | |
239 | if (fd < 0) | |
240 | return BadMatch; | |
241 | ||
242 | if (ioctl(fd, EVIOCGRAB, 1) < 0) | |
243 | perror("Grabbing evdev mouse device failed"); | |
244 | ||
245 | if (ioctl(fd, EVIOCGBIT(0 /*EV*/, sizeof(ev)), ev) < 0) { | |
246 | perror("EVIOCGBIT 0"); | |
247 | close(fd); | |
248 | return BadMatch; | |
249 | } | |
250 | ke = calloc(1, sizeof(Kevdev)); | |
251 | if (!ke) { | |
252 | close(fd); | |
253 | return BadAlloc; | |
254 | } | |
255 | if (ISBITSET(ev, EV_KEY)) { | |
256 | if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(ke->keybits)), ke->keybits) < 0) { | |
257 | perror("EVIOCGBIT EV_KEY"); | |
258 | free(ke); | |
259 | close(fd); | |
260 | return BadMatch; | |
261 | } | |
262 | } | |
263 | if (ISBITSET(ev, EV_REL)) { | |
264 | if (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(ke->relbits)), ke->relbits) < 0) { | |
265 | perror("EVIOCGBIT EV_REL"); | |
266 | free(ke); | |
267 | close(fd); | |
268 | return BadMatch; | |
269 | } | |
270 | for (ke->max_rel = REL_MAX; ke->max_rel >= 0; ke->max_rel--) | |
271 | if (ISBITSET(ke->relbits, ke->max_rel)) | |
272 | break; | |
273 | } | |
274 | if (ISBITSET(ev, EV_ABS)) { | |
275 | int i; | |
276 | ||
277 | if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(ke->absbits)), ke->absbits) < 0) { | |
278 | perror("EVIOCGBIT EV_ABS"); | |
279 | free(ke); | |
280 | close(fd); | |
281 | return BadMatch; | |
282 | } | |
283 | for (ke->max_abs = ABS_MAX; ke->max_abs >= 0; ke->max_abs--) | |
284 | if (ISBITSET(ke->absbits, ke->max_abs)) | |
285 | break; | |
286 | for (i = 0; i <= ke->max_abs; i++) { | |
287 | if (ISBITSET(ke->absbits, i)) | |
288 | if (ioctl(fd, EVIOCGABS(i), &ke->absinfo[i]) < 0) { | |
289 | perror("EVIOCGABS"); | |
290 | break; | |
291 | } | |
292 | ke->prevabs[i] = ABS_UNSET; | |
293 | } | |
294 | if (i <= ke->max_abs) { | |
295 | free(ke); | |
296 | close(fd); | |
297 | return BadValue; | |
298 | } | |
299 | } | |
300 | if (!KdRegisterFd(fd, EvdevPtrRead, pi)) { | |
301 | free(ke); | |
302 | close(fd); | |
303 | return BadAlloc; | |
304 | } | |
305 | pi->driverPrivate = ke; | |
306 | ke->fd = fd; | |
307 | ||
308 | return Success; | |
309 | } | |
310 | ||
311 | static void | |
312 | EvdevPtrDisable(KdPointerInfo * pi) | |
313 | { | |
314 | Kevdev *ke; | |
315 | ||
316 | ke = pi->driverPrivate; | |
317 | ||
318 | if (!pi || !pi->driverPrivate) | |
319 | return; | |
320 | ||
321 | KdUnregisterFd(pi, ke->fd, TRUE); | |
322 | ||
323 | if (ioctl(ke->fd, EVIOCGRAB, 0) < 0) | |
324 | perror("Ungrabbing evdev mouse device failed"); | |
325 | ||
326 | free(ke); | |
327 | pi->driverPrivate = 0; | |
328 | } | |
329 | ||
330 | static void | |
331 | EvdevPtrFini(KdPointerInfo * pi) | |
332 | { | |
333 | } | |
334 | ||
335 | /* | |
336 | * Evdev keyboard functions | |
337 | */ | |
338 | ||
339 | static void | |
340 | readMapping(KdKeyboardInfo * ki) | |
341 | { | |
342 | if (!ki) | |
343 | return; | |
344 | ||
345 | ki->minScanCode = 0; | |
346 | ki->maxScanCode = 247; | |
347 | } | |
348 | ||
349 | static void | |
350 | EvdevKbdRead(int evdevPort, void *closure) | |
351 | { | |
352 | KdKeyboardInfo *ki = closure; | |
353 | struct input_event events[NUM_EVENTS]; | |
354 | int i, n; | |
355 | ||
356 | n = read(evdevPort, &events, NUM_EVENTS * sizeof(struct input_event)); | |
357 | if (n <= 0) { | |
358 | if (errno == ENODEV) | |
359 | DeleteInputDeviceRequest(ki->dixdev); | |
360 | return; | |
361 | } | |
362 | ||
363 | n /= sizeof(struct input_event); | |
364 | for (i = 0; i < n; i++) { | |
365 | if (events[i].type == EV_KEY) | |
366 | KdEnqueueKeyboardEvent(ki, events[i].code, !events[i].value); | |
367 | /* FIXME: must implement other types of events | |
368 | else | |
369 | ErrorF("Event type (%d) not delivered\n", events[i].type); | |
370 | */ | |
371 | } | |
372 | } | |
373 | ||
374 | static Status | |
375 | EvdevKbdInit(KdKeyboardInfo * ki) | |
376 | { | |
377 | int fd; | |
378 | ||
379 | if (!ki->path) { | |
380 | ErrorF("Couldn't find evdev device path\n"); | |
381 | return BadValue; | |
382 | } | |
383 | else { | |
384 | fd = open(ki->path, O_RDWR); | |
385 | if (fd < 0) { | |
386 | ErrorF("Failed to open evdev device %s\n", ki->path); | |
387 | return BadMatch; | |
388 | } | |
389 | } | |
390 | ||
391 | close(fd); | |
392 | ||
393 | ki->name = strdup("Evdev keyboard"); | |
394 | ||
395 | readMapping(ki); | |
396 | ||
397 | return Success; | |
398 | } | |
399 | ||
400 | static Status | |
401 | EvdevKbdEnable(KdKeyboardInfo * ki) | |
402 | { | |
403 | unsigned long ev[NBITS(EV_MAX)]; | |
404 | Kevdev *ke; | |
405 | int fd; | |
406 | ||
407 | if (!ki || !ki->path) | |
408 | return BadImplementation; | |
409 | ||
410 | fd = open(ki->path, O_RDWR); | |
411 | if (fd < 0) | |
412 | return BadMatch; | |
413 | ||
414 | if (ioctl(fd, EVIOCGRAB, 1) < 0) | |
415 | perror("Grabbing evdev keyboard device failed"); | |
416 | ||
417 | if (ioctl(fd, EVIOCGBIT(0 /*EV*/, sizeof(ev)), ev) < 0) { | |
418 | perror("EVIOCGBIT 0"); | |
419 | close(fd); | |
420 | return BadMatch; | |
421 | } | |
422 | ||
423 | ke = calloc(1, sizeof(Kevdev)); | |
424 | if (!ke) { | |
425 | close(fd); | |
426 | return BadAlloc; | |
427 | } | |
428 | ||
429 | if (!KdRegisterFd(fd, EvdevKbdRead, ki)) { | |
430 | free(ke); | |
431 | close(fd); | |
432 | return BadAlloc; | |
433 | } | |
434 | ki->driverPrivate = ke; | |
435 | ke->fd = fd; | |
436 | ||
437 | return Success; | |
438 | } | |
439 | ||
440 | static void | |
441 | EvdevKbdLeds(KdKeyboardInfo * ki, int leds) | |
442 | { | |
443 | /* struct input_event event; | |
444 | Kevdev *ke; | |
445 | ||
446 | ki->driverPrivate = ke; | |
447 | ||
448 | memset(&event, 0, sizeof(event)); | |
449 | ||
450 | event.type = EV_LED; | |
451 | event.code = LED_CAPSL; | |
452 | event.value = leds & (1 << 0) ? 1 : 0; | |
453 | write(ke->fd, (char *) &event, sizeof(event)); | |
454 | ||
455 | event.type = EV_LED; | |
456 | event.code = LED_NUML; | |
457 | event.value = leds & (1 << 1) ? 1 : 0; | |
458 | write(ke->fd, (char *) &event, sizeof(event)); | |
459 | ||
460 | event.type = EV_LED; | |
461 | event.code = LED_SCROLLL; | |
462 | event.value = leds & (1 << 2) ? 1 : 0; | |
463 | write(ke->fd, (char *) &event, sizeof(event)); | |
464 | ||
465 | event.type = EV_LED; | |
466 | event.code = LED_COMPOSE; | |
467 | event.value = leds & (1 << 3) ? 1 : 0; | |
468 | write(ke->fd, (char *) &event, sizeof(event)); | |
469 | */ | |
470 | } | |
471 | ||
472 | static void | |
473 | EvdevKbdBell(KdKeyboardInfo * ki, int volume, int frequency, int duration) | |
474 | { | |
475 | } | |
476 | ||
477 | static void | |
478 | EvdevKbdDisable(KdKeyboardInfo * ki) | |
479 | { | |
480 | Kevdev *ke; | |
481 | ||
482 | ke = ki->driverPrivate; | |
483 | ||
484 | if (!ki || !ki->driverPrivate) | |
485 | return; | |
486 | ||
487 | KdUnregisterFd(ki, ke->fd, TRUE); | |
488 | ||
489 | if (ioctl(ke->fd, EVIOCGRAB, 0) < 0) | |
490 | perror("Ungrabbing evdev keyboard device failed"); | |
491 | ||
492 | free(ke); | |
493 | ki->driverPrivate = 0; | |
494 | } | |
495 | ||
496 | static void | |
497 | EvdevKbdFini(KdKeyboardInfo * ki) | |
498 | { | |
499 | } | |
500 | ||
501 | KdPointerDriver LinuxEvdevMouseDriver = { | |
502 | "evdev", | |
503 | EvdevPtrInit, | |
504 | EvdevPtrEnable, | |
505 | EvdevPtrDisable, | |
506 | EvdevPtrFini, | |
507 | NULL, | |
508 | }; | |
509 | ||
510 | KdKeyboardDriver LinuxEvdevKeyboardDriver = { | |
511 | "evdev", | |
512 | EvdevKbdInit, | |
513 | EvdevKbdEnable, | |
514 | EvdevKbdLeds, | |
515 | EvdevKbdBell, | |
516 | EvdevKbdDisable, | |
517 | EvdevKbdFini, | |
518 | NULL, | |
519 | }; |