5 #include "tdm_backend_drm.h"
13 #define TDM_DRM_NAME "vigs"
16 static struct udev_device *
17 _tdm_find_primary_gpu(void)
20 struct udev_enumerate *e;
21 struct udev_list_entry *entry;
22 const char *path, *id;
23 struct udev_device *device, *drm_device, *pci;
27 TDM_BACKEND_ERR("fail to initialize udev context\n");
31 e = udev_enumerate_new(udev);
32 udev_enumerate_add_match_subsystem(e, "drm");
33 udev_enumerate_add_match_sysname(e, "card[0-9]*");
35 udev_enumerate_scan_devices(e);
37 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
38 path = udev_list_entry_get_name(entry);
39 device = udev_device_new_from_syspath(udev, path);
43 pci = udev_device_get_parent_with_subsystem_devtype(device,
46 id = udev_device_get_sysattr_value(pci, "boot_vga");
47 if (id && !strcmp(id, "1")) {
49 udev_device_unref(drm_device);
58 udev_device_unref(device);
61 udev_enumerate_unref(e);
66 _tdm_drm_udev_fd_handler(int fd, hal_tdm_event_loop_mask mask, void *user_data)
68 tdm_drm_display *display_data = (tdm_drm_display*)user_data;
69 struct udev_device *dev;
75 dev = udev_monitor_receive_device(display_data->uevent_monitor);
77 TDM_BACKEND_ERR("couldn't receive device");
78 return HAL_TDM_ERROR_OPERATION_FAILED;
81 udev_devnum = udev_device_get_devnum(dev);
83 ret = fstat(display_data->drm_fd, &s);
85 TDM_BACKEND_ERR("fstat failed");
86 udev_device_unref(dev);
87 return HAL_TDM_ERROR_OPERATION_FAILED;
90 hotplug = udev_device_get_property_value(dev, "HOTPLUG");
92 if (memcmp(&s.st_rdev, &udev_devnum, sizeof(dev_t)) == 0 &&
93 hotplug && atoi(hotplug) == 1) {
94 TDM_BACKEND_INFO("HotPlug");
95 tdm_drm_display_update_output_status(display_data);
98 udev_device_unref(dev);
100 return HAL_TDM_ERROR_NONE;
103 static struct udev_monitor *
104 _tdm_drm_create_udev_monitor()
106 struct udev *u = NULL;
107 struct udev_monitor *mon = NULL;
111 TDM_BACKEND_ERR("couldn't create udev");
115 mon = udev_monitor_new_from_netlink(u, "udev");
117 TDM_BACKEND_ERR("couldn't create udev monitor");
121 if (udev_monitor_filter_add_match_subsystem_devtype(mon, "drm", "drm_minor") > 0 ||
122 udev_monitor_enable_receiving(mon) < 0) {
123 TDM_BACKEND_ERR("add match subsystem failed");
127 TDM_BACKEND_INFO("hotplug monitor created");
133 udev_monitor_unref(mon);
141 _tdm_drm_destroy_udev_monitor(struct udev_monitor *mon)
148 u = udev_monitor_get_udev(mon);
149 udev_monitor_unref(mon);
152 TDM_BACKEND_INFO("hotplug monitor destroyed");
157 _tdm_drm_open_drm(void)
161 fd = drmOpen(TDM_DRM_NAME, NULL);
163 TDM_BACKEND_WRN("Cannot open '%s' drm", TDM_DRM_NAME);
167 struct udev_device *drm_device = NULL;
168 const char *filename;
169 TDM_BACKEND_WRN("Cannot open drm device.. search by udev");
171 drm_device = _tdm_find_primary_gpu();
172 if (drm_device == NULL) {
173 TDM_BACKEND_ERR("fail to find drm device\n");
177 filename = udev_device_get_devnode(drm_device);
179 fd = open(filename, O_RDWR | O_CLOEXEC);
181 TDM_BACKEND_ERR("Cannot open drm device(%s)\n", filename);
183 TDM_BACKEND_DBG("open drm device (name:%s, fd:%d)", filename, fd);
185 udev_device_unref(drm_device);
193 _tdm_drm_display_deinitialize(tdm_drm_display *display_data)
195 tdm_drm_display_destroy_output_list(display_data);
197 if (display_data->plane_res)
198 drmModeFreePlaneResources(display_data->plane_res);
199 if (display_data->mode_res)
200 drmModeFreeResources(display_data->mode_res);
204 _tdm_drm_display_initialize(tdm_drm_display *display_data)
208 #if LIBDRM_MAJOR_VERSION >= 2 && LIBDRM_MINOR_VERSION >= 4 && LIBDRM_MICRO_VERSION >= 47
209 if (drmSetClientCap(display_data->drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1) < 0) {
210 TDM_BACKEND_WRN("Set DRM_CLIENT_CAP_UNIVERSAL_PLANES failed");
212 TDM_BACKEND_INFO("has universal planes");
213 display_data->has_universal_plane = 1;
217 display_data->mode_res = drmModeGetResources(display_data->drm_fd);
218 if (!display_data->mode_res) {
219 TDM_BACKEND_ERR("no drm resource: %m");
220 ret = HAL_TDM_ERROR_OPERATION_FAILED;
224 display_data->plane_res = drmModeGetPlaneResources(display_data->drm_fd);
225 if (!display_data->plane_res) {
226 TDM_BACKEND_ERR("no drm plane resource: %m");
227 ret = HAL_TDM_ERROR_OPERATION_FAILED;
231 if (display_data->plane_res->count_planes <= 0) {
232 TDM_BACKEND_ERR("no drm plane resource");
233 ret = HAL_TDM_ERROR_OPERATION_FAILED;
237 ret = tdm_drm_display_create_output_list(display_data);
238 if (ret != HAL_TDM_ERROR_NONE)
241 ret = tdm_drm_display_create_layer_list(display_data);
242 if (ret != HAL_TDM_ERROR_NONE)
248 _tdm_drm_display_deinitialize(display_data);
254 _tdm_drm_master_drm_fd_handler(hal_tdm_fd master_drm_fd, void *user_data)
256 tdm_drm_display *display_data = (tdm_drm_display *) user_data;
259 TDM_BACKEND_RETURN_VAL_IF_FAIL(display_data != NULL, HAL_TDM_ERROR_INVALID_PARAMETER);
261 display_data->drm_fd = master_drm_fd;
262 TDM_BACKEND_INFO("Get the master drm_fd(%d)!\n", display_data->drm_fd);
264 // initialize display with a master drm_fd
265 ret = _tdm_drm_display_initialize(display_data);
266 if (ret != HAL_TDM_ERROR_NONE) {
267 TDM_BACKEND_ERR("fail to _tdm_drm_display_initialize!\n");
268 _tdm_drm_display_deinitialize(display_data);
270 return HAL_TDM_ERROR_OPERATION_FAILED;
273 return HAL_TDM_ERROR_NONE;
277 hal_backend_tdm_drm_exit(void *data)
279 hal_tdm_backend_data *backend_data = (hal_tdm_backend_data *)data;
280 tdm_drm_display *display_data;
282 TDM_BACKEND_INFO("deinit");
284 TDM_BACKEND_RETURN_VAL_IF_FAIL(backend_data != NULL, -1);
286 display_data = (tdm_drm_display *)backend_data->display;
287 TDM_BACKEND_RETURN_VAL_IF_FAIL(display_data != NULL, -1);
289 if (backend_data->hwc_window_funcs) {
290 free(backend_data->hwc_window_funcs);
291 backend_data->hwc_window_funcs = NULL;
293 if (backend_data->hwc_funcs) {
294 free(backend_data->hwc_funcs);
295 backend_data->hwc_funcs = NULL;
297 if (backend_data->output_funcs) {
298 free(backend_data->output_funcs);
299 backend_data->output_funcs = NULL;
301 if (backend_data->display_funcs) {
302 free(backend_data->display_funcs);
303 backend_data->display_funcs = NULL;
306 _tdm_drm_display_deinitialize(display_data);
309 if (display_data->uevent_monitor)
310 _tdm_drm_destroy_udev_monitor(display_data->uevent_monitor);
313 if (display_data->drm_fd >= 0)
314 close(display_data->drm_fd);
321 return HAL_TDM_ERROR_NONE;
325 hal_backend_tdm_drm_init(void **data)
327 hal_tdm_backend_data *backend_data = NULL;
328 hal_tdm_display_funcs *display_funcs = NULL;
329 hal_tdm_output_funcs *output_funcs = NULL;
330 hal_tdm_hwc_funcs *hwc_funcs = NULL;
331 hal_tdm_hwc_window_funcs *hwc_window_funcs = NULL;
332 hal_tdm_pp_funcs *pp_funcs = NULL;
333 tdm_drm_display *display_data = NULL;
337 static struct udev_monitor *mon;
338 hal_tdm_event_source *udev_event_source;
342 TDM_BACKEND_ERR("*data is null.\n");
346 /* allocate a hal_tdm_backend_data */
347 backend_data = calloc(1, sizeof(struct _hal_tdm_backend_data));
349 TDM_BACKEND_ERR("fail to alloc backend_data!\n");
353 *data = backend_data;
355 /* allocate a hal_tdm_display */
356 display_data = calloc(1, sizeof(struct _tdm_drm_display));
358 TDM_BACKEND_ERR("fail to alloc display_data!\n");
361 backend_data->display = (hal_tdm_display *)display_data;
363 LIST_INITHEAD(&display_data->output_list);
364 LIST_INITHEAD(&display_data->buffer_list);
366 // check if drm_fd is master fd.
367 drm_fd = _tdm_drm_open_drm();
369 ret = HAL_TDM_ERROR_OPERATION_FAILED;
373 // set true when backend has a drm_device.
374 backend_data->has_drm_device = 1;
376 if (drmIsMaster(drm_fd)) {
377 // drm_fd is a master drm_fd.
378 backend_data->drm_info.drm_fd = drm_fd;
379 backend_data->drm_info.is_master = 1;
381 display_data->drm_fd = drm_fd;
382 TDM_BACKEND_INFO("Get the master drm_fd(%d)!\n", display_data->drm_fd);
384 // initialize display with a master drm_fd
385 ret = _tdm_drm_display_initialize(display_data);
386 if (ret != HAL_TDM_ERROR_NONE) {
387 TDM_BACKEND_ERR("fail to _tdm_drm_display_initialize!\n");
391 // drm_fd is not a master drm_fd.
392 // request a master drm_fd
394 backend_data->drm_info.drm_fd = -1;
395 backend_data->drm_info.is_master = 0;
396 backend_data->drm_info.master_drm_fd_func = _tdm_drm_master_drm_fd_handler;
397 backend_data->drm_info.user_data = display_data;
399 TDM_BACKEND_INFO("A backend requests an master drm_fd.\n");
403 mon = _tdm_drm_create_udev_monitor();
405 ret = HAL_TDM_ERROR_OPERATION_FAILED;
408 display_data->uevent_monitor = mon;
410 /* alloc and register udev_event_source */
411 udev_event_source = calloc(1, sizeof(struct _hal_tdm_event_source));
412 if (!udev_event_source) {
413 TDM_BACKEND_ERR("fail to alloc udev_event_source!\n");
416 udev_event_source->event_fd = udev_monitor_get_fd(mon);
417 udev_event_source->func = _tdm_drm_udev_fd_handler;
418 udev_event_source->user_data = display_data;
420 backend_data->event_sources[0] = udev_event_source;
421 backend_data->num_event_sources++;
424 /* alloc and register display_funcs */
425 display_funcs = calloc(1, sizeof(struct _hal_tdm_display_funcs));
426 if (!display_funcs) {
427 TDM_BACKEND_ERR("fail to alloc display_funcs!\n");
430 backend_data->display_funcs = display_funcs;
432 display_funcs->display_get_capability = drm_display_get_capability;
433 display_funcs->display_get_pp_capability = drm_display_get_pp_capability;
434 display_funcs->display_get_outputs = drm_display_get_outputs;
435 display_funcs->display_get_fd = drm_display_get_fd;
436 display_funcs->display_handle_events = drm_display_handle_events;
437 display_funcs->display_create_pp = drm_display_create_pp;
439 /* alloc and register output_funcs */
440 output_funcs = calloc(1, sizeof(struct _hal_tdm_output_funcs));
442 TDM_BACKEND_ERR("fail to alloc output_funcs!\n");
445 backend_data->output_funcs = output_funcs;
447 output_funcs->output_get_capability = drm_output_get_capability;
448 output_funcs->output_set_property = drm_output_set_property;
449 output_funcs->output_get_property = drm_output_get_property;
450 output_funcs->output_wait_vblank = drm_output_wait_vblank;
451 output_funcs->output_set_vblank_handler = drm_output_set_vblank_handler;
452 output_funcs->output_commit = drm_output_commit;
453 output_funcs->output_set_commit_handler = drm_output_set_commit_handler;
454 output_funcs->output_set_dpms = drm_output_set_dpms;
455 output_funcs->output_get_dpms = drm_output_get_dpms;
456 output_funcs->output_set_mode = drm_output_set_mode;
457 output_funcs->output_get_mode = drm_output_get_mode;
459 output_funcs->output_set_status_handler = drm_output_set_status_handler;
461 output_funcs->output_get_hwc = drm_output_get_hwc;
463 /* alloc and register hwc_funcs */
464 hwc_funcs = calloc(1, sizeof(struct _hal_tdm_hwc_funcs));
466 TDM_BACKEND_ERR("fail to alloc hwc_funcs!\n");
469 backend_data->hwc_funcs = hwc_funcs;
471 hwc_funcs->hwc_create_window = drm_hwc_create_window;
472 hwc_funcs->hwc_get_video_supported_formats = drm_hwc_get_video_supported_formats;
473 hwc_funcs->hwc_get_video_available_properties = NULL;
474 hwc_funcs->hwc_get_capabilities = drm_hwc_get_capabilities;
475 hwc_funcs->hwc_get_available_properties = drm_hwc_get_available_properties;
476 hwc_funcs->hwc_get_client_target_buffer_queue = drm_hwc_get_client_target_buffer_queue;
477 hwc_funcs->hwc_set_client_target_buffer = drm_hwc_set_client_target_buffer;
478 hwc_funcs->hwc_validate = drm_hwc_validate;
479 hwc_funcs->hwc_get_changed_composition_types = drm_hwc_get_changed_composition_types;
480 hwc_funcs->hwc_accept_validation = drm_hwc_accept_validation;
481 hwc_funcs->hwc_commit = drm_hwc_commit;
482 hwc_funcs->hwc_set_commit_handler = drm_hwc_set_commit_handler;
484 /* alloc and register hwc_window_funcs */
485 hwc_window_funcs = calloc(1, sizeof(struct _hal_tdm_hwc_window_funcs));
487 TDM_BACKEND_ERR("fail to alloc hwc_window_funcs!\n");
490 backend_data->hwc_window_funcs = hwc_window_funcs;
492 hwc_window_funcs->hwc_window_destroy = drm_hwc_window_destroy;
493 hwc_window_funcs->hwc_window_acquire_buffer_queue = NULL; // no need
494 hwc_window_funcs->hwc_window_release_buffer_queue = NULL; // no need
495 hwc_window_funcs->hwc_window_set_composition_type = drm_hwc_window_set_composition_type;
496 hwc_window_funcs->hwc_window_set_buffer_damage = drm_hwc_window_set_buffer_damage;
497 hwc_window_funcs->hwc_window_set_info = drm_hwc_window_set_info;
498 hwc_window_funcs->hwc_window_set_buffer = drm_hwc_window_set_buffer;
499 hwc_window_funcs->hwc_window_set_property = drm_hwc_window_set_property;
500 hwc_window_funcs->hwc_window_get_property = drm_hwc_window_get_property;
501 hwc_window_funcs->hwc_window_get_constraints = drm_hwc_window_get_constraints;
502 hwc_window_funcs->hwc_window_set_name = drm_hwc_window_set_name;
503 hwc_window_funcs->hwc_window_set_cursor_image = drm_hwc_window_set_cursor_image;
506 /* alloc and register pp_funcs */
507 pp_funcs = calloc(1, sizeof(struct _hal_tdm_pp_funcs));
509 TDM_BACKEND_ERR("fail to alloc pp_funcs!\n");
512 backend_data->pp_funcs = pp_funcs;
514 pp_funcs->pp_destroy = drm_pp_destroy;
515 pp_funcs->pp_set_info = drm_pp_set_info;
516 pp_funcs->pp_attach = drm_pp_attach;
517 pp_funcs->pp_commit = drm_pp_commit;
518 pp_funcs->pp_set_done_handler = drm_pp_set_done_handler;
521 TDM_BACKEND_INFO("init success!");
523 return HAL_TDM_ERROR_NONE;
526 TDM_BACKEND_ERR("init failed!");
528 hal_backend_tdm_drm_exit((void *)backend_data);
533 hal_backend hal_backend_tdm_data = {
536 HAL_ABI_VERSION_TIZEN_6_5,
537 hal_backend_tdm_drm_init,
538 hal_backend_tdm_drm_exit