drm/kms/fb: add polling support for when nothing is connected.
[safe/jmp/linux-2.6] / drivers / gpu / drm / drm_fb_helper.c
index 6374e9b..3312092 100644 (file)
@@ -1308,9 +1308,14 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper)
        /*
         * we shouldn't end up with no modes here.
         */
-       if (count == 0)
-               printk(KERN_INFO "No connectors reported connected with modes\n");
-
+       if (count == 0) {
+               if (fb_helper->poll_enabled) {
+                       delayed_slow_work_enqueue(&fb_helper->output_poll_slow_work,
+                                                 5*HZ);
+                       printk(KERN_INFO "No connectors reported connected with modes - started polling\n");
+               } else
+                       printk(KERN_INFO "No connectors reported connected with modes\n");
+       }
        drm_setup_crtcs(fb_helper);
 
        return 0;
@@ -1318,15 +1323,80 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper)
 EXPORT_SYMBOL(drm_fb_helper_initial_config);
 
 bool drm_helper_fb_hotplug_event(struct drm_fb_helper *fb_helper,
-                                u32 max_width, u32 max_height)
+                                u32 max_width, u32 max_height, bool polled)
 {
+       int count = 0;
+       int ret;
        DRM_DEBUG_KMS("\n");
 
-       drm_fb_helper_probe_connector_modes(fb_helper, max_width,
+       count = drm_fb_helper_probe_connector_modes(fb_helper, max_width,
                                                    max_height);
-
+       if (fb_helper->poll_enabled && !polled) {
+               if (count) {
+                       delayed_slow_work_cancel(&fb_helper->output_poll_slow_work);
+               } else {
+                       ret = delayed_slow_work_enqueue(&fb_helper->output_poll_slow_work, 5*HZ);
+               }
+       }
        drm_setup_crtcs(fb_helper);
 
        return true;
 }
 EXPORT_SYMBOL(drm_helper_fb_hotplug_event);
+
+static void output_poll_execute(struct slow_work *work)
+{
+       struct delayed_slow_work *delayed_work = container_of(work, struct delayed_slow_work, work);
+       struct drm_fb_helper *fb_helper = container_of(delayed_work, struct drm_fb_helper, output_poll_slow_work);
+       struct drm_device *dev = fb_helper->dev;
+       struct drm_connector *connector;
+       enum drm_connector_status old_status, status;
+       bool repoll = true, changed = false;
+       int ret;
+
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               old_status = connector->status;
+               status = connector->funcs->detect(connector);
+               if (old_status != status) {
+                       changed = true;
+                       /* something changed */
+               }
+               if (status == connector_status_connected) {
+                       DRM_DEBUG("%s is connected - stop polling\n", drm_get_connector_name(connector));
+                       repoll = false;
+               }
+       }
+
+       if (repoll) {
+               ret = delayed_slow_work_enqueue(delayed_work, 5*HZ);
+               if (ret)
+                       DRM_ERROR("delayed enqueue failed %d\n", ret);
+       }
+
+       if (changed) {
+               if (fb_helper->fb_poll_changed)
+                       fb_helper->fb_poll_changed(fb_helper);
+       }
+}
+
+struct slow_work_ops output_poll_ops = {
+       .execute = output_poll_execute,
+};
+
+void drm_fb_helper_poll_init(struct drm_fb_helper *fb_helper)
+{
+       int ret;
+
+       ret = slow_work_register_user(THIS_MODULE);
+
+       delayed_slow_work_init(&fb_helper->output_poll_slow_work, &output_poll_ops);
+       fb_helper->poll_enabled = true;
+}
+EXPORT_SYMBOL(drm_fb_helper_poll_init);
+
+void drm_fb_helper_poll_fini(struct drm_fb_helper *fb_helper)
+{
+       delayed_slow_work_cancel(&fb_helper->output_poll_slow_work);
+       slow_work_unregister_user(THIS_MODULE);
+}
+EXPORT_SYMBOL(drm_fb_helper_poll_fini);