10 #include <tdm_helper.h>
11 #include <tbm_drm_helper.h>
15 #define TDM_DRM_NAME "vigs"
19 static tdm_drm_data *drm_data;
22 static struct udev_device *
23 _tdm_find_primary_gpu(void)
26 struct udev_enumerate *e;
27 struct udev_list_entry *entry;
28 const char *path, *id;
29 struct udev_device *device, *drm_device, *pci;
33 TDM_ERR("fail to initialize udev context\n");
37 e = udev_enumerate_new(udev);
38 udev_enumerate_add_match_subsystem(e, "drm");
39 udev_enumerate_add_match_sysname(e, "card[0-9]*");
41 udev_enumerate_scan_devices(e);
43 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
44 path = udev_list_entry_get_name(entry);
45 device = udev_device_new_from_syspath(udev, path);
49 pci = udev_device_get_parent_with_subsystem_devtype(device,
52 id = udev_device_get_sysattr_value(pci, "boot_vga");
53 if (id && !strcmp(id, "1")) {
55 udev_device_unref(drm_device);
64 udev_device_unref(device);
67 udev_enumerate_unref(e);
72 _tdm_drm_udev_fd_handler(int fd, tdm_event_loop_mask mask, void *user_data)
74 tdm_drm_data *edata = (tdm_drm_data*)user_data;
75 struct udev_device *dev;
81 dev = udev_monitor_receive_device(edata->uevent_monitor);
83 TDM_ERR("couldn't receive device");
84 return TDM_ERROR_OPERATION_FAILED;
87 udev_devnum = udev_device_get_devnum(dev);
89 ret = fstat(edata->drm_fd, &s);
91 TDM_ERR("fstat failed");
92 udev_device_unref(dev);
93 return TDM_ERROR_OPERATION_FAILED;
96 hotplug = udev_device_get_property_value(dev, "HOTPLUG");
98 if (memcmp(&s.st_rdev, &udev_devnum, sizeof(dev_t)) == 0 &&
99 hotplug && atoi(hotplug) == 1) {
101 tdm_drm_display_update_output_status(edata);
104 udev_device_unref(dev);
106 return TDM_ERROR_NONE;
110 _tdm_drm_udev_init(tdm_drm_data *edata)
112 struct udev *u = NULL;
113 struct udev_monitor *mon = NULL;
117 TDM_ERR("couldn't create udev");
121 mon = udev_monitor_new_from_netlink(u, "udev");
123 TDM_ERR("couldn't create udev monitor");
127 if (udev_monitor_filter_add_match_subsystem_devtype(mon, "drm", "drm_minor") > 0 ||
128 udev_monitor_enable_receiving(mon) < 0) {
129 TDM_ERR("add match subsystem failed");
133 edata->uevent_source =
134 tdm_event_loop_add_fd_handler(edata->dpy, udev_monitor_get_fd(mon),
135 TDM_EVENT_LOOP_READABLE,
136 _tdm_drm_udev_fd_handler,
138 if (!edata->uevent_source) {
139 TDM_ERR("couldn't create udev event source");
143 edata->uevent_monitor = mon;
145 TDM_INFO("hotplug monitor created");
150 udev_monitor_unref(mon);
156 _tdm_drm_udev_deinit(tdm_drm_data *edata)
158 if (edata->uevent_source) {
159 tdm_event_loop_source_remove(edata->uevent_source);
160 edata->uevent_source = NULL;
163 if (edata->uevent_monitor) {
164 struct udev *u = udev_monitor_get_udev(edata->uevent_monitor);
165 udev_monitor_unref(edata->uevent_monitor);
167 edata->uevent_monitor = NULL;
168 TDM_INFO("hotplug monitor destroyed");
174 _tdm_drm_open_drm(void)
178 fd = drmOpen(TDM_DRM_NAME, NULL);
180 TDM_WRN("Cannot open '%s' drm", TDM_DRM_NAME);
184 struct udev_device *drm_device = NULL;
185 const char *filename;
186 TDM_WRN("Cannot open drm device.. search by udev");
188 drm_device = _tdm_find_primary_gpu();
189 if (drm_device == NULL) {
190 TDM_ERR("fail to find drm device\n");
194 filename = udev_device_get_devnode(drm_device);
196 fd = open(filename, O_RDWR | O_CLOEXEC);
198 TDM_ERR("Cannot open drm device(%s)\n", filename);
200 TDM_DBG("open drm device (name:%s, fd:%d)", filename, fd);
202 udev_device_unref(drm_device);
210 tdm_drm_deinit(tdm_backend_data *bdata)
212 if (drm_data != bdata)
218 _tdm_drm_udev_deinit(drm_data);
221 tdm_drm_display_destroy_output_list(drm_data);
223 if (drm_data->plane_res)
224 drmModeFreePlaneResources(drm_data->plane_res);
225 if (drm_data->mode_res)
226 drmModeFreeResources(drm_data->mode_res);
227 if (drm_data->drm_fd >= 0)
228 close(drm_data->drm_fd);
235 tdm_drm_init(tdm_display *dpy, tdm_error *error)
237 tdm_func_display drm_func_display;
238 tdm_func_output drm_func_output;
239 tdm_func_layer drm_func_layer;
240 tdm_func_hwc drm_func_hwc;
241 tdm_func_hwc_window drm_func_hwc_window;
243 tdm_func_pp drm_func_pp;
248 TDM_ERR("display is null");
250 *error = TDM_ERROR_INVALID_PARAMETER;
255 TDM_ERR("failed: init twice");
257 *error = TDM_ERROR_BAD_REQUEST;
261 drm_data = calloc(1, sizeof(tdm_drm_data));
263 TDM_ERR("alloc failed");
265 *error = TDM_ERROR_OUT_OF_MEMORY;
270 /* enable the tdm_hwc */
271 drm_data->hwc_mode = 1;
274 LIST_INITHEAD(&drm_data->output_list);
275 LIST_INITHEAD(&drm_data->buffer_list);
277 memset(&drm_func_display, 0, sizeof(drm_func_display));
278 drm_func_display.display_get_capability = drm_display_get_capability;
279 drm_func_display.display_get_pp_capability = drm_display_get_pp_capability;
280 drm_func_display.display_get_outputs = drm_display_get_outputs;
281 drm_func_display.display_get_fd = drm_display_get_fd;
282 drm_func_display.display_handle_events = drm_display_handle_events;
283 drm_func_display.display_create_pp = drm_display_create_pp;
285 memset(&drm_func_output, 0, sizeof(drm_func_output));
286 drm_func_output.output_get_capability = drm_output_get_capability;
287 drm_func_output.output_get_layers = drm_output_get_layers;
288 drm_func_output.output_set_property = drm_output_set_property;
289 drm_func_output.output_get_property = drm_output_get_property;
290 drm_func_output.output_wait_vblank = drm_output_wait_vblank;
291 drm_func_output.output_set_vblank_handler = drm_output_set_vblank_handler;
292 drm_func_output.output_commit = drm_output_commit;
293 drm_func_output.output_set_commit_handler = drm_output_set_commit_handler;
294 drm_func_output.output_set_dpms = drm_output_set_dpms;
295 drm_func_output.output_get_dpms = drm_output_get_dpms;
296 drm_func_output.output_set_mode = drm_output_set_mode;
297 drm_func_output.output_get_mode = drm_output_get_mode;
299 drm_func_output.output_set_status_handler = drm_output_set_status_handler;
302 if (drm_data->hwc_mode) {
303 drm_func_output.output_get_hwc = drm_output_get_hwc;
305 memset(&drm_func_hwc, 0, sizeof(drm_func_hwc));
306 drm_func_hwc.hwc_create_window = drm_hwc_create_window;
307 drm_func_hwc.hwc_get_video_supported_formats = drm_hwc_get_video_supported_formats;
308 drm_func_hwc.hwc_get_video_available_properties = NULL;
309 drm_func_hwc.hwc_get_capabilities = drm_hwc_get_capabilities;
310 drm_func_hwc.hwc_get_available_properties = drm_hwc_get_available_properties;
311 drm_func_hwc.hwc_get_client_target_buffer_queue = drm_hwc_get_client_target_buffer_queue;
312 drm_func_hwc.hwc_set_client_target_buffer = drm_hwc_set_client_target_buffer;
313 drm_func_hwc.hwc_validate = drm_hwc_validate;
314 drm_func_hwc.hwc_get_changed_composition_types = drm_hwc_get_changed_composition_types;
315 drm_func_hwc.hwc_accept_validation = drm_hwc_accept_validation;
316 drm_func_hwc.hwc_commit = drm_hwc_commit;
317 drm_func_hwc.hwc_set_commit_handler = drm_hwc_set_commit_handler;
319 memset(&drm_func_hwc_window, 0, sizeof(drm_func_hwc_window));
320 drm_func_hwc_window.hwc_window_destroy = drm_hwc_window_destroy;
321 drm_func_hwc_window.hwc_window_acquire_buffer_queue = NULL; // no need
322 drm_func_hwc_window.hwc_window_release_buffer_queue = NULL; // no need
323 drm_func_hwc_window.hwc_window_set_composition_type = drm_hwc_window_set_composition_type;
324 drm_func_hwc_window.hwc_window_set_buffer_damage = drm_hwc_window_set_buffer_damage;
325 drm_func_hwc_window.hwc_window_set_info = drm_hwc_window_set_info;
326 drm_func_hwc_window.hwc_window_set_buffer = drm_hwc_window_set_buffer;
327 drm_func_hwc_window.hwc_window_set_property = drm_hwc_window_set_property;
328 drm_func_hwc_window.hwc_window_get_property = drm_hwc_window_get_property;
329 drm_func_hwc_window.hwc_window_get_constraints = drm_hwc_window_get_constraints;
330 drm_func_hwc_window.hwc_window_set_name = drm_hwc_window_set_name;
331 drm_func_hwc_window.hwc_window_set_cursor_image = drm_hwc_window_set_cursor_image;
334 memset(&drm_func_layer, 0, sizeof(drm_func_layer));
335 drm_func_layer.layer_get_capability = drm_layer_get_capability;
336 drm_func_layer.layer_set_property = drm_layer_set_property;
337 drm_func_layer.layer_get_property = drm_layer_get_property;
338 drm_func_layer.layer_set_info = drm_layer_set_info;
339 drm_func_layer.layer_get_info = drm_layer_get_info;
340 drm_func_layer.layer_set_buffer = drm_layer_set_buffer;
341 drm_func_layer.layer_unset_buffer = drm_layer_unset_buffer;
344 memset(&drm_func_pp, 0, sizeof(drm_func_pp));
345 drm_func_pp.pp_destroy = drm_pp_destroy;
346 drm_func_pp.pp_set_info = drm_pp_set_info;
347 drm_func_pp.pp_attach = drm_pp_attach;
348 drm_func_pp.pp_commit = drm_pp_commit;
349 drm_func_pp.pp_set_done_handler = drm_pp_set_done_handler;
352 ret = tdm_backend_register_func_display(dpy, &drm_func_display);
353 if (ret != TDM_ERROR_NONE)
356 ret = tdm_backend_register_func_output(dpy, &drm_func_output);
357 if (ret != TDM_ERROR_NONE)
360 ret = tdm_backend_register_func_layer(dpy, &drm_func_layer);
361 if (ret != TDM_ERROR_NONE)
364 if (drm_data->hwc_mode) {
365 ret = tdm_backend_register_func_hwc(dpy, &drm_func_hwc);
366 if (ret != TDM_ERROR_NONE)
369 ret = tdm_backend_register_func_hwc_window(dpy, &drm_func_hwc_window);
370 if (ret != TDM_ERROR_NONE)
375 ret = tdm_backend_register_func_pp(dpy, &drm_func_pp);
376 if (ret != TDM_ERROR_NONE)
382 /* The drm master fd can be opened by a tbm backend module in
383 * tbm_bufmgr_init() time. In this case, we just get it from tbm.
385 drm_data->drm_fd = tbm_drm_helper_get_master_fd();
386 if (drm_data->drm_fd < 0) {
387 drm_data->drm_fd = _tdm_drm_open_drm();
389 if (drm_data->drm_fd < 0) {
390 ret = TDM_ERROR_OPERATION_FAILED;
394 tbm_drm_helper_set_tbm_master_fd(drm_data->drm_fd);
397 TDM_INFO("master fd: %d", drm_data->drm_fd);
400 _tdm_drm_udev_init(drm_data);
403 #if LIBDRM_MAJOR_VERSION >= 2 && LIBDRM_MINOR_VERSION >= 4 && LIBDRM_MICRO_VERSION >= 47
404 if (drmSetClientCap(drm_data->drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1) < 0) {
405 TDM_WRN("Set DRM_CLIENT_CAP_UNIVERSAL_PLANES failed");
407 TDM_INFO("has universal planes");
408 drm_data->has_universal_plane = 1;
412 drm_data->mode_res = drmModeGetResources(drm_data->drm_fd);
413 if (!drm_data->mode_res) {
414 TDM_ERR("no drm resource: %m");
415 ret = TDM_ERROR_OPERATION_FAILED;
419 drm_data->plane_res = drmModeGetPlaneResources(drm_data->drm_fd);
420 if (!drm_data->plane_res) {
421 TDM_ERR("no drm plane resource: %m");
422 ret = TDM_ERROR_OPERATION_FAILED;
426 if (drm_data->plane_res->count_planes <= 0) {
427 TDM_ERR("no drm plane resource");
428 ret = TDM_ERROR_OPERATION_FAILED;
432 ret = tdm_drm_display_create_output_list(drm_data);
433 if (ret != TDM_ERROR_NONE)
436 ret = tdm_drm_display_create_layer_list(drm_data);
437 if (ret != TDM_ERROR_NONE)
441 *error = TDM_ERROR_NONE;
443 TDM_INFO("init success!");
445 return (tdm_backend_data *)drm_data;
450 tdm_drm_deinit(drm_data);
452 TDM_ERR("init failed!");
456 tdm_backend_module tdm_backend_module_data = {
459 TDM_BACKEND_SET_ABI_VERSION(1, 1),