1 /**************************************************************************
5 Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
7 Contact: SooChan Lim <sc1.lim@samsung.com>
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:
17 The above copyright notice and this permission notice (including the
18 next paragraph) shall be included in all copies or substantial portions
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.
29 **************************************************************************/
35 #include "tdm_backend_drm.h"
43 #define TDM_DRM_NAME "vigs"
46 static struct udev_device *
47 _tdm_find_primary_gpu(void)
50 struct udev_enumerate *e;
51 struct udev_list_entry *entry;
52 const char *path, *id;
53 struct udev_device *device, *drm_device, *pci;
57 TDM_BACKEND_ERR("fail to initialize udev context\n");
61 e = udev_enumerate_new(udev);
62 udev_enumerate_add_match_subsystem(e, "drm");
63 udev_enumerate_add_match_sysname(e, "card[0-9]*");
65 udev_enumerate_scan_devices(e);
67 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
68 path = udev_list_entry_get_name(entry);
69 device = udev_device_new_from_syspath(udev, path);
73 pci = udev_device_get_parent_with_subsystem_devtype(device,
76 id = udev_device_get_sysattr_value(pci, "boot_vga");
77 if (id && !strcmp(id, "1")) {
79 udev_device_unref(drm_device);
88 udev_device_unref(device);
91 udev_enumerate_unref(e);
96 _tdm_drm_udev_fd_handler(int fd, hal_tdm_event_loop_mask mask, void *user_data)
98 tdm_drm_display *display_data = (tdm_drm_display*)user_data;
99 struct udev_device *dev;
105 dev = udev_monitor_receive_device(display_data->uevent_monitor);
107 TDM_BACKEND_ERR("couldn't receive device");
108 return HAL_TDM_ERROR_OPERATION_FAILED;
111 udev_devnum = udev_device_get_devnum(dev);
113 ret = fstat(display_data->drm_fd, &s);
115 TDM_BACKEND_ERR("fstat failed");
116 udev_device_unref(dev);
117 return HAL_TDM_ERROR_OPERATION_FAILED;
120 hotplug = udev_device_get_property_value(dev, "HOTPLUG");
122 if (memcmp(&s.st_rdev, &udev_devnum, sizeof(dev_t)) == 0 &&
123 hotplug && atoi(hotplug) == 1) {
124 TDM_BACKEND_INFO("HotPlug");
125 tdm_drm_display_update_output_status(display_data);
128 udev_device_unref(dev);
130 return HAL_TDM_ERROR_NONE;
133 static struct udev_monitor *
134 _tdm_drm_create_udev_monitor()
136 struct udev *u = NULL;
137 struct udev_monitor *mon = NULL;
141 TDM_BACKEND_ERR("couldn't create udev");
145 mon = udev_monitor_new_from_netlink(u, "udev");
147 TDM_BACKEND_ERR("couldn't create udev monitor");
151 if (udev_monitor_filter_add_match_subsystem_devtype(mon, "drm", "drm_minor") > 0 ||
152 udev_monitor_enable_receiving(mon) < 0) {
153 TDM_BACKEND_ERR("add match subsystem failed");
157 TDM_BACKEND_INFO("hotplug monitor created");
163 udev_monitor_unref(mon);
171 _tdm_drm_destroy_udev_monitor(struct udev_monitor *mon)
178 u = udev_monitor_get_udev(mon);
179 udev_monitor_unref(mon);
182 TDM_BACKEND_INFO("hotplug monitor destroyed");
187 _tdm_drm_open_drm(void)
191 fd = drmOpen(TDM_DRM_NAME, NULL);
193 TDM_BACKEND_WRN("Cannot open '%s' drm", TDM_DRM_NAME);
197 struct udev_device *drm_device = NULL;
198 const char *filename;
199 TDM_BACKEND_WRN("Cannot open drm device.. search by udev");
201 drm_device = _tdm_find_primary_gpu();
202 if (drm_device == NULL) {
203 TDM_BACKEND_ERR("fail to find drm device\n");
207 filename = udev_device_get_devnode(drm_device);
209 fd = open(filename, O_RDWR | O_CLOEXEC);
211 TDM_BACKEND_ERR("Cannot open drm device(%s)\n", filename);
213 TDM_BACKEND_DBG("open drm device (name:%s, fd:%d)", filename, fd);
215 udev_device_unref(drm_device);
223 _tdm_drm_display_deinitialize(tdm_drm_display *display_data)
225 tdm_drm_display_destroy_output_list(display_data);
227 if (display_data->plane_res)
228 drmModeFreePlaneResources(display_data->plane_res);
229 if (display_data->mode_res)
230 drmModeFreeResources(display_data->mode_res);
234 _tdm_drm_display_initialize(tdm_drm_display *display_data)
238 #if LIBDRM_MAJOR_VERSION >= 2 && LIBDRM_MINOR_VERSION >= 4 && LIBDRM_MICRO_VERSION >= 47
239 if (drmSetClientCap(display_data->drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1) < 0) {
240 TDM_BACKEND_WRN("Set DRM_CLIENT_CAP_UNIVERSAL_PLANES failed");
242 TDM_BACKEND_INFO("has universal planes");
243 display_data->has_universal_plane = 1;
247 display_data->mode_res = drmModeGetResources(display_data->drm_fd);
248 if (!display_data->mode_res) {
249 TDM_BACKEND_ERR("no drm resource: %m");
250 ret = HAL_TDM_ERROR_OPERATION_FAILED;
254 display_data->plane_res = drmModeGetPlaneResources(display_data->drm_fd);
255 if (!display_data->plane_res) {
256 TDM_BACKEND_ERR("no drm plane resource: %m");
257 ret = HAL_TDM_ERROR_OPERATION_FAILED;
261 if (display_data->plane_res->count_planes <= 0) {
262 TDM_BACKEND_ERR("no drm plane resource");
263 ret = HAL_TDM_ERROR_OPERATION_FAILED;
267 ret = tdm_drm_display_create_output_list(display_data);
268 if (ret != HAL_TDM_ERROR_NONE)
271 ret = tdm_drm_display_create_layer_list(display_data);
272 if (ret != HAL_TDM_ERROR_NONE)
278 _tdm_drm_display_deinitialize(display_data);
284 _tdm_drm_master_drm_fd_handler(hal_tdm_fd master_drm_fd, void *user_data)
286 tdm_drm_display *display_data = (tdm_drm_display *) user_data;
289 TDM_BACKEND_RETURN_VAL_IF_FAIL(display_data != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
291 display_data->drm_fd = master_drm_fd;
292 TDM_BACKEND_INFO("Get the master drm_fd(%d)!\n", display_data->drm_fd);
294 // initialize display with a master drm_fd
295 ret = _tdm_drm_display_initialize(display_data);
296 if (ret != HAL_TDM_ERROR_NONE) {
297 TDM_BACKEND_ERR("fail to _tdm_drm_display_initialize!\n");
298 _tdm_drm_display_deinitialize(display_data);
300 return HAL_TDM_ERROR_OPERATION_FAILED;
303 return HAL_TDM_ERROR_NONE;
307 hal_backend_tdm_drm_exit(void *data)
309 hal_tdm_backend_data *backend_data = (hal_tdm_backend_data *)data;
310 tdm_drm_display *display_data;
312 TDM_BACKEND_INFO("deinit");
314 TDM_BACKEND_RETURN_VAL_IF_FAIL(backend_data != NULL, -1);
316 display_data = (tdm_drm_display *)backend_data->display;
317 TDM_BACKEND_RETURN_VAL_IF_FAIL(display_data != NULL, -1);
319 if (backend_data->hwc_window_funcs) {
320 free(backend_data->hwc_window_funcs);
321 backend_data->hwc_window_funcs = NULL;
323 if (backend_data->hwc_funcs) {
324 free(backend_data->hwc_funcs);
325 backend_data->hwc_funcs = NULL;
327 if (backend_data->output_funcs) {
328 free(backend_data->output_funcs);
329 backend_data->output_funcs = NULL;
331 if (backend_data->display_funcs) {
332 free(backend_data->display_funcs);
333 backend_data->display_funcs = NULL;
336 _tdm_drm_display_deinitialize(display_data);
339 if (display_data->uevent_monitor)
340 _tdm_drm_destroy_udev_monitor(display_data->uevent_monitor);
343 if (display_data->drm_fd >= 0)
344 close(display_data->drm_fd);
351 return HAL_TDM_ERROR_NONE;
355 hal_backend_tdm_drm_init(void **data)
357 hal_tdm_backend_data *backend_data = NULL;
358 hal_tdm_display_funcs *display_funcs = NULL;
359 hal_tdm_output_funcs *output_funcs = NULL;
360 hal_tdm_hwc_funcs *hwc_funcs = NULL;
361 hal_tdm_hwc_window_funcs *hwc_window_funcs = NULL;
362 hal_tdm_pp_funcs *pp_funcs = NULL;
363 tdm_drm_display *display_data = NULL;
367 static struct udev_monitor *mon;
368 hal_tdm_event_source *udev_event_source;
372 TDM_BACKEND_ERR("*data is null.\n");
376 /* allocate a hal_tdm_backend_data */
377 backend_data = calloc(1, sizeof(struct _hal_tdm_backend_data));
379 TDM_BACKEND_ERR("fail to alloc backend_data!\n");
383 *data = backend_data;
385 /* allocate a hal_tdm_display */
386 display_data = calloc(1, sizeof(struct _tdm_drm_display));
388 TDM_BACKEND_ERR("fail to alloc display_data!\n");
391 backend_data->display = (hal_tdm_display *)display_data;
393 LIST_INITHEAD(&display_data->output_list);
394 LIST_INITHEAD(&display_data->buffer_list);
396 // check if drm_fd is master fd.
397 drm_fd = _tdm_drm_open_drm();
399 ret = HAL_TDM_ERROR_OPERATION_FAILED;
403 // set true when backend has a drm_device.
404 backend_data->has_drm_device = 1;
406 if (drmIsMaster(drm_fd)) {
407 // drm_fd is a master drm_fd.
408 backend_data->drm_info.drm_fd = drm_fd;
409 backend_data->drm_info.is_master = 1;
411 display_data->drm_fd = drm_fd;
412 TDM_BACKEND_INFO("Get the master drm_fd(%d)!\n", display_data->drm_fd);
414 // initialize display with a master drm_fd
415 ret = _tdm_drm_display_initialize(display_data);
416 if (ret != HAL_TDM_ERROR_NONE) {
417 TDM_BACKEND_ERR("fail to _tdm_drm_display_initialize!\n");
421 // drm_fd is not a master drm_fd.
422 // request a master drm_fd
424 backend_data->drm_info.drm_fd = -1;
425 backend_data->drm_info.is_master = 0;
426 backend_data->drm_info.master_drm_fd_func = _tdm_drm_master_drm_fd_handler;
427 backend_data->drm_info.user_data = display_data;
429 TDM_BACKEND_INFO("A backend requests an master drm_fd.\n");
433 mon = _tdm_drm_create_udev_monitor();
435 ret = HAL_TDM_ERROR_OPERATION_FAILED;
438 display_data->uevent_monitor = mon;
440 /* alloc and register udev_event_source */
441 udev_event_source = calloc(1, sizeof(struct _hal_tdm_event_source));
442 if (!udev_event_source) {
443 TDM_BACKEND_ERR("fail to alloc udev_event_source!\n");
446 udev_event_source->event_fd = udev_monitor_get_fd(mon);
447 udev_event_source->func = _tdm_drm_udev_fd_handler;
448 udev_event_source->user_data = display_data;
450 backend_data->event_sources[0] = udev_event_source;
451 backend_data->num_event_sources++;
454 /* alloc and register display_funcs */
455 display_funcs = calloc(1, sizeof(struct _hal_tdm_display_funcs));
456 if (!display_funcs) {
457 TDM_BACKEND_ERR("fail to alloc display_funcs!\n");
460 backend_data->display_funcs = display_funcs;
462 display_funcs->display_get_capability = drm_display_get_capability;
463 display_funcs->display_get_pp_capability = drm_display_get_pp_capability;
464 display_funcs->display_get_outputs = drm_display_get_outputs;
465 display_funcs->display_get_fd = drm_display_get_fd;
466 display_funcs->display_handle_events = drm_display_handle_events;
467 display_funcs->display_create_pp = drm_display_create_pp;
469 /* alloc and register output_funcs */
470 output_funcs = calloc(1, sizeof(struct _hal_tdm_output_funcs));
472 TDM_BACKEND_ERR("fail to alloc output_funcs!\n");
475 backend_data->output_funcs = output_funcs;
477 output_funcs->output_get_capability = drm_output_get_capability;
478 output_funcs->output_set_property = drm_output_set_property;
479 output_funcs->output_get_property = drm_output_get_property;
480 output_funcs->output_wait_vblank = drm_output_wait_vblank;
481 output_funcs->output_set_vblank_handler = drm_output_set_vblank_handler;
482 output_funcs->output_commit = drm_output_commit;
483 output_funcs->output_set_commit_handler = drm_output_set_commit_handler;
484 output_funcs->output_set_dpms = drm_output_set_dpms;
485 output_funcs->output_get_dpms = drm_output_get_dpms;
486 output_funcs->output_set_mode = drm_output_set_mode;
487 output_funcs->output_get_mode = drm_output_get_mode;
489 output_funcs->output_set_status_handler = drm_output_set_status_handler;
491 output_funcs->output_get_hwc = drm_output_get_hwc;
493 /* alloc and register hwc_funcs */
494 hwc_funcs = calloc(1, sizeof(struct _hal_tdm_hwc_funcs));
496 TDM_BACKEND_ERR("fail to alloc hwc_funcs!\n");
499 backend_data->hwc_funcs = hwc_funcs;
501 hwc_funcs->hwc_create_window = drm_hwc_create_window;
502 hwc_funcs->hwc_get_video_supported_formats = drm_hwc_get_video_supported_formats;
503 hwc_funcs->hwc_get_video_available_properties = NULL;
504 hwc_funcs->hwc_get_capabilities = drm_hwc_get_capabilities;
505 hwc_funcs->hwc_get_available_properties = drm_hwc_get_available_properties;
506 hwc_funcs->hwc_get_client_target_buffer_queue = drm_hwc_get_client_target_buffer_queue;
507 hwc_funcs->hwc_set_client_target_buffer = drm_hwc_set_client_target_buffer;
508 hwc_funcs->hwc_validate = drm_hwc_validate;
509 hwc_funcs->hwc_get_changed_composition_types = drm_hwc_get_changed_composition_types;
510 hwc_funcs->hwc_accept_validation = drm_hwc_accept_validation;
511 hwc_funcs->hwc_commit = drm_hwc_commit;
512 hwc_funcs->hwc_set_commit_handler = drm_hwc_set_commit_handler;
514 /* alloc and register hwc_window_funcs */
515 hwc_window_funcs = calloc(1, sizeof(struct _hal_tdm_hwc_window_funcs));
517 TDM_BACKEND_ERR("fail to alloc hwc_window_funcs!\n");
520 backend_data->hwc_window_funcs = hwc_window_funcs;
522 hwc_window_funcs->hwc_window_destroy = drm_hwc_window_destroy;
523 hwc_window_funcs->hwc_window_acquire_buffer_queue = NULL; // no need
524 hwc_window_funcs->hwc_window_release_buffer_queue = NULL; // no need
525 hwc_window_funcs->hwc_window_set_composition_type = drm_hwc_window_set_composition_type;
526 hwc_window_funcs->hwc_window_set_buffer_damage = drm_hwc_window_set_buffer_damage;
527 hwc_window_funcs->hwc_window_set_info = drm_hwc_window_set_info;
528 hwc_window_funcs->hwc_window_set_buffer = drm_hwc_window_set_buffer;
529 hwc_window_funcs->hwc_window_set_property = drm_hwc_window_set_property;
530 hwc_window_funcs->hwc_window_get_property = drm_hwc_window_get_property;
531 hwc_window_funcs->hwc_window_get_constraints = drm_hwc_window_get_constraints;
532 hwc_window_funcs->hwc_window_set_name = drm_hwc_window_set_name;
533 hwc_window_funcs->hwc_window_set_cursor_image = drm_hwc_window_set_cursor_image;
536 /* alloc and register pp_funcs */
537 pp_funcs = calloc(1, sizeof(struct _hal_tdm_pp_funcs));
539 TDM_BACKEND_ERR("fail to alloc pp_funcs!\n");
542 backend_data->pp_funcs = pp_funcs;
544 pp_funcs->pp_destroy = drm_pp_destroy;
545 pp_funcs->pp_set_info = drm_pp_set_info;
546 pp_funcs->pp_attach = drm_pp_attach;
547 pp_funcs->pp_commit = drm_pp_commit;
548 pp_funcs->pp_set_done_handler = drm_pp_set_done_handler;
551 TDM_BACKEND_INFO("init success!");
553 return HAL_TDM_ERROR_NONE;
556 TDM_BACKEND_ERR("init failed!");
558 hal_backend_tdm_drm_exit((void *)backend_data);
563 hal_backend hal_backend_tdm_data = {
566 HAL_ABI_VERSION_TIZEN_6_5,
567 hal_backend_tdm_drm_init,
568 hal_backend_tdm_drm_exit