xref: /openbmc/linux/drivers/gpu/drm/udl/udl_drv.c (revision 3381df09)
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