• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2013-2015 Red Hat, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23 
24 #include "config.h"
25 
26 #include <string.h>
27 #include <sys/stat.h>
28 #include <libudev.h>
29 
30 #include "evdev.h"
31 
32 struct path_input {
33 	struct libinput base;
34 	struct udev *udev;
35 	struct list path_list;
36 };
37 
38 struct path_device {
39 	struct list link;
40 	struct udev_device *udev_device;
41 };
42 
43 struct path_seat {
44 	struct libinput_seat base;
45 };
46 
47 static const char default_seat[] = "seat0";
48 static const char default_seat_name[] = "default";
49 
50 static void
path_disable_device(struct evdev_device * device)51 path_disable_device(struct evdev_device *device)
52 {
53 	struct libinput_seat *seat = device->base.seat;
54 	struct evdev_device *dev;
55 
56 	list_for_each_safe(dev,
57 			   &seat->devices_list, base.link) {
58 		if (dev != device)
59 			continue;
60 
61 		evdev_device_remove(device);
62 		break;
63 	}
64 }
65 
66 static void
path_input_disable(struct libinput * libinput)67 path_input_disable(struct libinput *libinput)
68 {
69 	struct path_input *input = (struct path_input*)libinput;
70 	struct path_seat *seat;
71 	struct evdev_device *device;
72 
73 	list_for_each_safe(seat, &input->base.seat_list, base.link) {
74 		libinput_seat_ref(&seat->base);
75 		list_for_each_safe(device,
76 				   &seat->base.devices_list, base.link)
77 			path_disable_device(device);
78 		libinput_seat_unref(&seat->base);
79 	}
80 }
81 
82 static void
path_seat_destroy(struct libinput_seat * seat)83 path_seat_destroy(struct libinput_seat *seat)
84 {
85 	struct path_seat *pseat = (struct path_seat*)seat;
86 	free(pseat);
87 }
88 
89 static struct path_seat*
path_seat_create(struct path_input * input,const char * seat_name,const char * seat_logical_name)90 path_seat_create(struct path_input *input,
91 		 const char *seat_name,
92 		 const char *seat_logical_name)
93 {
94 	struct path_seat *seat;
95 
96 	seat = zalloc(sizeof(*seat));
97 
98 	libinput_seat_init(&seat->base, &input->base, seat_name,
99 			   seat_logical_name, path_seat_destroy);
100 
101 	return seat;
102 }
103 
104 static struct path_seat*
path_seat_get_named(struct path_input * input,const char * seat_name_physical,const char * seat_name_logical)105 path_seat_get_named(struct path_input *input,
106 		    const char *seat_name_physical,
107 		    const char *seat_name_logical)
108 {
109 	struct path_seat *seat;
110 
111 	list_for_each(seat, &input->base.seat_list, base.link) {
112 		if (streq(seat->base.physical_name, seat_name_physical) &&
113 		    streq(seat->base.logical_name, seat_name_logical))
114 			return seat;
115 	}
116 
117 	return NULL;
118 }
119 
120 static struct path_seat *
path_seat_get_for_device(struct path_input * input,struct udev_device * udev_device,const char * seat_logical_name_override)121 path_seat_get_for_device(struct path_input *input,
122 			 struct udev_device *udev_device,
123 			 const char *seat_logical_name_override)
124 {
125 	struct path_seat *seat = NULL;
126 	char *seat_name = NULL, *seat_logical_name = NULL;
127 	const char *seat_prop;
128 
129 	const char *devnode, *sysname;
130 
131 	devnode = udev_device_get_devnode(udev_device);
132 	sysname = udev_device_get_sysname(udev_device);
133 
134 	seat_prop = udev_device_get_property_value(udev_device, "ID_SEAT");
135 	seat_name = safe_strdup(seat_prop ? seat_prop : default_seat);
136 
137 	if (seat_logical_name_override) {
138 		seat_logical_name = safe_strdup(seat_logical_name_override);
139 	} else {
140 		seat_prop = udev_device_get_property_value(udev_device, "WL_SEAT");
141 		seat_logical_name = safe_strdup(seat_prop ? seat_prop : default_seat_name);
142 	}
143 
144 	if (!seat_logical_name) {
145 		log_error(&input->base,
146 			  "%s: failed to create seat name for device '%s'.\n",
147 			  sysname,
148 			  devnode);
149 		goto out;
150 	}
151 
152 	seat = path_seat_get_named(input, seat_name, seat_logical_name);
153 
154 	if (!seat)
155 		seat = path_seat_create(input, seat_name, seat_logical_name);
156 	if (!seat) {
157 		log_info(&input->base,
158 			 "%s: failed to create seat for device '%s'.\n",
159 			 sysname,
160 			 devnode);
161 		goto out;
162 	}
163 
164 	libinput_seat_ref(&seat->base);
165 out:
166 	free(seat_name);
167 	free(seat_logical_name);
168 
169 	return seat;
170 }
171 
172 static struct libinput_device *
path_device_enable(struct path_input * input,struct udev_device * udev_device,const char * seat_logical_name_override)173 path_device_enable(struct path_input *input,
174 		   struct udev_device *udev_device,
175 		   const char *seat_logical_name_override)
176 {
177 	struct path_seat *seat;
178 	struct evdev_device *device = NULL;
179 	const char *output_name;
180 	const char *devnode, *sysname;
181 
182 	devnode = udev_device_get_devnode(udev_device);
183 	sysname = udev_device_get_sysname(udev_device);
184 
185 	seat = path_seat_get_for_device(input, udev_device, seat_logical_name_override);
186 	if (!seat)
187 		goto out;
188 
189 	device = evdev_device_create(&seat->base, udev_device);
190 	libinput_seat_unref(&seat->base);
191 
192 	if (device == EVDEV_UNHANDLED_DEVICE) {
193 		device = NULL;
194 		log_info(&input->base,
195 			 "%-7s - not using input device '%s'.\n",
196 			 sysname,
197 			 devnode);
198 		goto out;
199 	} else if (device == NULL) {
200 		log_info(&input->base,
201 			 "%-7s - failed to create input device '%s'.\n",
202 			 sysname,
203 			 devnode);
204 		goto out;
205 	}
206 
207 	evdev_read_calibration_prop(device);
208 	output_name = udev_device_get_property_value(udev_device, "WL_OUTPUT");
209 	device->output_name = safe_strdup(output_name);
210 
211 out:
212 	return device ? &device->base : NULL;
213 }
214 
215 static int
path_input_enable(struct libinput * libinput)216 path_input_enable(struct libinput *libinput)
217 {
218 	struct path_input *input = (struct path_input*)libinput;
219 	struct path_device *dev;
220 
221 	list_for_each(dev, &input->path_list, link) {
222 		if (path_device_enable(input, dev->udev_device, NULL) == NULL) {
223 			path_input_disable(libinput);
224 			return -1;
225 		}
226 	}
227 
228 	return 0;
229 }
230 
231 static void
path_device_destroy(struct path_device * dev)232 path_device_destroy(struct path_device *dev)
233 {
234 	list_remove(&dev->link);
235 	udev_device_unref(dev->udev_device);
236 	free(dev);
237 }
238 
239 static void
path_input_destroy(struct libinput * input)240 path_input_destroy(struct libinput *input)
241 {
242 	struct path_input *path_input = (struct path_input*)input;
243 	struct path_device *dev;
244 
245 	udev_unref(path_input->udev);
246 
247 	list_for_each_safe(dev, &path_input->path_list, link)
248 		path_device_destroy(dev);
249 
250 }
251 
252 static struct libinput_device *
path_create_device(struct libinput * libinput,struct udev_device * udev_device,const char * seat_name)253 path_create_device(struct libinput *libinput,
254 		   struct udev_device *udev_device,
255 		   const char *seat_name)
256 {
257 	struct path_input *input = (struct path_input*)libinput;
258 	struct path_device *dev;
259 	struct libinput_device *device;
260 
261 	dev = zalloc(sizeof *dev);
262 	dev->udev_device = udev_device_ref(udev_device);
263 
264 	list_insert(&input->path_list, &dev->link);
265 
266 	device = path_device_enable(input, udev_device, seat_name);
267 
268 	if (!device)
269 		path_device_destroy(dev);
270 
271 	return device;
272 }
273 
274 static int
path_device_change_seat(struct libinput_device * device,const char * seat_name)275 path_device_change_seat(struct libinput_device *device,
276 			const char *seat_name)
277 {
278 	struct libinput *libinput = device->seat->libinput;
279 	struct evdev_device *evdev = evdev_device(device);
280 	struct udev_device *udev_device = NULL;
281 	int rc = -1;
282 
283 	udev_device = evdev->udev_device;
284 	udev_device_ref(udev_device);
285 	libinput_path_remove_device(device);
286 
287 	if (path_create_device(libinput, udev_device, seat_name) != NULL)
288 		rc = 0;
289 	udev_device_unref(udev_device);
290 	return rc;
291 }
292 
293 static const struct libinput_interface_backend interface_backend = {
294 	.resume = path_input_enable,
295 	.suspend = path_input_disable,
296 	.destroy = path_input_destroy,
297 	.device_change_seat = path_device_change_seat,
298 };
299 
300 LIBINPUT_EXPORT struct libinput *
libinput_path_create_context(const struct libinput_interface * interface,void * user_data)301 libinput_path_create_context(const struct libinput_interface *interface,
302 			     void *user_data)
303 {
304 	struct path_input *input;
305 	struct udev *udev;
306 
307 	if (!interface)
308 		return NULL;
309 
310 	udev = udev_new();
311 	if (!udev)
312 		return NULL;
313 
314 	input = zalloc(sizeof *input);
315 	if (libinput_init(&input->base, interface,
316 			  &interface_backend, user_data) != 0) {
317 		udev_unref(udev);
318 		free(input);
319 		return NULL;
320 	}
321 
322 	input->udev = udev;
323 	list_init(&input->path_list);
324 
325 	return &input->base;
326 }
327 
328 static inline struct udev_device *
udev_device_from_devnode(struct libinput * libinput,struct udev * udev,const char * devnode)329 udev_device_from_devnode(struct libinput *libinput,
330 			 struct udev *udev,
331 			 const char *devnode)
332 {
333 	struct udev_device *dev;
334 	struct stat st;
335 	size_t count = 0;
336 
337 	if (stat(devnode, &st) < 0)
338 		return NULL;
339 
340 	dev = udev_device_new_from_devnum(udev, 'c', st.st_rdev);
341 
342 	while (dev && !udev_device_get_is_initialized(dev)) {
343 		udev_device_unref(dev);
344 		count++;
345 		if (count > 200) {
346 			log_bug_libinput(libinput,
347 					"udev device never initialized (%s)\n",
348 					devnode);
349 			return NULL;
350 		}
351 		msleep(10);
352 		dev = udev_device_new_from_devnum(udev, 'c', st.st_rdev);
353 	}
354 
355 	return dev;
356 }
357 
358 LIBINPUT_EXPORT struct libinput_device *
libinput_path_add_device(struct libinput * libinput,const char * path)359 libinput_path_add_device(struct libinput *libinput,
360 			 const char *path)
361 {
362 	struct path_input *input = (struct path_input *)libinput;
363 	struct udev *udev = input->udev;
364 	struct udev_device *udev_device;
365 	struct libinput_device *device;
366 
367 	if (strlen(path) > PATH_MAX) {
368 		log_bug_client(libinput,
369 			       "Unexpected path, limited to %d characters.\n",
370 			       PATH_MAX);
371 		return NULL;
372 	}
373 
374 	if (libinput->interface_backend != &interface_backend) {
375 		log_bug_client(libinput, "Mismatching backends.\n");
376 		return NULL;
377 	}
378 
379 	udev_device = udev_device_from_devnode(libinput, udev, path);
380 	if (!udev_device) {
381 		log_bug_client(libinput, "Invalid path %s\n", path);
382 		return NULL;
383 	}
384 
385 	if (ignore_litest_test_suite_device(udev_device)) {
386 		udev_device_unref(udev_device);
387 		return NULL;
388 	}
389 
390 	/* We cannot do this during path_create_context because the log
391 	 * handler isn't set up there but we really want to log to the right
392 	 * place if the quirks run into parser errors. So we have to do it
393 	 * on the first call to add_device.
394 	 */
395 	libinput_init_quirks(libinput);
396 
397 	device = path_create_device(libinput, udev_device, NULL);
398 	udev_device_unref(udev_device);
399 	return device;
400 }
401 
402 LIBINPUT_EXPORT void
libinput_path_remove_device(struct libinput_device * device)403 libinput_path_remove_device(struct libinput_device *device)
404 {
405 	struct libinput *libinput = device->seat->libinput;
406 	struct path_input *input = (struct path_input*)libinput;
407 	struct libinput_seat *seat;
408 	struct evdev_device *evdev = evdev_device(device);
409 	struct path_device *dev;
410 
411 	if (libinput->interface_backend != &interface_backend) {
412 		log_bug_client(libinput, "Mismatching backends.\n");
413 		return;
414 	}
415 
416 	list_for_each_safe(dev, &input->path_list, link) {
417 		if (dev->udev_device == evdev->udev_device) {
418 			path_device_destroy(dev);
419 			break;
420 		}
421 	}
422 
423 	seat = device->seat;
424 	libinput_seat_ref(seat);
425 	path_disable_device(evdev);
426 	libinput_seat_unref(seat);
427 }
428