drm/udl: implement usb_driver suspend/resume.
authorHaixia Shi <hshi@chromium.org>
Tue, 30 Aug 2016 21:50:21 +0000 (14:50 -0700)
committerSean Paul <seanpaul@chromium.org>
Tue, 6 Sep 2016 17:56:42 +0000 (13:56 -0400)
The usb_driver suspend and resume function pointers must be populated
to prevent forced unbinding of USB interface driver. See usb/core/driver.c:
unbind_no_pm_drivers_interfaces().

Restore mode and damage the entire frame buffer upon resume.

TEST=suspend and resume with the same UDL device connected
TEST=suspend with UDL, unplug UDL and resume
TEST=suspend with UDL, unplug and connect another UDL device then resume

Signed-off-by: Haixia Shi <hshi@chromium.org>
Reviewed-by: Stéphane Marchesin <marcheu@chromium.org>
[seanpaul fixed checkpatch warnings and gave marcheu his é back]
Signed-off-by: Sean Paul <seanpaul@chromium.org>
Link: http://patchwork.freedesktop.org/patch/msgid/1472593821-38429-2-git-send-email-hshi@chromium.org
drivers/gpu/drm/udl/udl_drv.c
drivers/gpu/drm/udl/udl_drv.h
drivers/gpu/drm/udl/udl_modeset.c

index 17d34e0..f0851db 100644 (file)
@@ -16,6 +16,20 @@ static int udl_driver_set_busid(struct drm_device *d, struct drm_master *m)
        return 0;
 }
 
+static int udl_usb_suspend(struct usb_interface *interface,
+                          pm_message_t message)
+{
+       return 0;
+}
+
+static int udl_usb_resume(struct usb_interface *interface)
+{
+       struct drm_device *dev = usb_get_intfdata(interface);
+
+       udl_modeset_restore(dev);
+       return 0;
+}
+
 static const struct vm_operations_struct udl_gem_vm_ops = {
        .fault = udl_gem_fault,
        .open = drm_gem_vm_open,
@@ -122,6 +136,8 @@ static struct usb_driver udl_driver = {
        .name = "udl",
        .probe = udl_usb_probe,
        .disconnect = udl_usb_disconnect,
+       .suspend = udl_usb_suspend,
+       .resume = udl_usb_resume,
        .id_table = id_table,
 };
 module_usb_driver(udl_driver);
index 0b03d34..f338a57 100644 (file)
@@ -52,6 +52,7 @@ struct udl_device {
        struct device *dev;
        struct drm_device *ddev;
        struct usb_device *udev;
+       struct drm_crtc *crtc;
 
        int sku_pixel_limit;
 
@@ -87,6 +88,7 @@ struct udl_framebuffer {
 
 /* modeset */
 int udl_modeset_init(struct drm_device *dev);
+void udl_modeset_restore(struct drm_device *dev);
 void udl_modeset_cleanup(struct drm_device *dev);
 int udl_connector_init(struct drm_device *dev, struct drm_encoder *encoder);
 
index 7369512..f2b2481 100644 (file)
@@ -309,6 +309,8 @@ static int udl_crtc_mode_set(struct drm_crtc *crtc,
        char *wrptr;
        int color_depth = 0;
 
+       udl->crtc = crtc;
+
        buf = (char *)udl->mode_buf;
 
        /* for now we just clip 24 -> 16 - if we fix that fix this */
@@ -450,6 +452,18 @@ int udl_modeset_init(struct drm_device *dev)
        return 0;
 }
 
+void udl_modeset_restore(struct drm_device *dev)
+{
+       struct udl_device *udl = dev->dev_private;
+       struct udl_framebuffer *ufb;
+
+       if (!udl->crtc || !udl->crtc->primary->fb)
+               return;
+       udl_crtc_commit(udl->crtc);
+       ufb = to_udl_fb(udl->crtc->primary->fb);
+       udl_handle_damage(ufb, 0, 0, ufb->base.width, ufb->base.height);
+}
+
 void udl_modeset_cleanup(struct drm_device *dev)
 {
        drm_mode_config_cleanup(dev);