drm_output_set_status_handler 45/65545/1 accepted/tizen/common/20160414.142620 accepted/tizen/ivi/20160415.014823 accepted/tizen/mobile/20160415.014843 accepted/tizen/tv/20160415.014740 accepted/tizen/wearable/20160415.014804 submit/tizen/20160414.040521
authorBoram Park <boram1288.park@samsung.com>
Mon, 11 Apr 2016 03:01:09 +0000 (12:01 +0900)
committerBoram Park <boram1288.park@samsung.com>
Mon, 11 Apr 2016 10:39:57 +0000 (19:39 +0900)
Change-Id: I4d71adee08f09b5b8e26bedff19c716323b4277d

src/tdm_drm.c
src/tdm_drm.h
src/tdm_drm_display.c

index aaf3b45..8ac23d4 100644 (file)
@@ -64,6 +64,107 @@ _tdm_find_primary_gpu(void)
        udev_enumerate_unref(e);
        return drm_device;
 }
+
+static tdm_error
+_tdm_drm_udev_fd_handler(int fd, tdm_event_loop_mask mask, void *user_data)
+{
+       tdm_drm_data *edata = (tdm_drm_data*)user_data;
+       struct udev_device *dev;
+       const char *hotplug;
+       struct stat s;
+       dev_t udev_devnum;
+       int ret;
+
+       dev = udev_monitor_receive_device(edata->uevent_monitor);
+       if (!dev) {
+               TDM_ERR("couldn't receive device");
+               return TDM_ERROR_OPERATION_FAILED;
+       }
+
+       udev_devnum = udev_device_get_devnum(dev);
+
+       ret = fstat(edata->drm_fd, &s);
+       if (ret == -1) {
+               TDM_ERR("fstat failed");
+               return TDM_ERROR_OPERATION_FAILED;
+       }
+
+       hotplug = udev_device_get_property_value(dev, "HOTPLUG");
+
+       if (memcmp(&s.st_rdev, &udev_devnum, sizeof (dev_t)) == 0 &&
+               hotplug && atoi(hotplug) == 1)
+       {
+               TDM_INFO("HotPlug");
+               tdm_drm_display_update_output_status(edata);
+       }
+
+       udev_device_unref(dev);
+
+       return TDM_ERROR_NONE;
+}
+
+static void
+_tdm_drm_udev_init(tdm_drm_data *edata)
+{
+       struct udev *u = NULL;
+       struct udev_monitor *mon = NULL;
+
+       u = udev_new();
+       if (!u) {
+               TDM_ERR("couldn't create udev");
+               goto failed;
+       }
+
+       mon = udev_monitor_new_from_netlink(u, "udev");
+       if (!mon) {
+               TDM_ERR("couldn't create udev monitor");
+               goto failed;
+       }
+
+       if (udev_monitor_filter_add_match_subsystem_devtype(mon, "drm", "drm_minor") > 0 ||
+           udev_monitor_enable_receiving(mon) < 0) {
+               TDM_ERR("add match subsystem failed");
+               goto failed;
+       }
+
+       edata->uevent_source =
+               tdm_event_loop_add_fd_handler(edata->dpy, udev_monitor_get_fd(mon),
+                                             TDM_EVENT_LOOP_READABLE,
+                                             _tdm_drm_udev_fd_handler,
+                                             edata, NULL);
+       if (!edata->uevent_source) {
+               TDM_ERR("couldn't create udev event source");
+               goto failed;
+       }
+
+       edata->uevent_monitor = mon;
+
+       TDM_INFO("hotplug monitor created");
+
+       return;
+failed:
+       if (mon)
+               udev_monitor_unref(mon);
+       if (u)
+               udev_unref(u);
+}
+
+static void
+_tdm_drm_udev_deinit(tdm_drm_data *edata)
+{
+       if (edata->uevent_source) {
+               tdm_event_loop_source_remove(edata->uevent_source);
+               edata->uevent_source = NULL;
+       }
+
+       if (edata->uevent_monitor) {
+               struct udev *u = udev_monitor_get_udev(edata->uevent_monitor);
+               udev_monitor_unref(edata->uevent_monitor);
+               udev_unref(u);
+               edata->uevent_monitor = NULL;
+               TDM_INFO("hotplug monitor destroyed");
+       }
+}
 #endif
 
 static int
@@ -111,6 +212,10 @@ tdm_drm_deinit(tdm_backend_data *bdata)
 
        TDM_INFO("deinit");
 
+#ifdef HAVE_UDEV
+       _tdm_drm_udev_deinit(drm_data);
+#endif
+
        tdm_drm_display_destroy_output_list(drm_data);
 
        if (drm_data->plane_res)
@@ -181,6 +286,9 @@ tdm_drm_init(tdm_display *dpy, tdm_error *error)
        drm_func_output.output_get_dpms = drm_output_get_dpms;
        drm_func_output.output_set_mode = drm_output_set_mode;
        drm_func_output.output_get_mode = drm_output_get_mode;
+#ifdef HAVE_UDEV
+       drm_func_output.output_set_status_handler = drm_output_set_status_handler;
+#endif
 
        memset(&drm_func_layer, 0, sizeof(drm_func_layer));
        drm_func_layer.layer_get_capability = drm_layer_get_capability;
@@ -237,6 +345,10 @@ tdm_drm_init(tdm_display *dpy, tdm_error *error)
        /* To share the drm master fd with other modules in display server side. */
        tdm_helper_set_fd("TDM_DRM_MASTER_FD", drm_data->drm_fd);
 
