1a46c0ec8Sopenharmony_ci/*
2a46c0ec8Sopenharmony_ci * Copyright © 2013 Intel Corporation
3a46c0ec8Sopenharmony_ci * Copyright © 2013-2015 Red Hat, Inc.
4a46c0ec8Sopenharmony_ci *
5a46c0ec8Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
6a46c0ec8Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
7a46c0ec8Sopenharmony_ci * to deal in the Software without restriction, including without limitation
8a46c0ec8Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9a46c0ec8Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
10a46c0ec8Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
11a46c0ec8Sopenharmony_ci *
12a46c0ec8Sopenharmony_ci * The above copyright notice and this permission notice (including the next
13a46c0ec8Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
14a46c0ec8Sopenharmony_ci * Software.
15a46c0ec8Sopenharmony_ci *
16a46c0ec8Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17a46c0ec8Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18a46c0ec8Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19a46c0ec8Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20a46c0ec8Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21a46c0ec8Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22a46c0ec8Sopenharmony_ci * DEALINGS IN THE SOFTWARE.
23a46c0ec8Sopenharmony_ci */
24a46c0ec8Sopenharmony_ci
25a46c0ec8Sopenharmony_ci#include "config.h"
26a46c0ec8Sopenharmony_ci
27a46c0ec8Sopenharmony_ci#include <stdlib.h>
28a46c0ec8Sopenharmony_ci#include <stdio.h>
29a46c0ec8Sopenharmony_ci#include <string.h>
30a46c0ec8Sopenharmony_ci
31a46c0ec8Sopenharmony_ci#include "evdev.h"
32a46c0ec8Sopenharmony_ci#include "udev-seat.h"
33a46c0ec8Sopenharmony_ci
34a46c0ec8Sopenharmony_cistatic const char default_seat[] = "seat0";
35a46c0ec8Sopenharmony_cistatic const char default_seat_name[] = "default";
36a46c0ec8Sopenharmony_ci
37a46c0ec8Sopenharmony_cistatic struct udev_seat *
38a46c0ec8Sopenharmony_ciudev_seat_create(struct udev_input *input,
39a46c0ec8Sopenharmony_ci		 const char *device_seat,
40a46c0ec8Sopenharmony_ci		 const char *seat_name);
41a46c0ec8Sopenharmony_cistatic struct udev_seat *
42a46c0ec8Sopenharmony_ciudev_seat_get_named(struct udev_input *input, const char *seat_name);
43a46c0ec8Sopenharmony_ci
44a46c0ec8Sopenharmony_cistatic inline bool
45a46c0ec8Sopenharmony_cifilter_duplicates(struct udev_seat *udev_seat,
46a46c0ec8Sopenharmony_ci		  struct udev_device *udev_device)
47a46c0ec8Sopenharmony_ci{
48a46c0ec8Sopenharmony_ci	struct libinput_device *device;
49a46c0ec8Sopenharmony_ci	const char *new_syspath = udev_device_get_syspath(udev_device);
50a46c0ec8Sopenharmony_ci	bool ignore_device = false;
51a46c0ec8Sopenharmony_ci
52a46c0ec8Sopenharmony_ci	if (!udev_seat)
53a46c0ec8Sopenharmony_ci		return false;
54a46c0ec8Sopenharmony_ci
55a46c0ec8Sopenharmony_ci	list_for_each(device, &udev_seat->base.devices_list, link) {
56a46c0ec8Sopenharmony_ci		const char *syspath;
57a46c0ec8Sopenharmony_ci		struct udev_device *ud;
58a46c0ec8Sopenharmony_ci
59a46c0ec8Sopenharmony_ci		ud = libinput_device_get_udev_device(device);
60a46c0ec8Sopenharmony_ci		if (!ud)
61a46c0ec8Sopenharmony_ci			continue;
62a46c0ec8Sopenharmony_ci
63a46c0ec8Sopenharmony_ci		syspath = udev_device_get_syspath(ud);
64a46c0ec8Sopenharmony_ci		if (syspath && new_syspath && streq(syspath, new_syspath))
65a46c0ec8Sopenharmony_ci			ignore_device = true;
66a46c0ec8Sopenharmony_ci		udev_device_unref(ud);
67a46c0ec8Sopenharmony_ci
68a46c0ec8Sopenharmony_ci		if (ignore_device)
69a46c0ec8Sopenharmony_ci			break;
70a46c0ec8Sopenharmony_ci	}
71a46c0ec8Sopenharmony_ci
72a46c0ec8Sopenharmony_ci	return ignore_device;
73a46c0ec8Sopenharmony_ci}
74a46c0ec8Sopenharmony_ci
75a46c0ec8Sopenharmony_cistatic int
76a46c0ec8Sopenharmony_cidevice_added(struct udev_device *udev_device,
77a46c0ec8Sopenharmony_ci	     struct udev_input *input,
78a46c0ec8Sopenharmony_ci	     const char *seat_name)
79a46c0ec8Sopenharmony_ci{
80a46c0ec8Sopenharmony_ci	struct evdev_device *device;
81a46c0ec8Sopenharmony_ci	const char *devnode, *sysname;
82a46c0ec8Sopenharmony_ci	const char *device_seat, *output_name;
83a46c0ec8Sopenharmony_ci	struct udev_seat *seat;
84a46c0ec8Sopenharmony_ci
85a46c0ec8Sopenharmony_ci	device_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
86a46c0ec8Sopenharmony_ci	if (!device_seat)
87a46c0ec8Sopenharmony_ci		device_seat = default_seat;
88a46c0ec8Sopenharmony_ci
89a46c0ec8Sopenharmony_ci	if (!streq(device_seat, input->seat_id))
90a46c0ec8Sopenharmony_ci		return 0;
91a46c0ec8Sopenharmony_ci
92a46c0ec8Sopenharmony_ci	if (ignore_litest_test_suite_device(udev_device))
93a46c0ec8Sopenharmony_ci		return 0;
94a46c0ec8Sopenharmony_ci
95a46c0ec8Sopenharmony_ci	devnode = udev_device_get_devnode(udev_device);
96a46c0ec8Sopenharmony_ci	sysname = udev_device_get_sysname(udev_device);
97a46c0ec8Sopenharmony_ci
98a46c0ec8Sopenharmony_ci	/* Search for matching logical seat */
99a46c0ec8Sopenharmony_ci	if (!seat_name)
100a46c0ec8Sopenharmony_ci		seat_name = udev_device_get_property_value(udev_device, "WL_SEAT");
101a46c0ec8Sopenharmony_ci	if (!seat_name)
102a46c0ec8Sopenharmony_ci		seat_name = default_seat_name;
103a46c0ec8Sopenharmony_ci
104a46c0ec8Sopenharmony_ci	seat = udev_seat_get_named(input, seat_name);
105a46c0ec8Sopenharmony_ci
106a46c0ec8Sopenharmony_ci	/* There is a race at startup: a device added between setting
107a46c0ec8Sopenharmony_ci	 * up the udev monitor and enumerating all current devices may show
108a46c0ec8Sopenharmony_ci	 * up in both lists. Filter those out.
109a46c0ec8Sopenharmony_ci	 */
110a46c0ec8Sopenharmony_ci	if (filter_duplicates(seat, udev_device))
111a46c0ec8Sopenharmony_ci		return 0;
112a46c0ec8Sopenharmony_ci
113a46c0ec8Sopenharmony_ci	if (seat)
114a46c0ec8Sopenharmony_ci		libinput_seat_ref(&seat->base);
115a46c0ec8Sopenharmony_ci	else {
116a46c0ec8Sopenharmony_ci		seat = udev_seat_create(input, device_seat, seat_name);
117a46c0ec8Sopenharmony_ci		if (!seat)
118a46c0ec8Sopenharmony_ci			return -1;
119a46c0ec8Sopenharmony_ci	}
120a46c0ec8Sopenharmony_ci
121a46c0ec8Sopenharmony_ci	device = evdev_device_create(&seat->base, udev_device);
122a46c0ec8Sopenharmony_ci	libinput_seat_unref(&seat->base);
123a46c0ec8Sopenharmony_ci
124a46c0ec8Sopenharmony_ci	if (device == EVDEV_UNHANDLED_DEVICE) {
125a46c0ec8Sopenharmony_ci		log_info(&input->base,
126a46c0ec8Sopenharmony_ci			 "%-7s - not using input device '%s'\n",
127a46c0ec8Sopenharmony_ci			 sysname,
128a46c0ec8Sopenharmony_ci			 devnode);
129a46c0ec8Sopenharmony_ci		return 0;
130a46c0ec8Sopenharmony_ci	}
131a46c0ec8Sopenharmony_ci
132a46c0ec8Sopenharmony_ci	if (device == NULL) {
133a46c0ec8Sopenharmony_ci		log_info(&input->base,
134a46c0ec8Sopenharmony_ci			 "%-7s - failed to create input device '%s'\n",
135a46c0ec8Sopenharmony_ci			 sysname,
136a46c0ec8Sopenharmony_ci			 devnode);
137a46c0ec8Sopenharmony_ci		return 0;
138a46c0ec8Sopenharmony_ci	}
139a46c0ec8Sopenharmony_ci
140a46c0ec8Sopenharmony_ci	evdev_read_calibration_prop(device);
141a46c0ec8Sopenharmony_ci
142a46c0ec8Sopenharmony_ci	output_name = udev_device_get_property_value(udev_device, "WL_OUTPUT");
143a46c0ec8Sopenharmony_ci	device->output_name = safe_strdup(output_name);
144a46c0ec8Sopenharmony_ci
145a46c0ec8Sopenharmony_ci	return 0;
146a46c0ec8Sopenharmony_ci}
147a46c0ec8Sopenharmony_ci
148a46c0ec8Sopenharmony_cistatic void
149a46c0ec8Sopenharmony_cidevice_removed(struct udev_device *udev_device, struct udev_input *input)
150a46c0ec8Sopenharmony_ci{
151a46c0ec8Sopenharmony_ci	struct evdev_device *device;
152a46c0ec8Sopenharmony_ci	struct udev_seat *seat;
153a46c0ec8Sopenharmony_ci	const char *syspath;
154a46c0ec8Sopenharmony_ci
155a46c0ec8Sopenharmony_ci	syspath = udev_device_get_syspath(udev_device);
156a46c0ec8Sopenharmony_ci	list_for_each(seat, &input->base.seat_list, base.link) {
157a46c0ec8Sopenharmony_ci		list_for_each_safe(device,
158a46c0ec8Sopenharmony_ci				   &seat->base.devices_list, base.link) {
159a46c0ec8Sopenharmony_ci			if (streq(syspath,
160a46c0ec8Sopenharmony_ci				  udev_device_get_syspath(device->udev_device))) {
161a46c0ec8Sopenharmony_ci				evdev_device_remove(device);
162a46c0ec8Sopenharmony_ci				break;
163a46c0ec8Sopenharmony_ci			}
164a46c0ec8Sopenharmony_ci		}
165a46c0ec8Sopenharmony_ci	}
166a46c0ec8Sopenharmony_ci}
167a46c0ec8Sopenharmony_ci
168a46c0ec8Sopenharmony_cistatic int
169a46c0ec8Sopenharmony_ciudev_input_add_devices(struct udev_input *input, struct udev *udev)
170a46c0ec8Sopenharmony_ci{
171a46c0ec8Sopenharmony_ci	struct udev_enumerate *e;
172a46c0ec8Sopenharmony_ci	struct udev_list_entry *entry;
173a46c0ec8Sopenharmony_ci	struct udev_device *device;
174a46c0ec8Sopenharmony_ci	const char *path, *sysname;
175a46c0ec8Sopenharmony_ci
176a46c0ec8Sopenharmony_ci	e = udev_enumerate_new(udev);
177a46c0ec8Sopenharmony_ci	udev_enumerate_add_match_subsystem(e, "input");
178a46c0ec8Sopenharmony_ci	udev_enumerate_scan_devices(e);
179a46c0ec8Sopenharmony_ci	udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
180a46c0ec8Sopenharmony_ci		path = udev_list_entry_get_name(entry);
181a46c0ec8Sopenharmony_ci		device = udev_device_new_from_syspath(udev, path);
182a46c0ec8Sopenharmony_ci		if (!device)
183a46c0ec8Sopenharmony_ci			continue;
184a46c0ec8Sopenharmony_ci
185a46c0ec8Sopenharmony_ci		sysname = udev_device_get_sysname(device);
186a46c0ec8Sopenharmony_ci		if (!strneq("event", sysname, 5)) {
187a46c0ec8Sopenharmony_ci			udev_device_unref(device);
188a46c0ec8Sopenharmony_ci			continue;
189a46c0ec8Sopenharmony_ci		}
190a46c0ec8Sopenharmony_ci
191a46c0ec8Sopenharmony_ci		/* Skip unconfigured device. udev will send an event
192a46c0ec8Sopenharmony_ci		 * when device is fully configured  */
193a46c0ec8Sopenharmony_ci		if (!udev_device_get_is_initialized(device)) {
194a46c0ec8Sopenharmony_ci			log_debug(&input->base,
195a46c0ec8Sopenharmony_ci				  "%-7s - skip unconfigured input device '%s'\n",
196a46c0ec8Sopenharmony_ci				  sysname,
197a46c0ec8Sopenharmony_ci				  udev_device_get_devnode(device));
198a46c0ec8Sopenharmony_ci			udev_device_unref(device);
199a46c0ec8Sopenharmony_ci			continue;
200a46c0ec8Sopenharmony_ci		}
201a46c0ec8Sopenharmony_ci
202a46c0ec8Sopenharmony_ci		if (device_added(device, input, NULL) < 0) {
203a46c0ec8Sopenharmony_ci			udev_device_unref(device);
204a46c0ec8Sopenharmony_ci			udev_enumerate_unref(e);
205a46c0ec8Sopenharmony_ci			return -1;
206a46c0ec8Sopenharmony_ci		}
207a46c0ec8Sopenharmony_ci
208a46c0ec8Sopenharmony_ci		udev_device_unref(device);
209a46c0ec8Sopenharmony_ci	}
210a46c0ec8Sopenharmony_ci	udev_enumerate_unref(e);
211a46c0ec8Sopenharmony_ci
212a46c0ec8Sopenharmony_ci	return 0;
213a46c0ec8Sopenharmony_ci}
214a46c0ec8Sopenharmony_ci
215a46c0ec8Sopenharmony_cistatic void
216a46c0ec8Sopenharmony_cievdev_udev_handler(void *data)
217a46c0ec8Sopenharmony_ci{
218a46c0ec8Sopenharmony_ci	struct udev_input *input = data;
219a46c0ec8Sopenharmony_ci	struct udev_device *udev_device;
220a46c0ec8Sopenharmony_ci	const char *action;
221a46c0ec8Sopenharmony_ci
222a46c0ec8Sopenharmony_ci	udev_device = udev_monitor_receive_device(input->udev_monitor);
223a46c0ec8Sopenharmony_ci	if (!udev_device)
224a46c0ec8Sopenharmony_ci		return;
225a46c0ec8Sopenharmony_ci
226a46c0ec8Sopenharmony_ci	action = udev_device_get_action(udev_device);
227a46c0ec8Sopenharmony_ci	if (!action)
228a46c0ec8Sopenharmony_ci		goto out;
229a46c0ec8Sopenharmony_ci
230a46c0ec8Sopenharmony_ci	if (!strneq("event", udev_device_get_sysname(udev_device), 5))
231a46c0ec8Sopenharmony_ci		goto out;
232a46c0ec8Sopenharmony_ci
233a46c0ec8Sopenharmony_ci	if (streq(action, "add"))
234a46c0ec8Sopenharmony_ci		device_added(udev_device, input, NULL);
235a46c0ec8Sopenharmony_ci	else if (streq(action, "remove"))
236a46c0ec8Sopenharmony_ci		device_removed(udev_device, input);
237a46c0ec8Sopenharmony_ci
238a46c0ec8Sopenharmony_ciout:
239a46c0ec8Sopenharmony_ci	udev_device_unref(udev_device);
240a46c0ec8Sopenharmony_ci}
241a46c0ec8Sopenharmony_ci
242a46c0ec8Sopenharmony_cistatic void
243a46c0ec8Sopenharmony_ciudev_input_remove_devices(struct udev_input *input)
244a46c0ec8Sopenharmony_ci{
245a46c0ec8Sopenharmony_ci	struct evdev_device *device;
246a46c0ec8Sopenharmony_ci	struct udev_seat *seat;
247a46c0ec8Sopenharmony_ci
248a46c0ec8Sopenharmony_ci	list_for_each_safe(seat, &input->base.seat_list, base.link) {
249a46c0ec8Sopenharmony_ci		libinput_seat_ref(&seat->base);
250a46c0ec8Sopenharmony_ci		list_for_each_safe(device,
251a46c0ec8Sopenharmony_ci				   &seat->base.devices_list, base.link) {
252a46c0ec8Sopenharmony_ci			evdev_device_remove(device);
253a46c0ec8Sopenharmony_ci		}
254a46c0ec8Sopenharmony_ci		libinput_seat_unref(&seat->base);
255a46c0ec8Sopenharmony_ci	}
256a46c0ec8Sopenharmony_ci}
257a46c0ec8Sopenharmony_ci
258a46c0ec8Sopenharmony_cistatic void
259a46c0ec8Sopenharmony_ciudev_input_disable(struct libinput *libinput)
260a46c0ec8Sopenharmony_ci{
261a46c0ec8Sopenharmony_ci	struct udev_input *input = (struct udev_input*)libinput;
262a46c0ec8Sopenharmony_ci
263a46c0ec8Sopenharmony_ci	if (!input->udev_monitor)
264a46c0ec8Sopenharmony_ci		return;
265a46c0ec8Sopenharmony_ci
266a46c0ec8Sopenharmony_ci	udev_monitor_unref(input->udev_monitor);
267a46c0ec8Sopenharmony_ci	input->udev_monitor = NULL;
268a46c0ec8Sopenharmony_ci	libinput_remove_source(&input->base, input->udev_monitor_source);
269a46c0ec8Sopenharmony_ci	input->udev_monitor_source = NULL;
270a46c0ec8Sopenharmony_ci
271a46c0ec8Sopenharmony_ci	udev_input_remove_devices(input);
272a46c0ec8Sopenharmony_ci}
273a46c0ec8Sopenharmony_ci
274a46c0ec8Sopenharmony_cistatic int
275a46c0ec8Sopenharmony_ciudev_input_enable(struct libinput *libinput)
276a46c0ec8Sopenharmony_ci{
277a46c0ec8Sopenharmony_ci	struct udev_input *input = (struct udev_input*)libinput;
278a46c0ec8Sopenharmony_ci	struct udev *udev = input->udev;
279a46c0ec8Sopenharmony_ci	int fd;
280a46c0ec8Sopenharmony_ci
281a46c0ec8Sopenharmony_ci	if (input->udev_monitor || !input->seat_id)
282a46c0ec8Sopenharmony_ci		return 0;
283a46c0ec8Sopenharmony_ci
284a46c0ec8Sopenharmony_ci	input->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
285a46c0ec8Sopenharmony_ci	if (!input->udev_monitor) {
286a46c0ec8Sopenharmony_ci		log_info(libinput,
287a46c0ec8Sopenharmony_ci			 "udev: failed to create the udev monitor\n");
288a46c0ec8Sopenharmony_ci		return -1;
289a46c0ec8Sopenharmony_ci	}
290a46c0ec8Sopenharmony_ci
291a46c0ec8Sopenharmony_ci	if (udev_monitor_filter_add_match_subsystem_devtype(
292a46c0ec8Sopenharmony_ci				input->udev_monitor, "input", NULL)) {
293a46c0ec8Sopenharmony_ci		log_info(libinput, "udev: failed to set up filter\n");
294a46c0ec8Sopenharmony_ci		return -1;
295a46c0ec8Sopenharmony_ci	}
296a46c0ec8Sopenharmony_ci
297a46c0ec8Sopenharmony_ci	if (udev_monitor_enable_receiving(input->udev_monitor)) {
298a46c0ec8Sopenharmony_ci		log_info(libinput, "udev: failed to bind the udev monitor\n");
299a46c0ec8Sopenharmony_ci		udev_monitor_unref(input->udev_monitor);
300a46c0ec8Sopenharmony_ci		input->udev_monitor = NULL;
301a46c0ec8Sopenharmony_ci		return -1;
302a46c0ec8Sopenharmony_ci	}
303a46c0ec8Sopenharmony_ci
304a46c0ec8Sopenharmony_ci	fd = udev_monitor_get_fd(input->udev_monitor);
305a46c0ec8Sopenharmony_ci	input->udev_monitor_source = libinput_add_fd(&input->base,
306a46c0ec8Sopenharmony_ci						     fd,
307a46c0ec8Sopenharmony_ci						     evdev_udev_handler,
308a46c0ec8Sopenharmony_ci						     input);
309a46c0ec8Sopenharmony_ci	if (!input->udev_monitor_source) {
310a46c0ec8Sopenharmony_ci		udev_monitor_unref(input->udev_monitor);
311a46c0ec8Sopenharmony_ci		input->udev_monitor = NULL;
312a46c0ec8Sopenharmony_ci		return -1;
313a46c0ec8Sopenharmony_ci	}
314a46c0ec8Sopenharmony_ci
315a46c0ec8Sopenharmony_ci	if (udev_input_add_devices(input, udev) < 0) {
316a46c0ec8Sopenharmony_ci		udev_input_disable(libinput);
317a46c0ec8Sopenharmony_ci		return -1;
318a46c0ec8Sopenharmony_ci	}
319a46c0ec8Sopenharmony_ci
320a46c0ec8Sopenharmony_ci	return 0;
321a46c0ec8Sopenharmony_ci}
322a46c0ec8Sopenharmony_ci
323a46c0ec8Sopenharmony_cistatic void
324a46c0ec8Sopenharmony_ciudev_input_destroy(struct libinput *input)
325a46c0ec8Sopenharmony_ci{
326a46c0ec8Sopenharmony_ci	struct udev_input *udev_input = (struct udev_input*)input;
327a46c0ec8Sopenharmony_ci
328a46c0ec8Sopenharmony_ci	if (input == NULL)
329a46c0ec8Sopenharmony_ci		return;
330a46c0ec8Sopenharmony_ci
331a46c0ec8Sopenharmony_ci	udev_unref(udev_input->udev);
332a46c0ec8Sopenharmony_ci	free(udev_input->seat_id);
333a46c0ec8Sopenharmony_ci}
334a46c0ec8Sopenharmony_ci
335a46c0ec8Sopenharmony_cistatic void
336a46c0ec8Sopenharmony_ciudev_seat_destroy(struct libinput_seat *seat)
337a46c0ec8Sopenharmony_ci{
338a46c0ec8Sopenharmony_ci	struct udev_seat *useat = (struct udev_seat*)seat;
339a46c0ec8Sopenharmony_ci	free(useat);
340a46c0ec8Sopenharmony_ci}
341a46c0ec8Sopenharmony_ci
342a46c0ec8Sopenharmony_cistatic struct udev_seat *
343a46c0ec8Sopenharmony_ciudev_seat_create(struct udev_input *input,
344a46c0ec8Sopenharmony_ci		 const char *device_seat,
345a46c0ec8Sopenharmony_ci		 const char *seat_name)
346a46c0ec8Sopenharmony_ci{
347a46c0ec8Sopenharmony_ci	struct udev_seat *seat;
348a46c0ec8Sopenharmony_ci
349a46c0ec8Sopenharmony_ci	seat = zalloc(sizeof *seat);
350a46c0ec8Sopenharmony_ci
351a46c0ec8Sopenharmony_ci	libinput_seat_init(&seat->base, &input->base,
352a46c0ec8Sopenharmony_ci			   device_seat, seat_name,
353a46c0ec8Sopenharmony_ci			   udev_seat_destroy);
354a46c0ec8Sopenharmony_ci
355a46c0ec8Sopenharmony_ci	return seat;
356a46c0ec8Sopenharmony_ci}
357a46c0ec8Sopenharmony_ci
358a46c0ec8Sopenharmony_cistatic struct udev_seat *
359a46c0ec8Sopenharmony_ciudev_seat_get_named(struct udev_input *input, const char *seat_name)
360a46c0ec8Sopenharmony_ci{
361a46c0ec8Sopenharmony_ci	struct udev_seat *seat;
362a46c0ec8Sopenharmony_ci
363a46c0ec8Sopenharmony_ci	list_for_each(seat, &input->base.seat_list, base.link) {
364a46c0ec8Sopenharmony_ci		if (streq(seat->base.logical_name, seat_name))
365a46c0ec8Sopenharmony_ci			return seat;
366a46c0ec8Sopenharmony_ci	}
367a46c0ec8Sopenharmony_ci
368a46c0ec8Sopenharmony_ci	return NULL;
369a46c0ec8Sopenharmony_ci}
370a46c0ec8Sopenharmony_ci
371a46c0ec8Sopenharmony_cistatic int
372a46c0ec8Sopenharmony_ciudev_device_change_seat(struct libinput_device *device,
373a46c0ec8Sopenharmony_ci			const char *seat_name)
374a46c0ec8Sopenharmony_ci{
375a46c0ec8Sopenharmony_ci	struct libinput *libinput = device->seat->libinput;
376a46c0ec8Sopenharmony_ci	struct udev_input *input = (struct udev_input *)libinput;
377a46c0ec8Sopenharmony_ci	struct evdev_device *evdev = evdev_device(device);
378a46c0ec8Sopenharmony_ci	struct udev_device *udev_device = evdev->udev_device;
379a46c0ec8Sopenharmony_ci	int rc;
380a46c0ec8Sopenharmony_ci
381a46c0ec8Sopenharmony_ci	udev_device_ref(udev_device);
382a46c0ec8Sopenharmony_ci	device_removed(udev_device, input);
383a46c0ec8Sopenharmony_ci	rc = device_added(udev_device, input, seat_name);
384a46c0ec8Sopenharmony_ci	udev_device_unref(udev_device);
385a46c0ec8Sopenharmony_ci
386a46c0ec8Sopenharmony_ci	return rc;
387a46c0ec8Sopenharmony_ci}
388a46c0ec8Sopenharmony_ci
389a46c0ec8Sopenharmony_cistatic const struct libinput_interface_backend interface_backend = {
390a46c0ec8Sopenharmony_ci	.resume = udev_input_enable,
391a46c0ec8Sopenharmony_ci	.suspend = udev_input_disable,
392a46c0ec8Sopenharmony_ci	.destroy = udev_input_destroy,
393a46c0ec8Sopenharmony_ci	.device_change_seat = udev_device_change_seat,
394a46c0ec8Sopenharmony_ci};
395a46c0ec8Sopenharmony_ci
396a46c0ec8Sopenharmony_ciLIBINPUT_EXPORT struct libinput *
397a46c0ec8Sopenharmony_cilibinput_udev_create_context(const struct libinput_interface *interface,
398a46c0ec8Sopenharmony_ci			     void *user_data,
399a46c0ec8Sopenharmony_ci			     struct udev *udev)
400a46c0ec8Sopenharmony_ci{
401a46c0ec8Sopenharmony_ci	struct udev_input *input;
402a46c0ec8Sopenharmony_ci
403a46c0ec8Sopenharmony_ci	if (!interface || !udev)
404a46c0ec8Sopenharmony_ci		return NULL;
405a46c0ec8Sopenharmony_ci
406a46c0ec8Sopenharmony_ci	input = zalloc(sizeof *input);
407a46c0ec8Sopenharmony_ci
408a46c0ec8Sopenharmony_ci	if (libinput_init(&input->base, interface,
409a46c0ec8Sopenharmony_ci			  &interface_backend, user_data) != 0) {
410a46c0ec8Sopenharmony_ci		libinput_unref(&input->base);
411a46c0ec8Sopenharmony_ci		free(input);
412a46c0ec8Sopenharmony_ci		return NULL;
413a46c0ec8Sopenharmony_ci	}
414a46c0ec8Sopenharmony_ci
415a46c0ec8Sopenharmony_ci	input->udev = udev_ref(udev);
416a46c0ec8Sopenharmony_ci
417a46c0ec8Sopenharmony_ci	return &input->base;
418a46c0ec8Sopenharmony_ci}
419a46c0ec8Sopenharmony_ci
420a46c0ec8Sopenharmony_ciLIBINPUT_EXPORT int
421a46c0ec8Sopenharmony_cilibinput_udev_assign_seat(struct libinput *libinput,
422a46c0ec8Sopenharmony_ci			  const char *seat_id)
423a46c0ec8Sopenharmony_ci{
424a46c0ec8Sopenharmony_ci	struct udev_input *input = (struct udev_input*)libinput;
425a46c0ec8Sopenharmony_ci
426a46c0ec8Sopenharmony_ci	if (!seat_id)
427a46c0ec8Sopenharmony_ci		return -1;
428a46c0ec8Sopenharmony_ci
429a46c0ec8Sopenharmony_ci	if (strlen(seat_id) > 256) {
430a46c0ec8Sopenharmony_ci		log_bug_client(libinput,
431a46c0ec8Sopenharmony_ci			       "Unexpected seat id, limited to 256 characters.\n");
432a46c0ec8Sopenharmony_ci		return -1;
433a46c0ec8Sopenharmony_ci	}
434a46c0ec8Sopenharmony_ci
435a46c0ec8Sopenharmony_ci	if (libinput->interface_backend != &interface_backend) {
436a46c0ec8Sopenharmony_ci		log_bug_client(libinput, "Mismatching backends.\n");
437a46c0ec8Sopenharmony_ci		return -1;
438a46c0ec8Sopenharmony_ci	}
439a46c0ec8Sopenharmony_ci
440a46c0ec8Sopenharmony_ci	if (input->seat_id != NULL)
441a46c0ec8Sopenharmony_ci		return -1;
442a46c0ec8Sopenharmony_ci
443a46c0ec8Sopenharmony_ci	/* We cannot do this during udev_create_context because the log
444a46c0ec8Sopenharmony_ci	 * handler isn't set up there but we really want to log to the right
445a46c0ec8Sopenharmony_ci	 * place if the quirks run into parser errors. So we have to do it
446a46c0ec8Sopenharmony_ci	 * here since we can expect the log handler to be set up by now.
447a46c0ec8Sopenharmony_ci	 */
448a46c0ec8Sopenharmony_ci	libinput_init_quirks(libinput);
449a46c0ec8Sopenharmony_ci
450a46c0ec8Sopenharmony_ci	input->seat_id = safe_strdup(seat_id);
451a46c0ec8Sopenharmony_ci
452a46c0ec8Sopenharmony_ci	if (udev_input_enable(&input->base) < 0)
453a46c0ec8Sopenharmony_ci		return -1;
454a46c0ec8Sopenharmony_ci
455a46c0ec8Sopenharmony_ci	return 0;
456a46c0ec8Sopenharmony_ci}
457