xref: /OK3568_Linux_fs/external/xserver/config/udev.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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