1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright © 2009 Julien Cristau
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Permission is hereby granted, free of charge, to any person obtaining a
5*4882a593Smuzhiyun * copy of this software and associated documentation files (the "Software"),
6*4882a593Smuzhiyun * to deal in the Software without restriction, including without limitation
7*4882a593Smuzhiyun * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8*4882a593Smuzhiyun * and/or sell copies of the Software, and to permit persons to whom the
9*4882a593Smuzhiyun * Software is furnished to do so, subject to the following conditions:
10*4882a593Smuzhiyun *
11*4882a593Smuzhiyun * The above copyright notice and this permission notice (including the next
12*4882a593Smuzhiyun * paragraph) shall be included in all copies or substantial portions of the
13*4882a593Smuzhiyun * Software.
14*4882a593Smuzhiyun *
15*4882a593Smuzhiyun * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16*4882a593Smuzhiyun * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17*4882a593Smuzhiyun * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18*4882a593Smuzhiyun * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19*4882a593Smuzhiyun * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20*4882a593Smuzhiyun * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21*4882a593Smuzhiyun * DEALINGS IN THE SOFTWARE.
22*4882a593Smuzhiyun *
23*4882a593Smuzhiyun * Author: Julien Cristau <jcristau@debian.org>
24*4882a593Smuzhiyun */
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun #ifdef HAVE_DIX_CONFIG_H
27*4882a593Smuzhiyun #include <dix-config.h>
28*4882a593Smuzhiyun #endif
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun #include <libudev.h>
31*4882a593Smuzhiyun #include <ctype.h>
32*4882a593Smuzhiyun #include <unistd.h>
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun #include "input.h"
35*4882a593Smuzhiyun #include "inputstr.h"
36*4882a593Smuzhiyun #include "hotplug.h"
37*4882a593Smuzhiyun #include "config-backends.h"
38*4882a593Smuzhiyun #include "os.h"
39*4882a593Smuzhiyun #include "globals.h"
40*4882a593Smuzhiyun #include "systemd-logind.h"
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun #define UDEV_XKB_PROP_KEY "xkb"
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun #define LOG_PROPERTY(path, prop, val) \
45*4882a593Smuzhiyun LogMessageVerb(X_INFO, 10, \
46*4882a593Smuzhiyun "config/udev: getting property %s on %s " \
47*4882a593Smuzhiyun "returned \"%s\"\n", \
48*4882a593Smuzhiyun (prop), (path), (val) ? (val) : "(null)")
49*4882a593Smuzhiyun #define LOG_SYSATTR(path, attr, val) \
50*4882a593Smuzhiyun LogMessageVerb(X_INFO, 10, \
51*4882a593Smuzhiyun "config/udev: getting attribute %s on %s " \
52*4882a593Smuzhiyun "returned \"%s\"\n", \
53*4882a593Smuzhiyun (attr), (path), (val) ? (val) : "(null)")
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun static struct udev_monitor *udev_monitor;
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun #ifdef CONFIG_UDEV_KMS
58*4882a593Smuzhiyun static void
59*4882a593Smuzhiyun config_udev_odev_setup_attribs(const char *path, const char *syspath,
60*4882a593Smuzhiyun int major, int minor,
61*4882a593Smuzhiyun config_odev_probe_proc_ptr probe_callback);
62*4882a593Smuzhiyun #endif
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun static char itoa_buf[16];
65*4882a593Smuzhiyun
itoa(int i)66*4882a593Smuzhiyun static const char *itoa(int i)
67*4882a593Smuzhiyun {
68*4882a593Smuzhiyun snprintf(itoa_buf, sizeof(itoa_buf), "%d", i);
69*4882a593Smuzhiyun return itoa_buf;
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun static Bool
check_seat(struct udev_device * udev_device)73*4882a593Smuzhiyun check_seat(struct udev_device *udev_device)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun const char *dev_seat;
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun dev_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
78*4882a593Smuzhiyun if (!dev_seat)
79*4882a593Smuzhiyun dev_seat = "seat0";
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun if (SeatId && strcmp(dev_seat, SeatId))
82*4882a593Smuzhiyun return FALSE;
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun if (!SeatId && strcmp(dev_seat, "seat0"))
85*4882a593Smuzhiyun return FALSE;
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun return TRUE;
88*4882a593Smuzhiyun }
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun static void
device_added(struct udev_device * udev_device)91*4882a593Smuzhiyun device_added(struct udev_device *udev_device)
92*4882a593Smuzhiyun {
93*4882a593Smuzhiyun const char *path, *name = NULL;
94*4882a593Smuzhiyun char *config_info = NULL;
95*4882a593Smuzhiyun const char *syspath;
96*4882a593Smuzhiyun const char *tags_prop;
97*4882a593Smuzhiyun const char *key, *value, *tmp;
98*4882a593Smuzhiyun InputOption *input_options;
99*4882a593Smuzhiyun InputAttributes attrs = { };
100*4882a593Smuzhiyun DeviceIntPtr dev = NULL;
101*4882a593Smuzhiyun struct udev_list_entry *set, *entry;
102*4882a593Smuzhiyun struct udev_device *parent;
103*4882a593Smuzhiyun int rc;
104*4882a593Smuzhiyun dev_t devnum;
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun path = udev_device_get_devnode(udev_device);
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun syspath = udev_device_get_syspath(udev_device);
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun if (!path || !syspath)
111*4882a593Smuzhiyun return;
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun if (!check_seat(udev_device))
114*4882a593Smuzhiyun return;
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun devnum = udev_device_get_devnum(udev_device);
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun #ifdef CONFIG_UDEV_KMS
119*4882a593Smuzhiyun if (!strcmp(udev_device_get_subsystem(udev_device), "drm")) {
120*4882a593Smuzhiyun const char *sysname = udev_device_get_sysname(udev_device);
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun if (strncmp(sysname, "card", 4) != 0)
123*4882a593Smuzhiyun return;
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun /* Check for devices already added through xf86platformProbe() */
126*4882a593Smuzhiyun if (xf86_find_platform_device_by_devnum(major(devnum), minor(devnum)))
127*4882a593Smuzhiyun return;
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun LogMessage(X_INFO, "config/udev: Adding drm device (%s)\n", path);
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun config_udev_odev_setup_attribs(path, syspath, major(devnum),
132*4882a593Smuzhiyun minor(devnum), NewGPUDeviceRequest);
133*4882a593Smuzhiyun return;
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun #endif
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun value = udev_device_get_property_value(udev_device, "ID_INPUT");
138*4882a593Smuzhiyun if (!value || !strcmp(value, "0")) {
139*4882a593Smuzhiyun LogMessageVerb(X_INFO, 10,
140*4882a593Smuzhiyun "config/udev: ignoring device %s without "
141*4882a593Smuzhiyun "property ID_INPUT set\n", path);
142*4882a593Smuzhiyun return;
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun input_options = input_option_new(NULL, "_source", "server/udev");
146*4882a593Smuzhiyun if (!input_options)
147*4882a593Smuzhiyun return;
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun parent = udev_device_get_parent(udev_device);
150*4882a593Smuzhiyun if (parent) {
151*4882a593Smuzhiyun const char *ppath = udev_device_get_devnode(parent);
152*4882a593Smuzhiyun const char *product = udev_device_get_property_value(parent, "PRODUCT");
153*4882a593Smuzhiyun const char *pnp_id = udev_device_get_sysattr_value(parent, "id");
154*4882a593Smuzhiyun unsigned int usb_vendor, usb_model;
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun name = udev_device_get_sysattr_value(parent, "name");
157*4882a593Smuzhiyun LOG_SYSATTR(ppath, "name", name);
158*4882a593Smuzhiyun if (!name) {
159*4882a593Smuzhiyun name = udev_device_get_property_value(parent, "NAME");
160*4882a593Smuzhiyun LOG_PROPERTY(ppath, "NAME", name);
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun /* construct USB ID in lowercase hex - "0000:ffff" */
164*4882a593Smuzhiyun if (product &&
165*4882a593Smuzhiyun sscanf(product, "%*x/%4x/%4x/%*x", &usb_vendor, &usb_model) == 2) {
166*4882a593Smuzhiyun char *usb_id;
167*4882a593Smuzhiyun if (asprintf(&usb_id, "%04x:%04x", usb_vendor, usb_model)
168*4882a593Smuzhiyun == -1)
169*4882a593Smuzhiyun usb_id = NULL;
170*4882a593Smuzhiyun else
171*4882a593Smuzhiyun LOG_PROPERTY(ppath, "PRODUCT", product);
172*4882a593Smuzhiyun attrs.usb_id = usb_id;
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun while (!pnp_id && (parent = udev_device_get_parent(parent))) {
176*4882a593Smuzhiyun pnp_id = udev_device_get_sysattr_value(parent, "id");
177*4882a593Smuzhiyun if (!pnp_id)
178*4882a593Smuzhiyun continue;
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun attrs.pnp_id = strdup(pnp_id);
181*4882a593Smuzhiyun ppath = udev_device_get_devnode(parent);
182*4882a593Smuzhiyun LOG_SYSATTR(ppath, "id", pnp_id);
183*4882a593Smuzhiyun }
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun if (!name)
187*4882a593Smuzhiyun name = "(unnamed)";
188*4882a593Smuzhiyun else
189*4882a593Smuzhiyun attrs.product = strdup(name);
190*4882a593Smuzhiyun input_options = input_option_new(input_options, "name", name);
191*4882a593Smuzhiyun input_options = input_option_new(input_options, "path", path);
192*4882a593Smuzhiyun input_options = input_option_new(input_options, "device", path);
193*4882a593Smuzhiyun input_options = input_option_new(input_options, "major", itoa(major(devnum)));
194*4882a593Smuzhiyun input_options = input_option_new(input_options, "minor", itoa(minor(devnum)));
195*4882a593Smuzhiyun if (path)
196*4882a593Smuzhiyun attrs.device = strdup(path);
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun tags_prop = udev_device_get_property_value(udev_device, "ID_INPUT.tags");
199*4882a593Smuzhiyun LOG_PROPERTY(path, "ID_INPUT.tags", tags_prop);
200*4882a593Smuzhiyun attrs.tags = xstrtokenize(tags_prop, ",");
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun if (asprintf(&config_info, "udev:%s", syspath) == -1) {
203*4882a593Smuzhiyun config_info = NULL;
204*4882a593Smuzhiyun goto unwind;
205*4882a593Smuzhiyun }
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun if (device_is_duplicate(config_info)) {
208*4882a593Smuzhiyun LogMessage(X_WARNING, "config/udev: device %s already added. "
209*4882a593Smuzhiyun "Ignoring.\n", name);
210*4882a593Smuzhiyun goto unwind;
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun set = udev_device_get_properties_list_entry(udev_device);
214*4882a593Smuzhiyun udev_list_entry_foreach(entry, set) {
215*4882a593Smuzhiyun key = udev_list_entry_get_name(entry);
216*4882a593Smuzhiyun if (!key)
217*4882a593Smuzhiyun continue;
218*4882a593Smuzhiyun value = udev_list_entry_get_value(entry);
219*4882a593Smuzhiyun if (!strncasecmp(key, UDEV_XKB_PROP_KEY, sizeof(UDEV_XKB_PROP_KEY) - 1)) {
220*4882a593Smuzhiyun LOG_PROPERTY(path, key, value);
221*4882a593Smuzhiyun tmp = key + sizeof(UDEV_XKB_PROP_KEY) - 1;
222*4882a593Smuzhiyun if (!strcasecmp(tmp, "rules"))
223*4882a593Smuzhiyun input_options =
224*4882a593Smuzhiyun input_option_new(input_options, "xkb_rules", value);
225*4882a593Smuzhiyun else if (!strcasecmp(tmp, "layout"))
226*4882a593Smuzhiyun input_options =
227*4882a593Smuzhiyun input_option_new(input_options, "xkb_layout", value);
228*4882a593Smuzhiyun else if (!strcasecmp(tmp, "variant"))
229*4882a593Smuzhiyun input_options =
230*4882a593Smuzhiyun input_option_new(input_options, "xkb_variant", value);
231*4882a593Smuzhiyun else if (!strcasecmp(tmp, "model"))
232*4882a593Smuzhiyun input_options =
233*4882a593Smuzhiyun input_option_new(input_options, "xkb_model", value);
234*4882a593Smuzhiyun else if (!strcasecmp(tmp, "options"))
235*4882a593Smuzhiyun input_options =
236*4882a593Smuzhiyun input_option_new(input_options, "xkb_options", value);
237*4882a593Smuzhiyun }
238*4882a593Smuzhiyun else if (!strcmp(key, "ID_VENDOR")) {
239*4882a593Smuzhiyun LOG_PROPERTY(path, key, value);
240*4882a593Smuzhiyun attrs.vendor = strdup(value);
241*4882a593Smuzhiyun } else if (!strncmp(key, "ID_INPUT_", 9)) {
242*4882a593Smuzhiyun const struct pfmap {
243*4882a593Smuzhiyun const char *property;
244*4882a593Smuzhiyun unsigned int flag;
245*4882a593Smuzhiyun } map[] = {
246*4882a593Smuzhiyun { "ID_INPUT_KEY", ATTR_KEY },
247*4882a593Smuzhiyun { "ID_INPUT_KEYBOARD", ATTR_KEYBOARD },
248*4882a593Smuzhiyun { "ID_INPUT_MOUSE", ATTR_POINTER },
249*4882a593Smuzhiyun { "ID_INPUT_JOYSTICK", ATTR_JOYSTICK },
250*4882a593Smuzhiyun { "ID_INPUT_TABLET", ATTR_TABLET },
251*4882a593Smuzhiyun { "ID_INPUT_TABLET_PAD", ATTR_TABLET_PAD },
252*4882a593Smuzhiyun { "ID_INPUT_TOUCHPAD", ATTR_TOUCHPAD },
253*4882a593Smuzhiyun { "ID_INPUT_TOUCHSCREEN", ATTR_TOUCHSCREEN },
254*4882a593Smuzhiyun { NULL, 0 },
255*4882a593Smuzhiyun };
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun /* Anything but the literal string "0" is considered a
258*4882a593Smuzhiyun * boolean true. The empty string isn't a thing with udev
259*4882a593Smuzhiyun * properties anyway */
260*4882a593Smuzhiyun if (value && strcmp(value, "0")) {
261*4882a593Smuzhiyun const struct pfmap *m = map;
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun while (m->property != NULL) {
264*4882a593Smuzhiyun if (!strcmp(m->property, key)) {
265*4882a593Smuzhiyun LOG_PROPERTY(path, key, value);
266*4882a593Smuzhiyun attrs.flags |= m->flag;
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun m++;
269*4882a593Smuzhiyun }
270*4882a593Smuzhiyun }
271*4882a593Smuzhiyun }
272*4882a593Smuzhiyun }
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun input_options = input_option_new(input_options, "config_info", config_info);
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun /* Default setting needed for non-seat0 seats */
277*4882a593Smuzhiyun if (ServerIsNotSeat0())
278*4882a593Smuzhiyun input_options = input_option_new(input_options, "GrabDevice", "on");
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun LogMessage(X_INFO, "config/udev: Adding input device %s (%s)\n",
281*4882a593Smuzhiyun name, path);
282*4882a593Smuzhiyun rc = NewInputDeviceRequest(input_options, &attrs, &dev);
283*4882a593Smuzhiyun if (rc != Success)
284*4882a593Smuzhiyun goto unwind;
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun unwind:
287*4882a593Smuzhiyun free(config_info);
288*4882a593Smuzhiyun input_option_free_list(&input_options);
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun free(attrs.usb_id);
291*4882a593Smuzhiyun free(attrs.pnp_id);
292*4882a593Smuzhiyun free(attrs.product);
293*4882a593Smuzhiyun free(attrs.device);
294*4882a593Smuzhiyun free(attrs.vendor);
295*4882a593Smuzhiyun if (attrs.tags) {
296*4882a593Smuzhiyun char **tag = attrs.tags;
297*4882a593Smuzhiyun
298*4882a593Smuzhiyun while (*tag) {
299*4882a593Smuzhiyun free(*tag);
300*4882a593Smuzhiyun tag++;
301*4882a593Smuzhiyun }
302*4882a593Smuzhiyun free(attrs.tags);
303*4882a593Smuzhiyun }
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun return;
306*4882a593Smuzhiyun }
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun static void
device_removed(struct udev_device * device)309*4882a593Smuzhiyun device_removed(struct udev_device *device)
310*4882a593Smuzhiyun {
311*4882a593Smuzhiyun char *value;
312*4882a593Smuzhiyun const char *syspath = udev_device_get_syspath(device);
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun #ifdef CONFIG_UDEV_KMS
315*4882a593Smuzhiyun if (!strcmp(udev_device_get_subsystem(device), "drm")) {
316*4882a593Smuzhiyun const char *sysname = udev_device_get_sysname(device);
317*4882a593Smuzhiyun const char *path = udev_device_get_devnode(device);
318*4882a593Smuzhiyun dev_t devnum = udev_device_get_devnum(device);
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun if ((strncmp(sysname,"card", 4) != 0) || (path == NULL))
321*4882a593Smuzhiyun return;
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun LogMessage(X_INFO, "config/udev: removing GPU device %s %s\n",
324*4882a593Smuzhiyun syspath, path);
325*4882a593Smuzhiyun config_udev_odev_setup_attribs(path, syspath, major(devnum),
326*4882a593Smuzhiyun minor(devnum), DeleteGPUDeviceRequest);
327*4882a593Smuzhiyun /* Retry vtenter after a drm node removal */
328*4882a593Smuzhiyun systemd_logind_vtenter();
329*4882a593Smuzhiyun return;
330*4882a593Smuzhiyun }
331*4882a593Smuzhiyun #endif
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun if (asprintf(&value, "udev:%s", syspath) == -1)
334*4882a593Smuzhiyun return;
335*4882a593Smuzhiyun
336*4882a593Smuzhiyun remove_devices("udev", value);
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun free(value);
339*4882a593Smuzhiyun }
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun static void
socket_handler(int fd,int ready,void * data)342*4882a593Smuzhiyun socket_handler(int fd, int ready, void *data)
343*4882a593Smuzhiyun {
344*4882a593Smuzhiyun struct udev_device *udev_device;
345*4882a593Smuzhiyun const char *action;
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun input_lock();
348*4882a593Smuzhiyun udev_device = udev_monitor_receive_device(udev_monitor);
349*4882a593Smuzhiyun if (!udev_device) {
350*4882a593Smuzhiyun input_unlock();
351*4882a593Smuzhiyun return;
352*4882a593Smuzhiyun }
353*4882a593Smuzhiyun action = udev_device_get_action(udev_device);
354*4882a593Smuzhiyun if (action) {
355*4882a593Smuzhiyun if (!strcmp(action, "add")) {
356*4882a593Smuzhiyun device_removed(udev_device);
357*4882a593Smuzhiyun device_added(udev_device);
358*4882a593Smuzhiyun } else if (!strcmp(action, "change")) {
359*4882a593Smuzhiyun /* ignore change for the drm devices */
360*4882a593Smuzhiyun if (strcmp(udev_device_get_subsystem(udev_device), "drm")) {
361*4882a593Smuzhiyun device_removed(udev_device);
362*4882a593Smuzhiyun device_added(udev_device);
363*4882a593Smuzhiyun }
364*4882a593Smuzhiyun }
365*4882a593Smuzhiyun else if (!strcmp(action, "remove"))
366*4882a593Smuzhiyun device_removed(udev_device);
367*4882a593Smuzhiyun }
368*4882a593Smuzhiyun udev_device_unref(udev_device);
369*4882a593Smuzhiyun input_unlock();
370*4882a593Smuzhiyun }
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun int
config_udev_pre_init(void)373*4882a593Smuzhiyun config_udev_pre_init(void)
374*4882a593Smuzhiyun {
375*4882a593Smuzhiyun struct udev *udev;
376*4882a593Smuzhiyun
377*4882a593Smuzhiyun udev = udev_new();
378*4882a593Smuzhiyun if (!udev)
379*4882a593Smuzhiyun return 0;
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
382*4882a593Smuzhiyun if (!udev_monitor)
383*4882a593Smuzhiyun return 0;
384*4882a593Smuzhiyun
385*4882a593Smuzhiyun udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "input",
386*4882a593Smuzhiyun NULL);
387*4882a593Smuzhiyun /* For Wacom serial devices */
388*4882a593Smuzhiyun udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "tty", NULL);
389*4882a593Smuzhiyun #ifdef CONFIG_UDEV_KMS
390*4882a593Smuzhiyun /* For output GPU devices */
391*4882a593Smuzhiyun udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "drm", NULL);
392*4882a593Smuzhiyun #endif
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun #ifdef HAVE_UDEV_MONITOR_FILTER_ADD_MATCH_TAG
395*4882a593Smuzhiyun if (ServerIsNotSeat0())
396*4882a593Smuzhiyun udev_monitor_filter_add_match_tag(udev_monitor, SeatId);
397*4882a593Smuzhiyun #endif
398*4882a593Smuzhiyun if (udev_monitor_enable_receiving(udev_monitor)) {
399*4882a593Smuzhiyun ErrorF("config/udev: failed to bind the udev monitor\n");
400*4882a593Smuzhiyun return 0;
401*4882a593Smuzhiyun }
402*4882a593Smuzhiyun return 1;
403*4882a593Smuzhiyun }
404*4882a593Smuzhiyun
405*4882a593Smuzhiyun int
config_udev_init(void)406*4882a593Smuzhiyun config_udev_init(void)
407*4882a593Smuzhiyun {
408*4882a593Smuzhiyun struct udev *udev;
409*4882a593Smuzhiyun struct udev_enumerate *enumerate;
410*4882a593Smuzhiyun struct udev_list_entry *devices, *device;
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun udev = udev_monitor_get_udev(udev_monitor);
413*4882a593Smuzhiyun enumerate = udev_enumerate_new(udev);
414*4882a593Smuzhiyun if (!enumerate)
415*4882a593Smuzhiyun return 0;
416*4882a593Smuzhiyun
417*4882a593Smuzhiyun udev_enumerate_add_match_subsystem(enumerate, "input");
418*4882a593Smuzhiyun udev_enumerate_add_match_subsystem(enumerate, "tty");
419*4882a593Smuzhiyun #ifdef CONFIG_UDEV_KMS
420*4882a593Smuzhiyun udev_enumerate_add_match_subsystem(enumerate, "drm");
421*4882a593Smuzhiyun #endif
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun #ifdef HAVE_UDEV_ENUMERATE_ADD_MATCH_TAG
424*4882a593Smuzhiyun if (ServerIsNotSeat0())
425*4882a593Smuzhiyun udev_enumerate_add_match_tag(enumerate, SeatId);
426*4882a593Smuzhiyun #endif
427*4882a593Smuzhiyun
428*4882a593Smuzhiyun udev_enumerate_scan_devices(enumerate);
429*4882a593Smuzhiyun devices = udev_enumerate_get_list_entry(enumerate);
430*4882a593Smuzhiyun udev_list_entry_foreach(device, devices) {
431*4882a593Smuzhiyun const char *syspath = udev_list_entry_get_name(device);
432*4882a593Smuzhiyun struct udev_device *udev_device =
433*4882a593Smuzhiyun udev_device_new_from_syspath(udev, syspath);
434*4882a593Smuzhiyun
435*4882a593Smuzhiyun /* Device might be gone by the time we try to open it */
436*4882a593Smuzhiyun if (!udev_device)
437*4882a593Smuzhiyun continue;
438*4882a593Smuzhiyun
439*4882a593Smuzhiyun device_added(udev_device);
440*4882a593Smuzhiyun udev_device_unref(udev_device);
441*4882a593Smuzhiyun }
442*4882a593Smuzhiyun udev_enumerate_unref(enumerate);
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun SetNotifyFd(udev_monitor_get_fd(udev_monitor), socket_handler, X_NOTIFY_READ, NULL);
445*4882a593Smuzhiyun
446*4882a593Smuzhiyun return 1;
447*4882a593Smuzhiyun }
448*4882a593Smuzhiyun
449*4882a593Smuzhiyun void
config_udev_fini(void)450*4882a593Smuzhiyun config_udev_fini(void)
451*4882a593Smuzhiyun {
452*4882a593Smuzhiyun struct udev *udev;
453*4882a593Smuzhiyun
454*4882a593Smuzhiyun if (!udev_monitor)
455*4882a593Smuzhiyun return;
456*4882a593Smuzhiyun
457*4882a593Smuzhiyun udev = udev_monitor_get_udev(udev_monitor);
458*4882a593Smuzhiyun
459*4882a593Smuzhiyun RemoveNotifyFd(udev_monitor_get_fd(udev_monitor));
460*4882a593Smuzhiyun udev_monitor_unref(udev_monitor);
461*4882a593Smuzhiyun udev_monitor = NULL;
462*4882a593Smuzhiyun udev_unref(udev);
463*4882a593Smuzhiyun }
464*4882a593Smuzhiyun
465*4882a593Smuzhiyun #ifdef CONFIG_UDEV_KMS
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun static void
config_udev_odev_setup_attribs(const char * path,const char * syspath,int major,int minor,config_odev_probe_proc_ptr probe_callback)468*4882a593Smuzhiyun config_udev_odev_setup_attribs(const char *path, const char *syspath,
469*4882a593Smuzhiyun int major, int minor,
470*4882a593Smuzhiyun config_odev_probe_proc_ptr probe_callback)
471*4882a593Smuzhiyun {
472*4882a593Smuzhiyun struct OdevAttributes *attribs = config_odev_allocate_attributes();
473*4882a593Smuzhiyun
474*4882a593Smuzhiyun attribs->path = XNFstrdup(path);
475*4882a593Smuzhiyun attribs->syspath = XNFstrdup(syspath);
476*4882a593Smuzhiyun attribs->major = major;
477*4882a593Smuzhiyun attribs->minor = minor;
478*4882a593Smuzhiyun
479*4882a593Smuzhiyun /* ownership of attribs is passed to probe layer */
480*4882a593Smuzhiyun probe_callback(attribs);
481*4882a593Smuzhiyun }
482*4882a593Smuzhiyun
483*4882a593Smuzhiyun void
config_udev_odev_probe(config_odev_probe_proc_ptr probe_callback)484*4882a593Smuzhiyun config_udev_odev_probe(config_odev_probe_proc_ptr probe_callback)
485*4882a593Smuzhiyun {
486*4882a593Smuzhiyun struct udev *udev;
487*4882a593Smuzhiyun struct udev_enumerate *enumerate;
488*4882a593Smuzhiyun struct udev_list_entry *devices, *device;
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun udev = udev_monitor_get_udev(udev_monitor);
491*4882a593Smuzhiyun enumerate = udev_enumerate_new(udev);
492*4882a593Smuzhiyun if (!enumerate)
493*4882a593Smuzhiyun return;
494*4882a593Smuzhiyun
495*4882a593Smuzhiyun udev_enumerate_add_match_subsystem(enumerate, "drm");
496*4882a593Smuzhiyun udev_enumerate_add_match_sysname(enumerate, "card[0-9]*");
497*4882a593Smuzhiyun #ifdef HAVE_UDEV_ENUMERATE_ADD_MATCH_TAG
498*4882a593Smuzhiyun if (ServerIsNotSeat0())
499*4882a593Smuzhiyun udev_enumerate_add_match_tag(enumerate, SeatId);
500*4882a593Smuzhiyun #endif
501*4882a593Smuzhiyun udev_enumerate_scan_devices(enumerate);
502*4882a593Smuzhiyun devices = udev_enumerate_get_list_entry(enumerate);
503*4882a593Smuzhiyun udev_list_entry_foreach(device, devices) {
504*4882a593Smuzhiyun const char *syspath = udev_list_entry_get_name(device);
505*4882a593Smuzhiyun struct udev_device *udev_device = udev_device_new_from_syspath(udev, syspath);
506*4882a593Smuzhiyun const char *path = udev_device_get_devnode(udev_device);
507*4882a593Smuzhiyun const char *sysname = udev_device_get_sysname(udev_device);
508*4882a593Smuzhiyun dev_t devnum = udev_device_get_devnum(udev_device);
509*4882a593Smuzhiyun
510*4882a593Smuzhiyun if (!path || !syspath)
511*4882a593Smuzhiyun goto no_probe;
512*4882a593Smuzhiyun else if (strcmp(udev_device_get_subsystem(udev_device), "drm") != 0)
513*4882a593Smuzhiyun goto no_probe;
514*4882a593Smuzhiyun else if (strncmp(sysname, "card", 4) != 0)
515*4882a593Smuzhiyun goto no_probe;
516*4882a593Smuzhiyun else if (!check_seat(udev_device))
517*4882a593Smuzhiyun goto no_probe;
518*4882a593Smuzhiyun
519*4882a593Smuzhiyun config_udev_odev_setup_attribs(path, syspath, major(devnum),
520*4882a593Smuzhiyun minor(devnum), probe_callback);
521*4882a593Smuzhiyun no_probe:
522*4882a593Smuzhiyun udev_device_unref(udev_device);
523*4882a593Smuzhiyun }
524*4882a593Smuzhiyun udev_enumerate_unref(enumerate);
525*4882a593Smuzhiyun return;
526*4882a593Smuzhiyun }
527*4882a593Smuzhiyun #endif
528*4882a593Smuzhiyun
529