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_drv.h> |
9 | #include <drm/drm_fbdev_generic.h> |
10 | #include <drm/drm_file.h> |
11 | #include <drm/drm_gem_shmem_helper.h> |
12 | #include <drm/drm_managed.h> |
13 | #include <drm/drm_modeset_helper.h> |
14 | #include <drm/drm_ioctl.h> |
15 | #include <drm/drm_probe_helper.h> |
16 | #include <drm/drm_print.h> |
17 | |
18 | #include "udl_drv.h" |
19 | |
20 | static int udl_usb_suspend(struct usb_interface *interface, |
21 | pm_message_t message) |
22 | { |
23 | struct drm_device *dev = usb_get_intfdata(intf: interface); |
24 | int ret; |
25 | |
26 | ret = drm_mode_config_helper_suspend(dev); |
27 | if (ret) |
28 | return ret; |
29 | |
30 | udl_sync_pending_urbs(dev); |
31 | return 0; |
32 | } |
33 | |
34 | static int udl_usb_resume(struct usb_interface *interface) |
35 | { |
36 | struct drm_device *dev = usb_get_intfdata(intf: interface); |
37 | |
38 | return drm_mode_config_helper_resume(dev); |
39 | } |
40 | |
41 | static int udl_usb_reset_resume(struct usb_interface *interface) |
42 | { |
43 | struct drm_device *dev = usb_get_intfdata(intf: interface); |
44 | struct udl_device *udl = to_udl(dev); |
45 | |
46 | udl_select_std_channel(udl); |
47 | |
48 | return drm_mode_config_helper_resume(dev); |
49 | } |
50 | |
51 | /* |
52 | * FIXME: Dma-buf sharing requires DMA support by the importing device. |
53 | * This function is a workaround to make USB devices work as well. |
54 | * See todo.rst for how to fix the issue in the dma-buf framework. |
55 | */ |
56 | static struct drm_gem_object *udl_driver_gem_prime_import(struct drm_device *dev, |
57 | struct dma_buf *dma_buf) |
58 | { |
59 | struct udl_device *udl = to_udl(dev); |
60 | |
61 | if (!udl->dmadev) |
62 | return ERR_PTR(error: -ENODEV); |
63 | |
64 | return drm_gem_prime_import_dev(dev, dma_buf, attach_dev: udl->dmadev); |
65 | } |
66 | |
67 | DEFINE_DRM_GEM_FOPS(udl_driver_fops); |
68 | |
69 | static const struct drm_driver driver = { |
70 | .driver_features = DRIVER_ATOMIC | DRIVER_GEM | DRIVER_MODESET, |
71 | |
72 | /* GEM hooks */ |
73 | .fops = &udl_driver_fops, |
74 | DRM_GEM_SHMEM_DRIVER_OPS, |
75 | .gem_prime_import = udl_driver_gem_prime_import, |
76 | |
77 | .name = DRIVER_NAME, |
78 | .desc = DRIVER_DESC, |
79 | .date = DRIVER_DATE, |
80 | .major = DRIVER_MAJOR, |
81 | .minor = DRIVER_MINOR, |
82 | .patchlevel = DRIVER_PATCHLEVEL, |
83 | }; |
84 | |
85 | static struct udl_device *udl_driver_create(struct usb_interface *interface) |
86 | { |
87 | struct udl_device *udl; |
88 | int r; |
89 | |
90 | udl = devm_drm_dev_alloc(&interface->dev, &driver, |
91 | struct udl_device, drm); |
92 | if (IS_ERR(ptr: udl)) |
93 | return udl; |
94 | |
95 | r = udl_init(udl); |
96 | if (r) |
97 | return ERR_PTR(error: r); |
98 | |
99 | usb_set_intfdata(intf: interface, data: udl); |
100 | |
101 | return udl; |
102 | } |
103 | |
104 | static int udl_usb_probe(struct usb_interface *interface, |
105 | const struct usb_device_id *id) |
106 | { |
107 | int r; |
108 | struct udl_device *udl; |
109 | |
110 | udl = udl_driver_create(interface); |
111 | if (IS_ERR(ptr: udl)) |
112 | return PTR_ERR(ptr: udl); |
113 | |
114 | r = drm_dev_register(dev: &udl->drm, flags: 0); |
115 | if (r) |
116 | return r; |
117 | |
118 | DRM_INFO("Initialized udl on minor %d\n" , udl->drm.primary->index); |
119 | |
120 | drm_fbdev_generic_setup(dev: &udl->drm, preferred_bpp: 0); |
121 | |
122 | return 0; |
123 | } |
124 | |
125 | static void udl_usb_disconnect(struct usb_interface *interface) |
126 | { |
127 | struct drm_device *dev = usb_get_intfdata(intf: interface); |
128 | |
129 | drm_kms_helper_poll_fini(dev); |
130 | udl_drop_usb(dev); |
131 | drm_dev_unplug(dev); |
132 | } |
133 | |
134 | /* |
135 | * There are many DisplayLink-based graphics products, all with unique PIDs. |
136 | * So we match on DisplayLink's VID + Vendor-Defined Interface Class (0xff) |
137 | * We also require a match on SubClass (0x00) and Protocol (0x00), |
138 | * which is compatible with all known USB 2.0 era graphics chips and firmware, |
139 | * but allows DisplayLink to increment those for any future incompatible chips |
140 | */ |
141 | static const struct usb_device_id id_table[] = { |
142 | {.idVendor = 0x17e9, .bInterfaceClass = 0xff, |
143 | .bInterfaceSubClass = 0x00, |
144 | .bInterfaceProtocol = 0x00, |
145 | .match_flags = USB_DEVICE_ID_MATCH_VENDOR | |
146 | USB_DEVICE_ID_MATCH_INT_CLASS | |
147 | USB_DEVICE_ID_MATCH_INT_SUBCLASS | |
148 | USB_DEVICE_ID_MATCH_INT_PROTOCOL,}, |
149 | {}, |
150 | }; |
151 | MODULE_DEVICE_TABLE(usb, id_table); |
152 | |
153 | static struct usb_driver udl_driver = { |
154 | .name = "udl" , |
155 | .probe = udl_usb_probe, |
156 | .disconnect = udl_usb_disconnect, |
157 | .suspend = udl_usb_suspend, |
158 | .resume = udl_usb_resume, |
159 | .reset_resume = udl_usb_reset_resume, |
160 | .id_table = id_table, |
161 | }; |
162 | module_usb_driver(udl_driver); |
163 | MODULE_LICENSE("GPL" ); |
164 | |