xref: /third_party/libinput/src/path-seat.c (revision a46c0ec8)
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
32struct path_input {
33	struct libinput base;
34	struct udev *udev;
35	struct list path_list;
36};
37
38struct path_device {
39	struct list link;
40	struct udev_device *udev_device;
41};
42
43struct path_seat {
44	struct libinput_seat base;
45};
46
47static const char default_seat[] = "seat0";
48static const char default_seat_name[] = "default";
49
50static void
51path_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
66static void
67path_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
82static void
83path_seat_destroy(struct libinput_seat *seat)
84{
85	struct path_seat *pseat = (struct path_seat*)seat;
86	free(pseat);
87}
88
89static struct path_seat*
90path_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
104static struct path_seat*
105path_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
120static struct path_seat *
121path_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);
165out:
166	free(seat_name);
167	free(seat_logical_name);
168
169	return seat;
170}
171
172static struct libinput_device *
173path_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
211out:
212	return device ? &device->base : NULL;
213}
214
215static int
216path_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
231static void
232path_device_destroy(struct path_device *dev)
233{
234	list_remove(&dev->link);
235	udev_device_unref(dev->udev_device);
236	free(dev);
237}
238
239static void
240path_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
252static struct libinput_device *
253path_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
274static int
275path_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
293static 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
300LIBINPUT_EXPORT struct libinput *
301libinput_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
328static inline struct udev_device *
329udev_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
358LIBINPUT_EXPORT struct libinput_device *
359libinput_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
402LIBINPUT_EXPORT void
403libinput_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