Add missing boilerplate
[platform/adaptation/libtdm-drm.git] / src / libtdm-drm / tdm_drm.c
1 /**************************************************************************
2
3 libtdm_drm
4
5 Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
6
7 Contact: SooChan Lim <sc1.lim@samsung.com>
8
9 Permission is hereby granted, free of charge, to any person obtaining a
10 copy of this software and associated documentation files (the
11 "Software"), to deal in the Software without restriction, including
12 without limitation the rights to use, copy, modify, merge, publish,
13 distribute, sub license, and/or sell copies of the Software, and to
14 permit persons to whom the Software is furnished to do so, subject to
15 the following conditions:
16
17 The above copyright notice and this permission notice (including the
18 next paragraph) shall be included in all copies or substantial portions
19 of the Software.
20
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
24 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
25 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
26 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
27 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28
29 **************************************************************************/
30
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34
35 #if HAVE_UDEV
36 #include <libudev.h>
37 #endif
38
39 #include "tdm_drm.h"
40 #include <tdm_helper.h>
41 #include <tbm_drm_helper.h>
42
43 #define ENABLE_PP
44
45 #define TDM_DRM_NAME "vigs"
46
47 #define TDM_HWC 1
48
49 static tdm_drm_data *drm_data;
50
51 #ifdef HAVE_UDEV
52 static struct udev_device *
53 _tdm_find_primary_gpu(void)
54 {
55         struct udev *udev;
56         struct udev_enumerate *e;
57         struct udev_list_entry *entry;
58         const char *path, *id;
59         struct udev_device *device, *drm_device, *pci;
60
61         udev = udev_new();
62         if (!udev) {
63                 TDM_ERR("fail to initialize udev context\n");
64                 return NULL;
65         }
66
67         e = udev_enumerate_new(udev);
68         udev_enumerate_add_match_subsystem(e, "drm");
69         udev_enumerate_add_match_sysname(e, "card[0-9]*");
70
71         udev_enumerate_scan_devices(e);
72         drm_device = NULL;
73         udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
74                 path = udev_list_entry_get_name(entry);
75                 device = udev_device_new_from_syspath(udev, path);
76                 if (!device)
77                         continue;
78
79                 pci = udev_device_get_parent_with_subsystem_devtype(device,
80                                                 "pci", NULL);
81                 if (pci) {
82                         id = udev_device_get_sysattr_value(pci, "boot_vga");
83                         if (id && !strcmp(id, "1")) {
84                                 if (drm_device)
85                                         udev_device_unref(drm_device);
86                                 drm_device = device;
87                                 break;
88                         }
89                 }
90
91                 if (!drm_device)
92                         drm_device = device;
93                 else
94                         udev_device_unref(device);
95         }
96
97         udev_enumerate_unref(e);
98         return drm_device;
99 }
100
101 static tdm_error
102 _tdm_drm_udev_fd_handler(int fd, tdm_event_loop_mask mask, void *user_data)
103 {
104         tdm_drm_data *edata = (tdm_drm_data*)user_data;
105         struct udev_device *dev;
106         const char *hotplug;
107         struct stat s;
108         dev_t udev_devnum;
109         int ret;
110
111         dev = udev_monitor_receive_device(edata->uevent_monitor);
112         if (!dev) {
113                 TDM_ERR("couldn't receive device");
114                 return TDM_ERROR_OPERATION_FAILED;
115         }
116
117         udev_devnum = udev_device_get_devnum(dev);
118
119         ret = fstat(edata->drm_fd, &s);
120         if (ret == -1) {
121                 TDM_ERR("fstat failed");
122                 udev_device_unref(dev);
123                 return TDM_ERROR_OPERATION_FAILED;
124         }
125
126         hotplug = udev_device_get_property_value(dev, "HOTPLUG");
127
128         if (memcmp(&s.st_rdev, &udev_devnum, sizeof(dev_t)) == 0 &&
129                         hotplug && atoi(hotplug) == 1) {
130                 TDM_INFO("HotPlug");
131                 tdm_drm_display_update_output_status(edata);
132         }
133
134         udev_device_unref(dev);
135
136         return TDM_ERROR_NONE;
137 }
138
139 static void
140 _tdm_drm_udev_init(tdm_drm_data *edata)
141 {
142         struct udev *u = NULL;
143         struct udev_monitor *mon = NULL;
144
145         u = udev_new();
146         if (!u) {
147                 TDM_ERR("couldn't create udev");
148                 goto failed;
149         }
150
151         mon = udev_monitor_new_from_netlink(u, "udev");
152         if (!mon) {
153                 TDM_ERR("couldn't create udev monitor");
154                 goto failed;
155         }
156
157         if (udev_monitor_filter_add_match_subsystem_devtype(mon, "drm", "drm_minor") > 0 ||
158                 udev_monitor_enable_receiving(mon) < 0) {
159                 TDM_ERR("add match subsystem failed");
160                 goto failed;
161         }
162
163         edata->uevent_source =
164                 tdm_event_loop_add_fd_handler(edata->dpy, udev_monitor_get_fd(mon),
165                                                                           TDM_EVENT_LOOP_READABLE,
166                                                                           _tdm_drm_udev_fd_handler,
167                                                                           edata, NULL);
168         if (!edata->uevent_source) {
169                 TDM_ERR("couldn't create udev event source");
170                 goto failed;
171         }
172
173         edata->uevent_monitor = mon;
174
175         TDM_INFO("hotplug monitor created");
176
177         return;
178 failed:
179         if (mon)
180                 udev_monitor_unref(mon);
181         if (u)
182                 udev_unref(u);
183 }
184
185 static void
186 _tdm_drm_udev_deinit(tdm_drm_data *edata)
187 {
188         if (edata->uevent_source) {
189                 tdm_event_loop_source_remove(edata->uevent_source);
190                 edata->uevent_source = NULL;
191         }
192
193         if (edata->uevent_monitor) {
194                 struct udev *u = udev_monitor_get_udev(edata->uevent_monitor);
195                 udev_monitor_unref(edata->uevent_monitor);
196                 udev_unref(u);
197                 edata->uevent_monitor = NULL;
198                 TDM_INFO("hotplug monitor destroyed");
199         }
200 }
201 #endif
202
203 static int
204 _tdm_drm_open_drm(void)
205 {
206         int fd = -1;
207
208         fd = drmOpen(TDM_DRM_NAME, NULL);
209         if (fd < 0)
210                 TDM_WRN("Cannot open '%s' drm", TDM_DRM_NAME);
211
212 #ifdef HAVE_UDEV
213         if (fd < 0) {
214                 struct udev_device *drm_device = NULL;
215                 const char *filename;
216                 TDM_WRN("Cannot open drm device.. search by udev");
217
218                 drm_device = _tdm_find_primary_gpu();
219                 if (drm_device == NULL) {
220                         TDM_ERR("fail to find drm device\n");
221                         goto close_l;
222                 }
223
224                 filename = udev_device_get_devnode(drm_device);
225
226                 fd = open(filename, O_RDWR | O_CLOEXEC);
227                 if (fd < 0)
228                         TDM_ERR("Cannot open drm device(%s)\n", filename);
229
230                 TDM_DBG("open drm device (name:%s, fd:%d)", filename, fd);
231
232                 udev_device_unref(drm_device);
233         }
234 close_l:
235 #endif
236         return fd;
237 }
238
239 void
240 tdm_drm_deinit(tdm_backend_data *bdata)
241 {
242         if (drm_data != bdata)
243                 return;
244
245         TDM_INFO("deinit");
246
247 #ifdef HAVE_UDEV
248         _tdm_drm_udev_deinit(drm_data);
249 #endif
250
251         tdm_drm_display_destroy_output_list(drm_data);
252
253         if (drm_data->plane_res)
254                 drmModeFreePlaneResources(drm_data->plane_res);
255         if (drm_data->mode_res)
256                 drmModeFreeResources(drm_data->mode_res);
257         if (drm_data->drm_fd >= 0)
258                 close(drm_data->drm_fd);
259
260         free(drm_data);
261         drm_data = NULL;
262 }
263
264 tdm_backend_data *
265 tdm_drm_init(tdm_display *dpy, tdm_error *error)
266 {
267         tdm_func_display drm_func_display;
268         tdm_func_output drm_func_output;
269         tdm_func_layer drm_func_layer;
270         tdm_func_hwc drm_func_hwc;
271         tdm_func_hwc_window drm_func_hwc_window;
272 #ifdef ENABLE_PP
273         tdm_func_pp drm_func_pp;
274 #endif
275         tdm_error ret;
276
277         if (!dpy) {
278                 TDM_ERR("display is null");
279                 if (error)
280                         *error = TDM_ERROR_INVALID_PARAMETER;
281                 return NULL;
282         }
283
284         if (drm_data) {
285                 TDM_ERR("failed: init twice");
286                 if (error)
287                         *error = TDM_ERROR_BAD_REQUEST;
288                 return NULL;
289         }
290
291         drm_data = calloc(1, sizeof(tdm_drm_data));
292         if (!drm_data) {
293                 TDM_ERR("alloc failed");
294                 if (error)
295                         *error = TDM_ERROR_OUT_OF_MEMORY;
296                 return NULL;
297         }
298
299 #if TDM_HWC
300         /* enable the tdm_hwc */
301         drm_data->hwc_mode = 1;
302 #endif
303
304         LIST_INITHEAD(&drm_data->output_list);
305         LIST_INITHEAD(&drm_data->buffer_list);
306
307         memset(&drm_func_display, 0, sizeof(drm_func_display));
308         drm_func_display.display_get_capability = drm_display_get_capability;
309         drm_func_display.display_get_pp_capability = drm_display_get_pp_capability;
310         drm_func_display.display_get_outputs = drm_display_get_outputs;
311         drm_func_display.display_get_fd = drm_display_get_fd;
312         drm_func_display.display_handle_events = drm_display_handle_events;
313         drm_func_display.display_create_pp = drm_display_create_pp;
314
315         memset(&drm_func_output, 0, sizeof(drm_func_output));
316         drm_func_output.output_get_capability = drm_output_get_capability;
317         drm_func_output.output_get_layers = drm_output_get_layers;
318         drm_func_output.output_set_property = drm_output_set_property;
319         drm_func_output.output_get_property = drm_output_get_property;
320         drm_func_output.output_wait_vblank = drm_output_wait_vblank;
321         drm_func_output.output_set_vblank_handler = drm_output_set_vblank_handler;
322         drm_func_output.output_commit = drm_output_commit;
323         drm_func_output.output_set_commit_handler = drm_output_set_commit_handler;
324         drm_func_output.output_set_dpms = drm_output_set_dpms;
325         drm_func_output.output_get_dpms = drm_output_get_dpms;
326         drm_func_output.output_set_mode = drm_output_set_mode;
327         drm_func_output.output_get_mode = drm_output_get_mode;
328 #ifdef HAVE_UDEV
329         drm_func_output.output_set_status_handler = drm_output_set_status_handler;
330 #endif
331
332         if (drm_data->hwc_mode) {
333                 drm_func_output.output_get_hwc = drm_output_get_hwc;
334
335                 memset(&drm_func_hwc, 0, sizeof(drm_func_hwc));
336                 drm_func_hwc.hwc_create_window = drm_hwc_create_window;
337                 drm_func_hwc.hwc_get_video_supported_formats = drm_hwc_get_video_supported_formats;
338                 drm_func_hwc.hwc_get_video_available_properties = NULL;
339                 drm_func_hwc.hwc_get_capabilities = drm_hwc_get_capabilities;
340                 drm_func_hwc.hwc_get_available_properties = drm_hwc_get_available_properties;
341                 drm_func_hwc.hwc_get_client_target_buffer_queue = drm_hwc_get_client_target_buffer_queue;
342                 drm_func_hwc.hwc_set_client_target_buffer = drm_hwc_set_client_target_buffer;
343                 drm_func_hwc.hwc_validate = drm_hwc_validate;
344                 drm_func_hwc.hwc_get_changed_composition_types = drm_hwc_get_changed_composition_types;
345                 drm_func_hwc.hwc_accept_validation = drm_hwc_accept_validation;
346                 drm_func_hwc.hwc_commit = drm_hwc_commit;
347                 drm_func_hwc.hwc_set_commit_handler = drm_hwc_set_commit_handler;
348
349                 memset(&drm_func_hwc_window, 0, sizeof(drm_func_hwc_window));
350                 drm_func_hwc_window.hwc_window_destroy = drm_hwc_window_destroy;
351                 drm_func_hwc_window.hwc_window_acquire_buffer_queue = NULL; // no need
352                 drm_func_hwc_window.hwc_window_release_buffer_queue = NULL; // no need
353                 drm_func_hwc_window.hwc_window_set_composition_type = drm_hwc_window_set_composition_type;
354                 drm_func_hwc_window.hwc_window_set_buffer_damage = drm_hwc_window_set_buffer_damage;
355                 drm_func_hwc_window.hwc_window_set_info = drm_hwc_window_set_info;
356                 drm_func_hwc_window.hwc_window_set_buffer = drm_hwc_window_set_buffer;
357                 drm_func_hwc_window.hwc_window_set_property = drm_hwc_window_set_property;
358                 drm_func_hwc_window.hwc_window_get_property = drm_hwc_window_get_property;
359                 drm_func_hwc_window.hwc_window_get_constraints = drm_hwc_window_get_constraints;
360                 drm_func_hwc_window.hwc_window_set_name = drm_hwc_window_set_name;
361                 drm_func_hwc_window.hwc_window_set_cursor_image = drm_hwc_window_set_cursor_image;
362         }
363
364         memset(&drm_func_layer, 0, sizeof(drm_func_layer));
365         drm_func_layer.layer_get_capability = drm_layer_get_capability;
366         drm_func_layer.layer_set_property = drm_layer_set_property;
367         drm_func_layer.layer_get_property = drm_layer_get_property;
368         drm_func_layer.layer_set_info = drm_layer_set_info;
369         drm_func_layer.layer_get_info = drm_layer_get_info;
370         drm_func_layer.layer_set_buffer = drm_layer_set_buffer;
371         drm_func_layer.layer_unset_buffer = drm_layer_unset_buffer;
372
373 #ifdef ENABLE_PP
374         memset(&drm_func_pp, 0, sizeof(drm_func_pp));
375         drm_func_pp.pp_destroy = drm_pp_destroy;
376         drm_func_pp.pp_set_info = drm_pp_set_info;
377         drm_func_pp.pp_attach = drm_pp_attach;
378         drm_func_pp.pp_commit = drm_pp_commit;
379         drm_func_pp.pp_set_done_handler = drm_pp_set_done_handler;
380 #endif
381
382         ret = tdm_backend_register_func_display(dpy, &drm_func_display);
383         if (ret != TDM_ERROR_NONE)
384                 goto failed;
385
386         ret = tdm_backend_register_func_output(dpy, &drm_func_output);
387         if (ret != TDM_ERROR_NONE)
388                 goto failed;
389
390         ret = tdm_backend_register_func_layer(dpy, &drm_func_layer);
391         if (ret != TDM_ERROR_NONE)
392                 goto failed;
393
394         if (drm_data->hwc_mode) {
395                 ret = tdm_backend_register_func_hwc(dpy, &drm_func_hwc);
396                 if (ret != TDM_ERROR_NONE)
397                         goto failed;
398
399                 ret = tdm_backend_register_func_hwc_window(dpy, &drm_func_hwc_window);
400                 if (ret != TDM_ERROR_NONE)
401                         goto failed;
402         }
403
404 #ifdef ENABLE_PP
405         ret = tdm_backend_register_func_pp(dpy, &drm_func_pp);
406         if (ret != TDM_ERROR_NONE)
407                 goto failed;
408 #endif
409
410         drm_data->dpy = dpy;
411
412         /* The drm master fd can be opened by a tbm backend module in
413          * tbm_bufmgr_init() time. In this case, we just get it from tbm.
414          */
415         drm_data->drm_fd = tbm_drm_helper_get_master_fd();
416         if (drm_data->drm_fd < 0) {
417                 drm_data->drm_fd = _tdm_drm_open_drm();
418
419                 if (drm_data->drm_fd < 0) {
420                         ret = TDM_ERROR_OPERATION_FAILED;
421                         goto failed;
422                 }
423
424                 tbm_drm_helper_set_tbm_master_fd(drm_data->drm_fd);
425         }
426
427         TDM_INFO("master fd: %d", drm_data->drm_fd);
428
429 #ifdef HAVE_UDEV
430         _tdm_drm_udev_init(drm_data);
431 #endif
432
433 #if LIBDRM_MAJOR_VERSION >= 2 && LIBDRM_MINOR_VERSION >= 4  && LIBDRM_MICRO_VERSION >= 47
434         if (drmSetClientCap(drm_data->drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1) < 0) {
435                 TDM_WRN("Set DRM_CLIENT_CAP_UNIVERSAL_PLANES failed");
436         } else {
437                 TDM_INFO("has universal planes");
438                 drm_data->has_universal_plane = 1;
439         }
440 #endif
441
442         drm_data->mode_res = drmModeGetResources(drm_data->drm_fd);
443         if (!drm_data->mode_res) {
444                 TDM_ERR("no drm resource: %m");
445                 ret = TDM_ERROR_OPERATION_FAILED;
446                 goto failed;
447         }
448
449         drm_data->plane_res = drmModeGetPlaneResources(drm_data->drm_fd);
450         if (!drm_data->plane_res) {
451                 TDM_ERR("no drm plane resource: %m");
452                 ret = TDM_ERROR_OPERATION_FAILED;
453                 goto failed;
454         }
455
456         if (drm_data->plane_res->count_planes <= 0) {
457                 TDM_ERR("no drm plane resource");
458                 ret = TDM_ERROR_OPERATION_FAILED;
459                 goto failed;
460         }
461
462         ret = tdm_drm_display_create_output_list(drm_data);
463         if (ret != TDM_ERROR_NONE)
464                 goto failed;
465
466         ret = tdm_drm_display_create_layer_list(drm_data);
467         if (ret != TDM_ERROR_NONE)
468                 goto failed;
469
470         if (error)
471                 *error = TDM_ERROR_NONE;
472
473         TDM_INFO("init success!");
474
475         return (tdm_backend_data *)drm_data;
476 failed:
477         if (error)
478                 *error = ret;
479
480         tdm_drm_deinit(drm_data);
481
482         TDM_ERR("init failed!");
483         return NULL;
484 }
485
486 tdm_backend_module tdm_backend_module_data = {
487         "drm",
488         "Samsung",
489         TDM_BACKEND_SET_ABI_VERSION(1, 1),
490         tdm_drm_init,
491         tdm_drm_deinit
492 };