GNU Linux-libre 4.19.211-gnu1
[releases.git] / drivers / gpu / drm / udl / udl_drv.c
1 /*
2  * Copyright (C) 2012 Red Hat
3  *
4  * This file is subject to the terms and conditions of the GNU General Public
5  * License v2. See the file COPYING in the main directory of this archive for
6  * more details.
7  */
8
9 #include <linux/module.h>
10 #include <drm/drmP.h>
11 #include <drm/drm_crtc_helper.h>
12 #include "udl_drv.h"
13
14 static int udl_usb_suspend(struct usb_interface *interface,
15                            pm_message_t message)
16 {
17         struct drm_device *dev = usb_get_intfdata(interface);
18
19         drm_kms_helper_poll_disable(dev);
20         return 0;
21 }
22
23 static int udl_usb_resume(struct usb_interface *interface)
24 {
25         struct drm_device *dev = usb_get_intfdata(interface);
26
27         drm_kms_helper_poll_enable(dev);
28         udl_modeset_restore(dev);
29         return 0;
30 }
31
32 static const struct vm_operations_struct udl_gem_vm_ops = {
33         .fault = udl_gem_fault,
34         .open = drm_gem_vm_open,
35         .close = drm_gem_vm_close,
36 };
37
38 static const struct file_operations udl_driver_fops = {
39         .owner = THIS_MODULE,
40         .open = drm_open,
41         .mmap = udl_drm_gem_mmap,
42         .poll = drm_poll,
43         .read = drm_read,
44         .unlocked_ioctl = drm_ioctl,
45         .release = drm_release,
46         .compat_ioctl = drm_compat_ioctl,
47         .llseek = noop_llseek,
48 };
49
50 static void udl_driver_release(struct drm_device *dev)
51 {
52         udl_fini(dev);
53         udl_modeset_cleanup(dev);
54         drm_dev_fini(dev);
55         kfree(dev);
56 }
57
58 static struct drm_driver driver = {
59         .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME,
60         .release = udl_driver_release,
61
62         /* gem hooks */
63         .gem_free_object_unlocked = udl_gem_free_object,
64         .gem_vm_ops = &udl_gem_vm_ops,
65
66         .dumb_create = udl_dumb_create,
67         .dumb_map_offset = udl_gem_mmap,
68         .fops = &udl_driver_fops,
69
70         .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
71         .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
72         .gem_prime_export = udl_gem_prime_export,
73         .gem_prime_import = udl_gem_prime_import,
74
75         .name = DRIVER_NAME,
76         .desc = DRIVER_DESC,
77         .date = DRIVER_DATE,
78         .major = DRIVER_MAJOR,
79         .minor = DRIVER_MINOR,
80         .patchlevel = DRIVER_PATCHLEVEL,
81 };
82
83 static struct udl_device *udl_driver_create(struct usb_interface *interface)
84 {
85         struct usb_device *udev = interface_to_usbdev(interface);
86         struct udl_device *udl;
87         int r;
88
89         udl = kzalloc(sizeof(*udl), GFP_KERNEL);
90         if (!udl)
91                 return ERR_PTR(-ENOMEM);
92
93         r = drm_dev_init(&udl->drm, &driver, &interface->dev);
94         if (r) {
95                 kfree(udl);
96                 return ERR_PTR(r);
97         }
98
99         udl->udev = udev;
100         udl->drm.dev_private = udl;
101
102         r = udl_init(udl);
103         if (r) {
104                 drm_dev_fini(&udl->drm);
105                 kfree(udl);
106                 return ERR_PTR(r);
107         }
108
109         usb_set_intfdata(interface, udl);
110         return udl;
111 }
112
113 static int udl_usb_probe(struct usb_interface *interface,
114                          const struct usb_device_id *id)
115 {
116         int r;
117         struct udl_device *udl;
118
119         udl = udl_driver_create(interface);
120         if (IS_ERR(udl))
121                 return PTR_ERR(udl);
122
123         r = drm_dev_register(&udl->drm, 0);
124         if (r)
125                 goto err_free;
126
127         DRM_INFO("Initialized udl on minor %d\n", udl->drm.primary->index);
128
129         return 0;
130
131 err_free:
132         drm_dev_put(&udl->drm);
133         return r;
134 }
135
136 static void udl_usb_disconnect(struct usb_interface *interface)
137 {
138         struct drm_device *dev = usb_get_intfdata(interface);
139
140         drm_kms_helper_poll_disable(dev);
141         udl_fbdev_unplug(dev);
142         udl_drop_usb(dev);
143         drm_dev_unplug(dev);
144 }
145
146 /*
147  * There are many DisplayLink-based graphics products, all with unique PIDs.
148  * So we match on DisplayLink's VID + Vendor-Defined Interface Class (0xff)
149  * We also require a match on SubClass (0x00) and Protocol (0x00),
150  * which is compatible with all known USB 2.0 era graphics chips and firmware,
151  * but allows DisplayLink to increment those for any future incompatible chips
152  */
153 static const struct usb_device_id id_table[] = {
154         {.idVendor = 0x17e9, .bInterfaceClass = 0xff,
155          .bInterfaceSubClass = 0x00,
156          .bInterfaceProtocol = 0x00,
157          .match_flags = USB_DEVICE_ID_MATCH_VENDOR |
158                         USB_DEVICE_ID_MATCH_INT_CLASS |
159                         USB_DEVICE_ID_MATCH_INT_SUBCLASS |
160                         USB_DEVICE_ID_MATCH_INT_PROTOCOL,},
161         {},
162 };
163 MODULE_DEVICE_TABLE(usb, id_table);
164
165 static struct usb_driver udl_driver = {
166         .name = "udl",
167         .probe = udl_usb_probe,
168         .disconnect = udl_usb_disconnect,
169         .suspend = udl_usb_suspend,
170         .resume = udl_usb_resume,
171         .id_table = id_table,
172 };
173 module_usb_driver(udl_driver);
174 MODULE_LICENSE("GPL");