1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2012 Red Hat 4 */ 5 6 #include <linux/module.h> 7 8 #include <drm/drm_crtc_helper.h> 9 #include <drm/drm_drv.h> 10 #include <drm/drm_fb_helper.h> 11 #include <drm/drm_file.h> 12 #include <drm/drm_gem_shmem_helper.h> 13 #include <drm/drm_ioctl.h> 14 #include <drm/drm_probe_helper.h> 15 #include <drm/drm_print.h> 16 17 #include "udl_drv.h" 18 19 static int udl_usb_suspend(struct usb_interface *interface, 20 pm_message_t message) 21 { 22 struct drm_device *dev = usb_get_intfdata(interface); 23 24 return drm_mode_config_helper_suspend(dev); 25 } 26 27 static int udl_usb_resume(struct usb_interface *interface) 28 { 29 struct drm_device *dev = usb_get_intfdata(interface); 30 31 return drm_mode_config_helper_resume(dev); 32 } 33 34 DEFINE_DRM_GEM_FOPS(udl_driver_fops); 35 36 static void udl_driver_release(struct drm_device *dev) 37 { 38 udl_fini(dev); 39 udl_modeset_cleanup(dev); 40 drm_dev_fini(dev); 41 kfree(dev); 42 } 43 44 static struct drm_driver driver = { 45 .driver_features = DRIVER_ATOMIC | DRIVER_GEM | DRIVER_MODESET, 46 .release = udl_driver_release, 47 48 /* gem hooks */ 49 .gem_create_object = udl_driver_gem_create_object, 50 51 .fops = &udl_driver_fops, 52 DRM_GEM_SHMEM_DRIVER_OPS, 53 54 .name = DRIVER_NAME, 55 .desc = DRIVER_DESC, 56 .date = DRIVER_DATE, 57 .major = DRIVER_MAJOR, 58 .minor = DRIVER_MINOR, 59 .patchlevel = DRIVER_PATCHLEVEL, 60 }; 61 62 static struct udl_device *udl_driver_create(struct usb_interface *interface) 63 { 64 struct usb_device *udev = interface_to_usbdev(interface); 65 struct udl_device *udl; 66 int r; 67 68 udl = kzalloc(sizeof(*udl), GFP_KERNEL); 69 if (!udl) 70 return ERR_PTR(-ENOMEM); 71 72 r = drm_dev_init(&udl->drm, &driver, &interface->dev); 73 if (r) { 74 kfree(udl); 75 return ERR_PTR(r); 76 } 77 78 udl->udev = udev; 79 udl->drm.dev_private = udl; 80 81 r = udl_init(udl); 82 if (r) { 83 drm_dev_fini(&udl->drm); 84 kfree(udl); 85 return ERR_PTR(r); 86 } 87 88 usb_set_intfdata(interface, udl); 89 return udl; 90 } 91 92 static int udl_usb_probe(struct usb_interface *interface, 93 const struct usb_device_id *id) 94 { 95 int r; 96 struct udl_device *udl; 97 98 udl = udl_driver_create(interface); 99 if (IS_ERR(udl)) 100 return PTR_ERR(udl); 101 102 r = drm_dev_register(&udl->drm, 0); 103 if (r) 104 goto err_free; 105 106 DRM_INFO("Initialized udl on minor %d\n", udl->drm.primary->index); 107 108 r = drm_fbdev_generic_setup(&udl->drm, 0); 109 if (r) 110 goto err_drm_dev_unregister; 111 112 return 0; 113 114 err_drm_dev_unregister: 115 drm_dev_unregister(&udl->drm); 116 err_free: 117 drm_dev_put(&udl->drm); 118 return r; 119 } 120 121 static void udl_usb_disconnect(struct usb_interface *interface) 122 { 123 struct drm_device *dev = usb_get_intfdata(interface); 124 125 drm_kms_helper_poll_disable(dev); 126 udl_drop_usb(dev); 127 drm_dev_unplug(dev); 128 drm_dev_put(dev); 129 } 130 131 /* 132 * There are many DisplayLink-based graphics products, all with unique PIDs. 133 * So we match on DisplayLink's VID + Vendor-Defined Interface Class (0xff) 134 * We also require a match on SubClass (0x00) and Protocol (0x00), 135 * which is compatible with all known USB 2.0 era graphics chips and firmware, 136 * but allows DisplayLink to increment those for any future incompatible chips 137 */ 138 static const struct usb_device_id id_table[] = { 139 {.idVendor = 0x17e9, .bInterfaceClass = 0xff, 140 .bInterfaceSubClass = 0x00, 141 .bInterfaceProtocol = 0x00, 142 .match_flags = USB_DEVICE_ID_MATCH_VENDOR | 143 USB_DEVICE_ID_MATCH_INT_CLASS | 144 USB_DEVICE_ID_MATCH_INT_SUBCLASS | 145 USB_DEVICE_ID_MATCH_INT_PROTOCOL,}, 146 {}, 147 }; 148 MODULE_DEVICE_TABLE(usb, id_table); 149 150 static struct usb_driver udl_driver = { 151 .name = "udl", 152 .probe = udl_usb_probe, 153 .disconnect = udl_usb_disconnect, 154 .suspend = udl_usb_suspend, 155 .resume = udl_usb_resume, 156 .id_table = id_table, 157 }; 158 module_usb_driver(udl_driver); 159 MODULE_LICENSE("GPL"); 160