+#ifdef HAVE_UDEV
+       _tdm_drm_udev_init(drm_data);
+#endif
+
 #if LIBDRM_MAJOR_VERSION >= 2 && LIBDRM_MINOR_VERSION >= 4  && LIBDRM_MICRO_VERSION >= 47
        if (drmSetClientCap(drm_data->drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1) < 0) {
                TDM_WRN("Set DRM_CLIENT_CAP_UNIVERSAL_PLANES failed");
index 952f959..333c670 100644 (file)
 #include <tdm_log.h>
 #include <tdm_list.h>
 
+#if HAVE_UDEV
+#include <libudev.h>
+#endif
+
 /* drm backend functions (display) */
 tdm_error    drm_display_get_capabilitiy(tdm_backend_data *bdata, tdm_caps_display *caps);
 tdm_error    drm_display_get_pp_capability(tdm_backend_data *bdata, tdm_caps_pp *caps);
@@ -40,6 +44,7 @@ tdm_error    drm_output_set_dpms(tdm_output *output, tdm_output_dpms dpms_value)
 tdm_error    drm_output_get_dpms(tdm_output *output, tdm_output_dpms *dpms_value);
 tdm_error    drm_output_set_mode(tdm_output *output, const tdm_output_mode *mode);
 tdm_error    drm_output_get_mode(tdm_output *output, const tdm_output_mode **mode);
+tdm_error    drm_output_set_status_handler(tdm_output *output, tdm_output_status_handler func, void *user_data);
 tdm_error    drm_layer_get_capability(tdm_layer *layer, tdm_caps_layer *caps);
 tdm_error    drm_layer_set_property(tdm_layer *layer, unsigned int id, tdm_value value);
 tdm_error    drm_layer_get_property(tdm_layer *layer, unsigned int id, tdm_value *value);
@@ -99,6 +104,11 @@ typedef struct _tdm_drm_data
 
     int has_universal_plane;
 
+#if HAVE_UDEV
+    struct udev_monitor *uevent_monitor;
+    tdm_event_loop_source *uevent_source;
+#endif
+
     drmModeResPtr mode_res;
     drmModePlaneResPtr plane_res;
 
@@ -109,6 +119,7 @@ typedef struct _tdm_drm_data
 uint32_t     tdm_drm_format_to_drm_format(tbm_format format);
 tbm_format   tdm_drm_format_to_tbm_format(uint32_t format);
 
+void         tdm_drm_display_update_output_status(tdm_drm_data *drm_data);
 tdm_error    tdm_drm_display_create_output_list(tdm_drm_data *drm_data);
 void         tdm_drm_display_destroy_output_list(tdm_drm_data *drm_data);
 tdm_error    tdm_drm_display_create_layer_list(tdm_drm_data *drm_data);
index 3ec906c..c8cab14 100644 (file)
@@ -57,6 +57,8 @@ struct _tdm_drm_output_data {
        tdm_output_commit_handler commit_func;
 
        tdm_output_conn_status status;
+       tdm_output_status_handler status_func;
+       void *status_user_data;
 
        int mode_changed;
        const tdm_output_mode *current_mode;
@@ -641,6 +643,54 @@ tdm_drm_display_destroy_output_list(tdm_drm_data *drm_data)
        }
 }
 
+static tdm_error
+_tdm_drm_output_update_status(tdm_drm_output_data *output_data,
+                              tdm_output_conn_status status)
+{
+       RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
+
+       if (output_data->status == status)
+               return TDM_ERROR_NONE;
+
+       output_data->status = status;
+
+       if (output_data->status_func)
+               output_data->status_func(output_data, status,
+                                        output_data->status_user_data);
+
+       return TDM_ERROR_NONE;
+}
+
+void
+tdm_drm_display_update_output_status(tdm_drm_data *drm_data)
+{
+       tdm_drm_output_data *output_data = NULL;
+
+       if (LIST_IS_EMPTY(&drm_data->output_list))
+               return;
+
+       LIST_FOR_EACH_ENTRY(output_data, &drm_data->output_list, link) {
+               drmModeConnectorPtr connector;
+               tdm_output_conn_status new_status;
+
+               connector = drmModeGetConnector(drm_data->drm_fd,
+                                               output_data->connector_id);
+               if (!connector) {
+                       TDM_ERR("no connector: %d", output_data->connector_id);
+                       continue;
+               }
+
+               if (connector->connection == DRM_MODE_CONNECTED)
+                       new_status = TDM_OUTPUT_CONN_STATUS_CONNECTED;
+               else
+                       new_status = TDM_OUTPUT_CONN_STATUS_DISCONNECTED;
+
+               _tdm_drm_output_update_status(output_data, new_status);
+
+               drmModeFreeConnector(connector);
+       }
+}
+
 tdm_error
 tdm_drm_display_create_output_list(tdm_drm_data *drm_data)
 {
@@ -1314,6 +1364,22 @@ drm_output_get_mode(tdm_output *output, const tdm_output_mode **mode)
 }
 
 tdm_error
+drm_output_set_status_handler(tdm_output *output,
+                              tdm_output_status_handler func,
+                              void *user_data)
+{
+       tdm_drm_output_data *output_data = output;
+
+       RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
+       RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
+
+       output_data->status_func = func;
+       output_data->status_user_data = user_data;
+
+       return TDM_ERROR_NONE;
+}
+
+tdm_error
 drm_layer_get_capability(tdm_layer *layer, tdm_caps_layer *caps)
 {
        tdm_drm_layer_data *layer_data = layer;