blob: 45914c95389efb0553cce4cc981a3c5770da5c49 [file] [log] [blame]
Dennis Kempina9963ba2012-06-08 10:32:23 -07001/*
2 * Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
Dennis Kempin320aef12012-06-11 15:26:52 -07006#include <libevdev/libevdev.h>
Dennis Kempina9963ba2012-06-08 10:32:23 -07007
8#include <errno.h>
9#include <fcntl.h>
10#include <linux/input.h>
11#include <stdio.h>
12#include <time.h>
13#include <unistd.h>
14
Dennis Kempin320aef12012-06-11 15:26:52 -070015#include <libevdev/libevdev_event.h>
16#include <libevdev/libevdev_log.h>
17#include <libevdev/libevdev_util.h>
Dennis Kempina9963ba2012-06-08 10:32:23 -070018
19/* Number of events to attempt to read from kernel on each SIGIO */
20#define NUM_EVENTS 16
21
22#ifndef EVIOCGMTSLOTS
23#define EVIOCGMTSLOTS(len) _IOC(_IOC_READ, 'E', 0x0a, len)
24#endif
25
26/* Set clockid to be used for timestamps */
27#ifndef EVIOCSCLOCKID
28#define EVIOCSCLOCKID _IOW('E', 0xa0, int)
29#endif
30
31static void Absinfo_Print(EvdevPtr device, struct input_absinfo*);
32static const char* Event_Property_To_String(int type);
33
34int EvdevOpen(EvdevPtr evdev, const char* device) {
35 evdev->fd = open(device, O_RDWR | O_NONBLOCK, 0);
36 return evdev->fd;
37}
38
39int EvdevClose(EvdevPtr evdev) {
40 close(evdev->fd);
41 evdev->fd = -1;
42 return evdev->fd;
43}
44
45int EvdevRead(EvdevPtr evdev) {
46 struct input_event ev[NUM_EVENTS];
47 int i;
48 int len;
49 bool sync_evdev_state = false;
50
51 do {
52 len = read(evdev->fd, &ev, sizeof(ev));
53 if (len <= 0)
54 return errno;
55
56 /* kernel always delivers complete events, so len must be sizeof *ev */
57 if (len % sizeof(*ev))
58 return errno;
59
60 /* Process events ... */
61 for (i = 0; i < len / sizeof(ev[0]); i++) {
62 if (sync_evdev_state)
63 break;
64 if (timercmp(&ev[i].time, &evdev->before_sync_time, <)) {
65 /* Ignore events before last sync time */
66 continue;
67 } else if (timercmp(&ev[i].time, &evdev->after_sync_time, >)) {
68 /* Event_Process returns TRUE if SYN_DROPPED detected */
69 sync_evdev_state = Event_Process(evdev, &ev[i]);
70 } else {
71 /* If the event occurred during sync, then sync again */
72 sync_evdev_state = true;
73 }
74 }
75
76 } while (len == sizeof(ev));
77 /* Keep reading if kernel supplied NUM_EVENTS events. */
78
79 if (sync_evdev_state)
80 Event_Sync_State(evdev);
81
82 return Success;
83}
84
85int EvdevProbe(EvdevPtr device) {
86 int len, i;
87 int fd;
88 EvdevInfoPtr info;
89
90 fd = device->fd;
91 info = &device->info;
92 if (ioctl(fd, EVIOCGID, &info->id) < 0) {
93 LOG_ERROR(device, "ioctl EVIOCGID failed: %s\n", strerror(errno));
94 return !Success;
95 }
96
97 if (ioctl(fd, EVIOCGNAME(sizeof(info->name) - 1),
98 info->name) < 0) {
99 LOG_ERROR(device, "ioctl EVIOCGNAME failed: %s\n", strerror(errno));
100 return !Success;
101 }
102
103 len = ioctl(fd, EVIOCGPROP(sizeof(info->prop_bitmask)),
104 info->prop_bitmask);
105 if (len < 0) {
106 LOG_ERROR(device, "ioctl EVIOCGPROP failed: %s\n", strerror(errno));
107 return !Success;
108 }
109 for (i = 0; i < len*8; i++) {
110 if (TestBit(i, info->prop_bitmask))
111 LOG_DEBUG(device, "Has Property: %d (%s)\n", i,
112 Event_Property_To_String(i));
113 }
114
115 len = ioctl(fd, EVIOCGBIT(0, sizeof(info->bitmask)),
116 info->bitmask);
117 if (len < 0) {
118 LOG_ERROR(device, "ioctl EVIOCGBIT failed: %s\n",
119 strerror(errno));
120 return !Success;
121 }
122 for (i = 0; i < len*8; i++) {
123 if (TestBit(i, info->bitmask))
124 LOG_DEBUG(device, "Has Event Type %d = %s\n", i,
125 Event_Type_To_String(i));
126 }
127
128 len = ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(info->key_bitmask)),
129 info->key_bitmask);
130 if (len < 0) {
131 LOG_ERROR(device, "ioctl EVIOCGBIT(EV_KEY) failed: %s\n",
132 strerror(errno));
133 return !Success;
134 }
135 for (i = 0; i < len*8; i++) {
136 if (TestBit(i, info->key_bitmask))
137 LOG_DEBUG(device, "Has KEY[%d] = %s\n", i,
138 Event_To_String(EV_KEY, i));
139 }
140
141 len = ioctl(fd, EVIOCGBIT(EV_LED, sizeof(info->led_bitmask)),
142 info->led_bitmask);
143 if (len < 0) {
144 LOG_ERROR(device, "ioctl EVIOCGBIT(EV_LED) failed: %s\n",
145 strerror(errno));
146 return !Success;
147 }
148 for (i = 0; i < len*8; i++) {
149 if (TestBit(i, info->led_bitmask))
150 LOG_DEBUG(device, "Has LED[%d] = %s\n", i,
151 Event_To_String(EV_LED, i));
152 }
153
154 len = ioctl(fd, EVIOCGBIT(EV_REL, sizeof(info->rel_bitmask)),
155 info->rel_bitmask);
156 if (len < 0) {
157 LOG_ERROR(device, "ioctl EVIOCGBIT(EV_REL) failed: %s\n",
158 strerror(errno));
159 return !Success;
160 }
161 for (i = 0; i < len*8; i++) {
162 if (TestBit(i, info->rel_bitmask))
163 LOG_DEBUG(device, "Has REL[%d] = %s\n", i,
164 Event_To_String(EV_REL, i));
165 }
166
167 /*
168 * TODO(djkurtz): Solve the race condition between MT slot initialization
169 * from absinfo, and incoming/lost input events.
170 * Specifically, if kernel driver sends MT_SLOT event between absinfo
171 * probe and when we start listening for input events.
172 */
173
174 len = ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(info->abs_bitmask)),
175 info->abs_bitmask);
176 if (len < 0) {
177 LOG_ERROR(device, "ioctl EVIOCGBIT(EV_ABS) failed: %s\n",
178 strerror(errno));
179 return !Success;
180 }
181
182 for (i = ABS_X; i <= ABS_MAX; i++) {
183 if (TestBit(i, info->abs_bitmask)) {
184 struct input_absinfo* absinfo = &info->absinfo[i];
185 LOG_DEBUG(device, "Has ABS[%d] = %s\n", i,
186 Event_To_String(EV_ABS, i));
187 len = ioctl(fd, EVIOCGABS(i), absinfo);
188 if (len < 0) {
189 LOG_ERROR(device, "ioctl EVIOCGABS(%d) failed: %s\n", i,
190 strerror(errno));
191 return !Success;
192 }
193
194 Absinfo_Print(device, absinfo);
195 }
196 }
197 return Success;
198}
199
200int EvdevProbeAbsinfo(EvdevPtr device, size_t key) {
201 struct input_absinfo* absinfo;
202
203 absinfo = &device->info.absinfo[key];
204 if (ioctl(device->fd, EVIOCGABS(key), absinfo) < 0) {
205 LOG_ERROR(device, "ioctl EVIOCGABS(%d) failed: %s\n", key,
206 strerror(errno));
207 return !Success;
208 } else {
209 return Success;
210 }
211}
212
Chung-yih Wang8b2fa0a2012-07-23 16:49:10 +0800213/*
214 * Check if the device is a single-pressure one which reports ABS_PRESSURE only.
215 */
216int EvdevIsSinglePressureDevice(EvdevPtr device) {
217 EvdevInfoPtr info = &device->info;
218
219 return (!TestBit(ABS_MT_PRESSURE, info->bitmask) &&
220 TestBit(ABS_PRESSURE, info->bitmask));
221}
222
Dennis Kempina9963ba2012-06-08 10:32:23 -0700223int EvdevProbeMTSlot(EvdevPtr device, MTSlotInfoPtr req) {
Dennis Kempine9cc2642012-06-25 11:52:24 -0700224 if (ioctl(device->fd, EVIOCGMTSLOTS((sizeof(*req))), req) < 0) {
Dennis Kempina9963ba2012-06-08 10:32:23 -0700225 LOG_ERROR(device, "ioctl EVIOCGMTSLOTS(req.code=%d) failed: %s\n",
Dennis Kempine9cc2642012-06-25 11:52:24 -0700226 req->code, strerror(errno));
Dennis Kempina9963ba2012-06-08 10:32:23 -0700227 return !Success;
228 } else {
229 return Success;
230 }
231}
232
233int EvdevProbeKeyState(EvdevPtr device) {
234 int len = sizeof(device->key_state_bitmask);
235
236 memset(device->key_state_bitmask, 0, len);
237 if (ioctl(device->fd, EVIOCGKEY(len), device->key_state_bitmask) < 0) {
238 LOG_ERROR(device, "ioctl EVIOCGKEY failed: %s\n", strerror(errno));
239 return !Success;
240 } else {
241 return Success;
242 }
243}
244
245int EvdevEnableMonotonic(EvdevPtr device) {
246 unsigned int clk = CLOCK_MONOTONIC;
247 return (ioctl(device->fd, EVIOCSCLOCKID, &clk) == 0) ? Success : !Success;
248}
249
250
251static const char*
252Event_Property_To_String(int type) {
253 switch (type) {
254 case INPUT_PROP_POINTER: return "POINTER"; /* needs a pointer */
255 case INPUT_PROP_DIRECT: return "DIRECT"; /* direct input devices */
256 case INPUT_PROP_BUTTONPAD: return "BUTTONPAD"; /* has button under pad */
257 case INPUT_PROP_SEMI_MT: return "SEMI_MT"; /* touch rectangle only */
258 default: return "?";
259 }
260}
261
262static void
263Absinfo_Print(EvdevPtr device, struct input_absinfo* absinfo)
264{
265 LOG_DEBUG(device, " min = %d\n", absinfo->minimum);
266 LOG_DEBUG(device, " max = %d\n", absinfo->maximum);
267 if (absinfo->fuzz)
268 LOG_DEBUG(device, " fuzz = %d\n", absinfo->fuzz);
269 if (absinfo->resolution)
270 LOG_DEBUG(device, " res = %d\n", absinfo->resolution);
271}
272