1 // SPDX-License-Identifier: MIT
2 /*
3 * Copyright © 2013 Red Hat, Inc.
4 */
5
6 #include "config.h"
7 #include <fcntl.h>
8 #include <poll.h>
9 #include <unistd.h>
10 #include <string.h>
11 #include <stdio.h>
12 #include <errno.h>
13 #include <linux/uinput.h>
14 #include <dirent.h>
15
16 #include <libevdev/libevdev.h>
17 #include <libevdev/libevdev-int.h>
18 #include <libevdev/libevdev-util.h>
19 #include <libevdev/libevdev-uinput.h>
20
21 #include "test-common-uinput.h"
22
23 #define SYS_INPUT_DIR "/sys/class/input"
24 #define DEV_INPUT_DIR "/dev/input/"
25
26 struct uinput_device
27 {
28 struct libevdev *d; /* lazy, it has all the accessors */
29 struct libevdev_uinput *uidev;
30 int dev_fd; /* open fd to the devnode */
31 int uinput_fd;
32 };
33
34 struct uinput_device*
uinput_device_new(const char * name)35 uinput_device_new(const char *name)
36 {
37 struct uinput_device *dev;
38
39 dev = calloc(1, sizeof(*dev));
40 if (!dev)
41 return NULL;
42
43 dev->d = libevdev_new();
44 dev->dev_fd = -1;
45 dev->uinput_fd = -1;
46
47 if (name)
48 libevdev_set_name(dev->d, name);
49
50 return dev;
51 }
52
53 int
uinput_device_new_with_events_v(struct uinput_device ** d,const char * name,const struct input_id * id,va_list args)54 uinput_device_new_with_events_v(struct uinput_device **d, const char *name, const struct input_id *id, va_list args)
55 {
56 int rc;
57 struct uinput_device *dev;
58
59 dev = uinput_device_new(name);
60 if (!dev)
61 return -ENOMEM;
62 if (id != DEFAULT_IDS)
63 uinput_device_set_ids(dev, id);
64
65 rc = uinput_device_set_event_bits_v(dev, args);
66
67 if (rc == 0)
68 rc = uinput_device_create(dev);
69
70 if (rc != 0) {
71 uinput_device_free(dev);
72 dev = NULL;
73 } else
74 *d = dev;
75
76 return rc;
77 }
78
79 int
uinput_device_new_with_events(struct uinput_device ** d,const char * name,const struct input_id * id,...)80 uinput_device_new_with_events(struct uinput_device **d, const char *name, const struct input_id *id, ...)
81 {
82 int rc;
83 va_list args;
84
85 va_start(args, id);
86 rc = uinput_device_new_with_events_v(d, name, id, args);
87 va_end(args);
88
89 return rc;
90 }
91
92 void
uinput_device_free(struct uinput_device * dev)93 uinput_device_free(struct uinput_device *dev)
94 {
95 if (!dev)
96 return;
97
98 if (dev->uinput_fd != -1) {
99 (void)ioctl(dev->uinput_fd, UI_DEV_DESTROY, NULL);
100 close(dev->uinput_fd);
101 }
102 if (dev->dev_fd != -1)
103 close(dev->dev_fd);
104 libevdev_free(dev->d);
105 libevdev_uinput_destroy(dev->uidev);
106 free(dev);
107 }
108
109 int
uinput_device_get_fd(const struct uinput_device * dev)110 uinput_device_get_fd(const struct uinput_device *dev)
111 {
112 return dev->dev_fd;
113 }
114
115 const char*
uinput_device_get_devnode(const struct uinput_device * dev)116 uinput_device_get_devnode(const struct uinput_device *dev)
117 {
118 return libevdev_uinput_get_devnode(dev->uidev);
119 }
120
121 int
uinput_device_create(struct uinput_device * d)122 uinput_device_create(struct uinput_device* d)
123 {
124 int rc;
125 int fd;
126 const char *devnode;
127
128 fd = open("/dev/uinput", O_RDWR);
129 if (fd < 0)
130 goto error;
131
132 d->uinput_fd = fd;
133
134 rc = libevdev_uinput_create_from_device(d->d, fd, &d->uidev);
135 if (rc != 0)
136 goto error;
137
138 devnode = libevdev_uinput_get_devnode(d->uidev);
139 if (devnode == NULL)
140 goto error;
141
142 d->dev_fd = open(devnode, O_RDWR);
143 if (d->dev_fd == -1)
144 goto error;
145
146 /* write abs resolution now */
147 if (libevdev_has_event_type(d->d, EV_ABS)) {
148 int code;
149 for (code = 0; code < ABS_CNT; code++) {
150 const struct input_absinfo *abs;
151
152 /* can't change slots */
153 if (code == ABS_MT_SLOT)
154 continue;
155
156 abs = libevdev_get_abs_info(d->d, code);
157 if (!abs)
158 continue;
159
160 rc = ioctl(d->dev_fd, EVIOCSABS(code), abs);
161 if (rc < 0) {
162 printf("error %s for code %d\n", strerror(-rc), code);
163 goto error;
164 }
165 }
166 }
167
168 return 0;
169
170 error:
171 if (d->dev_fd != -1)
172 close(d->dev_fd);
173 if (d->uinput_fd != -1)
174 close(d->uinput_fd);
175 return -errno;
176
177 }
178
uinput_device_set_name(struct uinput_device * dev,const char * name)179 int uinput_device_set_name(struct uinput_device *dev, const char *name)
180 {
181 libevdev_set_name(dev->d, name);
182 return 0;
183 }
184
uinput_device_set_ids(struct uinput_device * dev,const struct input_id * ids)185 int uinput_device_set_ids(struct uinput_device *dev, const struct input_id *ids)
186 {
187 libevdev_set_id_product(dev->d, ids->product);
188 libevdev_set_id_vendor(dev->d, ids->vendor);
189 libevdev_set_id_bustype(dev->d, ids->bustype);
190 libevdev_set_id_version(dev->d, ids->version);
191 return 0;
192 }
193
194 int
uinput_device_set_bit(struct uinput_device * dev,unsigned int bit)195 uinput_device_set_bit(struct uinput_device* dev, unsigned int bit)
196 {
197 return libevdev_enable_event_type(dev->d, bit);
198 }
199
200 int
uinput_device_set_prop(struct uinput_device * dev,unsigned int prop)201 uinput_device_set_prop(struct uinput_device *dev, unsigned int prop)
202 {
203 return libevdev_enable_property(dev->d, prop);
204 }
205
206 int
uinput_device_set_event_bit(struct uinput_device * dev,unsigned int type,unsigned int code)207 uinput_device_set_event_bit(struct uinput_device* dev, unsigned int type, unsigned int code)
208 {
209 return libevdev_enable_event_code(dev->d, type, code, NULL);
210 }
211
212 int
uinput_device_set_event_bits_v(struct uinput_device * dev,va_list args)213 uinput_device_set_event_bits_v(struct uinput_device *dev, va_list args)
214 {
215 int type, code;
216 int rc = 0;
217
218 do {
219 type = va_arg(args, int);
220 if (type == -1)
221 break;
222 code = va_arg(args, int);
223 if (code == -1)
224 break;
225 rc = libevdev_enable_event_code(dev->d, type, code, NULL);
226 } while (rc == 0);
227
228 return rc;
229 }
230
231 int
uinput_device_set_event_bits(struct uinput_device * dev,...)232 uinput_device_set_event_bits(struct uinput_device *dev, ...)
233 {
234 int rc;
235 va_list args;
236 va_start(args, dev);
237 rc = uinput_device_set_event_bits_v(dev, args);
238 va_end(args);
239
240 return rc;
241 }
242
243 int
uinput_device_set_abs_bit(struct uinput_device * dev,unsigned int code,const struct input_absinfo * absinfo)244 uinput_device_set_abs_bit(struct uinput_device* dev, unsigned int code, const struct input_absinfo *absinfo)
245 {
246 return libevdev_enable_event_code(dev->d, EV_ABS, code, absinfo);
247 }
248
249 int
uinput_device_event(const struct uinput_device * dev,unsigned int type,unsigned int code,int value)250 uinput_device_event(const struct uinput_device *dev, unsigned int type, unsigned int code, int value)
251 {
252 return libevdev_uinput_write_event(dev->uidev, type, code, value);
253 }
254
uinput_device_event_multiple_v(const struct uinput_device * dev,va_list args)255 int uinput_device_event_multiple_v(const struct uinput_device* dev, va_list args)
256 {
257 int type, code, value;
258 int rc = 0;
259
260 do {
261 type = va_arg(args, int);
262 if (type == -1)
263 break;
264 code = va_arg(args, int);
265 if (code == -1)
266 break;
267 value = va_arg(args, int);
268 rc = uinput_device_event(dev, type, code, value);
269 } while (rc == 0);
270
271 return rc;
272 }
273
uinput_device_event_multiple(const struct uinput_device * dev,...)274 int uinput_device_event_multiple(const struct uinput_device* dev, ...)
275 {
276 int rc;
277 va_list args;
278 va_start(args, dev);
279 rc = uinput_device_event_multiple_v(dev, args);
280 va_end(args);
281 return rc;
282 }
283