• 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 
48 static const char default_seat[] = "seat0";
49 static const char default_seat_name[] = "default";
50 
51 static void
path_disable_device(struct evdev_device * device)52 path_disable_device(struct evdev_device *device)
53 {
54 	struct libinput_seat *seat = device->base.seat;
55 	struct evdev_device *dev;
56 
57 	list_for_each_safe(dev,
58 			   &seat->devices_list, base.link) {
59 		if (dev != device)
60 			continue;
61 
62 		evdev_device_remove(device);
63 		break;
64 	}
65 }
66 
67 static void
path_input_disable(struct libinput * libinput)68 path_input_disable(struct libinput *libinput)
69 {
70 	struct path_input *input = (struct path_input*)libinput;
71 	struct path_seat *seat;
72 	struct evdev_device *device;
73 
74 	list_for_each_safe(seat, &input->base.seat_list, base.link) {
75 		libinput_seat_ref(&seat->base);
76 		list_for_each_safe(device,
77 				   &seat->base.devices_list, base.link)
78 			path_disable_device(device);
79 		libinput_seat_unref(&seat->base);
80 	}
81 }
82 
83 static void
path_seat_destroy(struct libinput_seat * seat)84 path_seat_destroy(struct libinput_seat *seat)
85 {
86 	struct path_seat *pseat = (struct path_seat*)seat;
87 	free(pseat);
88 }
89 
90 static struct path_seat*
path_seat_create(struct path_input * input,const char * seat_name,const char * seat_logical_name)91 path_seat_create(struct path_input *input,
92 		 const char *seat_name,
93 		 const char *seat_logical_name)
94 {
95 	struct path_seat *seat;
96 
97 	seat = zalloc(sizeof(*seat));
98 
99 	libinput_seat_init(&seat->base, &input->base, seat_name,
100 			   seat_logical_name, path_seat_destroy);
101 
102 	return seat;
103 }
104 
105 static struct path_seat*
path_seat_get_named(struct path_input * input,const char * seat_name_physical,const char * seat_name_logical)106 path_seat_get_named(struct path_input *input,
107 		    const char *seat_name_physical,
108 		    const char *seat_name_logical)
109 {
110 	struct path_seat *seat;
111 
112 	list_for_each(seat, &input->base.seat_list, base.link) {
113 		if (streq(seat->base.physical_name, seat_name_physical) &&
114 		    streq(seat->base.logical_name, seat_name_logical))
115 			return seat;
116 	}
117 
118 	return NULL;
119 }
120 
121 static struct path_seat *
path_seat_get_for_device(struct path_input * input,struct udev_device * udev_device,const char * seat_logical_name_override)122 path_seat_get_for_device(struct path_input *input,
123 			 struct udev_device *udev_device,
124 			 const char *seat_logical_name_override)
125 {
126 	struct path_seat *seat = NULL;
127 	char *seat_name = NULL, *seat_logical_name = NULL;
128 	const char *seat_prop;
129 
130 	const char *devnode, *sysname;
131 
132 	devnode = udev_device_get_devnode(udev_device);
133 	sysname = udev_device_get_sysname(udev_device);
134 
135 	seat_prop = udev_device_get_property_value(udev_device, "ID_SEAT");
136 	seat_name = safe_strdup(seat_prop ? seat_prop : default_seat);
137 
138 	if (seat_logical_name_override) {
139 		seat_logical_name = safe_strdup(seat_logical_name_override);
140 	} else {
141 		seat_prop = udev_device_get_property_value(udev_device, "WL_SEAT");
142 		seat_logical_name = safe_strdup(seat_prop ? seat_prop : default_seat_name);
143 	}
144 
145 	if (!seat_logical_name) {
146 		log_error(&input->base,
147 			  "%s: failed to create seat name for device '%s'.\n",
148 			  sysname,
149 			  devnode);
150 		goto out;
151 	}
152 
153 	seat = path_seat_get_named(input, seat_name, seat_logical_name);
154 
155 	if (!seat)
156 		seat = path_seat_create(input, seat_name, seat_logical_name);
157 	if (!seat) {
158 		log_info(&input->base,
159 			 "%s: failed to create seat for device '%s'.\n",
160 			 sysname,
161 			 devnode);
162 		goto out;
163 	}
164 
165 	libinput_seat_ref(&seat->base);
166 out:
167 	free(seat_name);
168 	free(seat_logical_name);
169 
170 	return seat;
171 }
172 
173 static struct libinput_device *
path_device_enable(struct path_input * input,struct udev_device * udev_device,const char * seat_logical_name_override)174 path_device_enable(struct path_input *input,
175 		   struct udev_device *udev_device,
176 		   const char *seat_logical_name_override)
177 {
178 	struct path_seat *seat;
179 	struct evdev_device *device = NULL;
180 	const char *output_name;
181 	const char *devnode, *sysname;
182 
183 	devnode = udev_device_get_devnode(udev_device);
184 	sysname = udev_device_get_sysname(udev_device);
185 
186 	seat = path_seat_get_for_device(input, udev_device, seat_logical_name_override);
187 	if (!seat)
188 		goto out;
189 
190 	device = evdev_device_create(&seat->base, udev_device);
191 	libinput_seat_unref(&seat->base);
192 
193 	if (device == EVDEV_UNHANDLED_DEVICE) {
194 		device = NULL;
195 		log_info(&input->base,
196 			 "%-7s - not using input device '%s'.\n",
197 			 sysname,
198 			 devnode);
199 		goto out;
200 	} else if (device == NULL) {
201 		log_info(&input->base,
202 			 "%-7s - failed to create input device '%s'.\n",
203 			 sysname,
204 			 devnode);
205 		goto out;
206 	}
207 
208 	evdev_read_calibration_prop(device);
209 	output_name = udev_device_get_property_value(udev_device, "WL_OUTPUT");
210 	device->output_name = safe_strdup(output_name);
211 
212 out:
213 	return device ? &device->base : NULL;
214 }
215 
216 static int
path_input_enable(struct libinput * libinput)217 path_input_enable(struct libinput *libinput)
218 {
219 	struct path_input *input = (struct path_input*)libinput;
220 	struct path_device *dev;
221 
222 	list_for_each(dev, &input->path_list, link) {
223 		if (path_device_enable(input, dev->udev_device, NULL) == NULL) {
224 			path_input_disable(libinput);
225 			return -1;
226 		}
227 	}
228 
229 	return 0;
230 }
231 
232 static void
path_device_destroy(struct path_device * dev)233 path_device_destroy(struct path_device *dev)
234 {
235 	list_remove(&dev->link);
236 	udev_device_unref(dev->udev_device);
237 	free(dev);
238 }
239 
240 static void
path_input_destroy(struct libinput * input)241 path_input_destroy(struct libinput *input)
242 {
243 	struct path_input *path_input = (struct path_input*)input;
244 	struct path_device *dev;
245 
246 	udev_unref(path_input->udev);
247 
248 	list_for_each_safe(dev, &path_input->path_list, link)
249 		path_device_destroy(dev);
250 
251 }
252 
253 static struct libinput_device *
path_create_device(struct libinput * libinput,struct udev_device * udev_device,const char * seat_name)254 path_create_device(struct libinput *libinput,
255 		   struct udev_device *udev_device,
256 		   const char *seat_name)
257 {
258 	struct path_input *input = (struct path_input*)libinput;
259 	struct path_device *dev;
260 	struct libinput_device *device;
261 
262 	dev = zalloc(sizeof *dev);
263 	dev->udev_device = udev_device_ref(udev_device);
264 
265 	list_insert(&input->path_list, &dev->link);
266 
267 	device = path_device_enable(input, udev_device, seat_name);
268 
269 	if (!device)
270 		path_device_destroy(dev);
271 
272 	return device;
273 }
274 
275 static int
path_device_change_seat(struct libinput_device * device,const char * seat_name)276 path_device_change_seat(struct libinput_device *device,
277 			const char *seat_name)
278 {
279 	struct libinput *libinput = device->seat->libinput;
280 	struct evdev_device *evdev = evdev_device(device);
281 	struct udev_device *udev_device = NULL;
282 	int rc = -1;
283 
284 	udev_device = evdev->udev_device;
285 	udev_device_ref(udev_device);
286 	libinput_path_remove_device(device);
287 
288 	if (path_create_device(libinput, udev_device, seat_name) != NULL)
289 		rc = 0;
290 	udev_device_unref(udev_device);
291 	return rc;
292 }
293 
294 static const struct libinput_interface_backend interface_backend = {
295 	.resume = path_input_enable,
296 	.suspend = path_input_disable,
297 	.destroy = path_input_destroy,
298 	.device_change_seat = path_device_change_seat,
299 };
300 
301 LIBINPUT_EXPORT struct libinput *
libinput_path_create_context(const struct libinput_interface * interface,void * user_data)302 libinput_path_create_context(const struct libinput_interface *interface,
303 			     void *user_data)
304 {
305 	struct path_input *input;
306 	struct udev *udev;
307 
308 	if (!interface)
309 		return NULL;
310 
311 	udev = udev_new();
312 	if (!udev)
313 		return NULL;
314 
315 	input = zalloc(sizeof *input);
316 	if (libinput_init(&input->base, interface,
317 			  &interface_backend, user_data) != 0) {
318 		udev_unref(udev);
319 		free(input);
320 		return NULL;
321 	}
322 
323 	input->udev = udev;
324 	list_init(&input->path_list);
325 
326 	return &input->base;
327 }
328 
329 static inline struct udev_device *
udev_device_from_devnode(struct libinput * libinput,struct udev * udev,const char * devnode)330 udev_device_from_devnode(struct libinput *libinput,
331 			 struct udev *udev,
332 			 const char *devnode)
333 {
334 	struct udev_device *dev;
335 	struct stat st;
336 	size_t count = 0;
337 
338 	if (stat(devnode, &st) < 0)
339 		return NULL;
340 
341 	dev = udev_device_new_from_devnum(udev, 'c', st.st_rdev);
342 
343 	while (dev && !udev_device_get_is_initialized(dev)) {
344 		udev_device_unref(dev);
345 		count++;
346 		if (count > 200) {
347 			log_bug_libinput(libinput,
348 					"udev device never initialized (%s)\n",
349 					devnode);
350 			return NULL;
351 		}
352 		msleep(10);
353 		dev = udev_device_new_from_devnum(udev, 'c', st.st_rdev);
354 	}
355 
356 	return dev;
357 }
358 
359 LIBINPUT_EXPORT struct libinput_device *
libinput_path_add_device(struct libinput * libinput,const char * path)360 libinput_path_add_device(struct libinput *libinput,
361 			 const char *path)
362 {
363 	struct path_input *input = (struct path_input *)libinput;
364 	struct udev *udev = input->udev;
365 	struct udev_device *udev_device;
366 	struct libinput_device *device;
367 
368 	if (strlen(path) > PATH_MAX) {
369 		log_bug_client(libinput,
370 			       "Unexpected path, limited to %d characters.\n",
371 			       PATH_MAX);
372 		return NULL;
373 	}
374 
375 	if (libinput->interface_backend != &interface_backend) {
376 		log_bug_client(libinput, "Mismatching backends.\n");
377 		return NULL;
378 	}
379 
380 	udev_device = udev_device_from_devnode(libinput, udev, path);
381 	if (!udev_device) {
382 		log_bug_client(libinput, "Invalid path %s\n", path);
383 		return NULL;
384 	}
385 
386 	if (ignore_litest_test_suite_device(udev_device)) {
387 		udev_device_unref(udev_device);
388 		return NULL;
389 	}
390 
391 	/* We cannot do this during path_create_context because the log
392 	 * handler isn't set up there but we really want to log to the right
393 	 * place if the quirks run into parser errors. So we have to do it
394 	 * on the first call to add_device.
395 	 */
396 	libinput_init_quirks(libinput);
397 
398 	device = path_create_device(libinput, udev_device, NULL);
399 	udev_device_unref(udev_device);
400 	return device;
401 }
402 
403 LIBINPUT_EXPORT void
libinput_path_remove_device(struct libinput_device * device)404 libinput_path_remove_device(struct libinput_device *device)
405 {
406 	struct libinput *libinput = device->seat->libinput;
407 	struct path_input *input = (struct path_input*)libinput;
408 	struct libinput_seat *seat;
409 	struct evdev_device *evdev = evdev_device(device);
410 	struct path_device *dev;
411 
412 	if (libinput->interface_backend != &interface_backend) {
413 		log_bug_client(libinput, "Mismatching backends.\n");
414 		return;
415 	}
416 
417 	list_for_each_safe(dev, &input->path_list, link) {
418 		if (dev->udev_device == evdev->udev_device) {
419 			path_device_destroy(dev);
420 			break;
421 		}
422 	}
423 
424 	seat = device->seat;
425 	libinput_seat_ref(seat);
426 	path_disable_device(evdev);
427 	libinput_seat_unref(seat);
428 }
429