Fix documentation for libinput_log_set_handler
[platform/upstream/libinput.git] / src / path.c
1 /*
2  * Copyright © 2013 Red Hat, Inc.
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and
5  * its documentation for any purpose is hereby granted without fee, provided
6  * that the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation, and that the name of the copyright holders not be used in
9  * advertising or publicity pertaining to distribution of the software
10  * without specific, written prior permission.  The copyright holders make
11  * no representations about the suitability of this software for any
12  * purpose.  It is provided "as is" without express or implied warranty.
13  *
14  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
15  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
16  * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
17  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
18  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
19  * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21  */
22
23 #include "config.h"
24
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <string.h>
28 #include <libudev.h>
29
30 #include "path.h"
31 #include "evdev.h"
32
33 static const char default_seat[] = "seat0";
34 static const char default_seat_name[] = "default";
35
36 int path_input_process_event(struct libinput_event);
37 static void path_seat_destroy(struct libinput_seat *seat);
38
39 static void
40 path_disable_device(struct libinput *libinput,
41                     struct evdev_device *device)
42 {
43         struct libinput_seat *seat = device->base.seat;
44         struct evdev_device *dev, *next;
45
46         list_for_each_safe(dev, next,
47                            &seat->devices_list, base.link) {
48                 if (dev != device)
49                         continue;
50
51                 evdev_device_remove(device);
52                 break;
53         }
54 }
55
56 static void
57 path_input_disable(struct libinput *libinput)
58 {
59         struct path_input *input = (struct path_input*)libinput;
60         struct path_seat *seat, *tmp;
61         struct evdev_device *device, *next;
62
63         list_for_each_safe(seat, tmp, &input->base.seat_list, base.link) {
64                 libinput_seat_ref(&seat->base);
65                 list_for_each_safe(device, next,
66                                    &seat->base.devices_list, base.link)
67                         path_disable_device(libinput, device);
68                 libinput_seat_unref(&seat->base);
69         }
70 }
71
72 static void
73 path_seat_destroy(struct libinput_seat *seat)
74 {
75         struct path_seat *pseat = (struct path_seat*)seat;
76         free(pseat);
77 }
78
79 static struct path_seat*
80 path_seat_create(struct path_input *input,
81                  const char *seat_name,
82                  const char *seat_logical_name)
83 {
84         struct path_seat *seat;
85
86         seat = zalloc(sizeof(*seat));
87         if (!seat)
88                 return NULL;
89
90         libinput_seat_init(&seat->base, &input->base, seat_name,
91                            seat_logical_name, path_seat_destroy);
92
93         return seat;
94 }
95
96 static struct path_seat*
97 path_seat_get_named(struct path_input *input,
98                     const char *seat_name_physical,
99                     const char *seat_name_logical)
100 {
101         struct path_seat *seat;
102
103         list_for_each(seat, &input->base.seat_list, base.link) {
104                 if (strcmp(seat->base.physical_name, seat_name_physical) == 0 &&
105                     strcmp(seat->base.logical_name, seat_name_logical) == 0)
106                         return seat;
107         }
108
109         return NULL;
110 }
111
112 static int
113 path_get_udev_properties(const char *path,
114                          char **sysname,
115                          char **syspath,
116                          char **seat_name,
117                          char **seat_logical_name)
118 {
119         struct udev *udev = NULL;
120         struct udev_device *device = NULL;
121         struct stat st;
122         const char *seat;
123         int rc = -1;
124
125         udev = udev_new();
126         if (!udev)
127                 goto out;
128
129         if (stat(path, &st) < 0)
130                 goto out;
131
132         device = udev_device_new_from_devnum(udev, 'c', st.st_rdev);
133         if (!device)
134                 goto out;
135
136         *sysname = strdup(udev_device_get_sysname(device));
137         *syspath = strdup(udev_device_get_syspath(device));
138
139         seat = udev_device_get_property_value(device, "ID_SEAT");
140         *seat_name = strdup(seat ? seat : default_seat);
141
142         seat = udev_device_get_property_value(device, "WL_SEAT");
143         *seat_logical_name = strdup(seat ? seat : default_seat_name);
144
145         rc = 0;
146
147 out:
148         if (device)
149                 udev_device_unref(device);
150         if (udev)
151                 udev_unref(udev);
152         return rc;
153 }
154
155 static struct libinput_device *
156 path_device_enable(struct path_input *input, const char *devnode)
157 {
158         struct path_seat *seat;
159         struct evdev_device *device = NULL;
160         char *sysname = NULL, *syspath = NULL;
161         char *seat_name = NULL, *seat_logical_name = NULL;
162
163         if (path_get_udev_properties(devnode, &sysname, &syspath,
164                                      &seat_name, &seat_logical_name) == -1) {
165                 log_info(&input->base,
166                          "failed to obtain sysname for device '%s'.\n",
167                          devnode);
168                 return NULL;
169         }
170
171         seat = path_seat_get_named(input, seat_name, seat_logical_name);
172
173         if (seat) {
174                 libinput_seat_ref(&seat->base);
175         } else {
176                 seat = path_seat_create(input, seat_name, seat_logical_name);
177                 if (!seat) {
178                         log_info(&input->base,
179                                  "failed to create seat for device '%s'.\n",
180                                  devnode);
181                         goto out;
182                 }
183         }
184
185         device = evdev_device_create(&seat->base, devnode, sysname, syspath);
186         libinput_seat_unref(&seat->base);
187
188         if (device == EVDEV_UNHANDLED_DEVICE) {
189                 device = NULL;
190                 log_info(&input->base,
191                          "not using input device '%s'.\n",
192                          devnode);
193                 goto out;
194         } else if (device == NULL) {
195                 log_info(&input->base,
196                          "failed to create input device '%s'.\n",
197                          devnode);
198                 goto out;
199         }
200
201 out:
202         free(sysname);
203         free(syspath);
204         free(seat_name);
205         free(seat_logical_name);
206
207         return device ? &device->base : NULL;
208 }
209
210 static int
211 path_input_enable(struct libinput *libinput)
212 {
213         struct path_input *input = (struct path_input*)libinput;
214         struct path_device *dev;
215
216         list_for_each(dev, &input->path_list, link) {
217                 if (path_device_enable(input, dev->path) == NULL) {
218                         path_input_disable(libinput);
219                         return -1;
220                 }
221         }
222
223         return 0;
224 }
225
226 static void
227 path_input_destroy(struct libinput *input)
228 {
229         struct path_input *path_input = (struct path_input*)input;
230         struct path_device *dev, *tmp;
231
232         list_for_each_safe(dev, tmp, &path_input->path_list, link) {
233                 free(dev->path);
234                 free(dev);
235         }
236
237 }
238
239 static const struct libinput_interface_backend interface_backend = {
240         .resume = path_input_enable,
241         .suspend = path_input_disable,
242         .destroy = path_input_destroy,
243 };
244
245 LIBINPUT_EXPORT struct libinput *
246 libinput_path_create_context(const struct libinput_interface *interface,
247                              void *user_data)
248 {
249         struct path_input *input;
250
251         if (!interface)
252                 return NULL;
253
254         input = zalloc(sizeof *input);
255         if (!input)
256                 return NULL;
257
258         if (libinput_init(&input->base, interface,
259                           &interface_backend, user_data) != 0) {
260                 free(input);
261                 return NULL;
262         }
263
264         list_init(&input->path_list);
265
266         return &input->base;
267 }
268
269 LIBINPUT_EXPORT struct libinput_device *
270 libinput_path_add_device(struct libinput *libinput,
271                          const char *path)
272 {
273         struct path_input *input = (struct path_input*)libinput;
274         struct path_device *dev;
275         struct libinput_device *device;
276
277         if (libinput->interface_backend != &interface_backend) {
278                 log_bug_client(libinput, "Mismatching backends.\n");
279                 return NULL;
280         }
281
282         dev = zalloc(sizeof *dev);
283         if (!dev)
284                 return NULL;
285
286         dev->path = strdup(path);
287         if (!dev->path) {
288                 free(dev);
289                 return NULL;
290         }
291
292         list_insert(&input->path_list, &dev->link);
293
294         device = path_device_enable(input, dev->path);
295
296         if (!device) {
297                 list_remove(&dev->link);
298                 free(dev->path);
299                 free(dev);
300         }
301
302         return device;
303 }
304
305 LIBINPUT_EXPORT void
306 libinput_path_remove_device(struct libinput_device *device)
307 {
308         struct libinput *libinput = device->seat->libinput;
309         struct path_input *input = (struct path_input*)libinput;
310         struct libinput_seat *seat;
311         struct evdev_device *evdev = (struct evdev_device*)device;
312         struct path_device *dev;
313
314         if (libinput->interface_backend != &interface_backend) {
315                 log_bug_client(libinput, "Mismatching backends.\n");
316                 return;
317         }
318
319         list_for_each(dev, &input->path_list, link) {
320                 if (strcmp(evdev->devnode, dev->path) == 0) {
321                         list_remove(&dev->link);
322                         free(dev->path);
323                         free(dev);
324                         break;
325                 }
326         }
327
328         seat = device->seat;
329         libinput_seat_ref(seat);
330         path_disable_device(libinput, evdev);
331         libinput_seat_unref(seat);
332 }