diff options
Diffstat (limited to 'drivers/gpu/drm/drm_ioctl.c')
-rw-r--r-- | drivers/gpu/drm/drm_ioctl.c | 140 |
1 files changed, 106 insertions, 34 deletions
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 9b9ff46c2378..7b03b197fc00 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c | |||
@@ -64,6 +64,19 @@ int drm_getunique(struct drm_device *dev, void *data, | |||
64 | return 0; | 64 | return 0; |
65 | } | 65 | } |
66 | 66 | ||
67 | static void | ||
68 | drm_unset_busid(struct drm_device *dev, | ||
69 | struct drm_master *master) | ||
70 | { | ||
71 | kfree(dev->devname); | ||
72 | dev->devname = NULL; | ||
73 | |||
74 | kfree(master->unique); | ||
75 | master->unique = NULL; | ||
76 | master->unique_len = 0; | ||
77 | master->unique_size = 0; | ||
78 | } | ||
79 | |||
67 | /** | 80 | /** |
68 | * Set the bus id. | 81 | * Set the bus id. |
69 | * | 82 | * |
@@ -94,17 +107,24 @@ int drm_setunique(struct drm_device *dev, void *data, | |||
94 | master->unique_len = u->unique_len; | 107 | master->unique_len = u->unique_len; |
95 | master->unique_size = u->unique_len + 1; | 108 | master->unique_size = u->unique_len + 1; |
96 | master->unique = kmalloc(master->unique_size, GFP_KERNEL); | 109 | master->unique = kmalloc(master->unique_size, GFP_KERNEL); |
97 | if (!master->unique) | 110 | if (!master->unique) { |
98 | return -ENOMEM; | 111 | ret = -ENOMEM; |
99 | if (copy_from_user(master->unique, u->unique, master->unique_len)) | 112 | goto err; |
100 | return -EFAULT; | 113 | } |
114 | |||
115 | if (copy_from_user(master->unique, u->unique, master->unique_len)) { | ||
116 | ret = -EFAULT; | ||
117 | goto err; | ||
118 | } | ||
101 | 119 | ||
102 | master->unique[master->unique_len] = '\0'; | 120 | master->unique[master->unique_len] = '\0'; |
103 | 121 | ||
104 | dev->devname = kmalloc(strlen(dev->driver->pci_driver.name) + | 122 | dev->devname = kmalloc(strlen(dev->driver->pci_driver.name) + |
105 | strlen(master->unique) + 2, GFP_KERNEL); | 123 | strlen(master->unique) + 2, GFP_KERNEL); |
106 | if (!dev->devname) | 124 | if (!dev->devname) { |
107 | return -ENOMEM; | 125 | ret = -ENOMEM; |
126 | goto err; | ||
127 | } | ||
108 | 128 | ||
109 | sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name, | 129 | sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name, |
110 | master->unique); | 130 | master->unique); |
@@ -113,53 +133,103 @@ int drm_setunique(struct drm_device *dev, void *data, | |||
113 | * busid. | 133 | * busid. |
114 | */ | 134 | */ |
115 | ret = sscanf(master->unique, "PCI:%d:%d:%d", &bus, &slot, &func); | 135 | ret = sscanf(master->unique, "PCI:%d:%d:%d", &bus, &slot, &func); |
116 | if (ret != 3) | 136 | if (ret != 3) { |
117 | return -EINVAL; | 137 | ret = -EINVAL; |
138 | goto err; | ||
139 | } | ||
140 | |||
118 | domain = bus >> 8; | 141 | domain = bus >> 8; |
119 | bus &= 0xff; | 142 | bus &= 0xff; |
120 | 143 | ||
121 | if ((domain != drm_get_pci_domain(dev)) || | 144 | if ((domain != drm_get_pci_domain(dev)) || |
122 | (bus != dev->pdev->bus->number) || | 145 | (bus != dev->pdev->bus->number) || |
123 | (slot != PCI_SLOT(dev->pdev->devfn)) || | 146 | (slot != PCI_SLOT(dev->pdev->devfn)) || |
124 | (func != PCI_FUNC(dev->pdev->devfn))) | 147 | (func != PCI_FUNC(dev->pdev->devfn))) { |
125 | return -EINVAL; | 148 | ret = -EINVAL; |
149 | goto err; | ||
150 | } | ||
126 | 151 | ||
127 | return 0; | 152 | return 0; |
153 | |||
154 | err: | ||
155 | drm_unset_busid(dev, master); | ||
156 | return ret; | ||
128 | } | 157 | } |
129 | 158 | ||
130 | static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv) | 159 | static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv) |
131 | { | 160 | { |
132 | struct drm_master *master = file_priv->master; | 161 | struct drm_master *master = file_priv->master; |
133 | int len; | 162 | int len, ret; |
134 | 163 | ||
135 | if (master->unique != NULL) | 164 | if (master->unique != NULL) |
136 | return -EBUSY; | 165 | drm_unset_busid(dev, master); |
137 | 166 | ||
138 | master->unique_len = 40; | 167 | if (drm_core_check_feature(dev, DRIVER_USE_PLATFORM_DEVICE)) { |
139 | master->unique_size = master->unique_len; | 168 | master->unique_len = 10 + strlen(dev->platformdev->name); |
140 | master->unique = kmalloc(master->unique_size, GFP_KERNEL); | 169 | master->unique = kmalloc(master->unique_len + 1, GFP_KERNEL); |
141 | if (master->unique == NULL) | ||
142 | return -ENOMEM; | ||
143 | |||
144 | len = snprintf(master->unique, master->unique_len, "pci:%04x:%02x:%02x.%d", | ||
145 | drm_get_pci_domain(dev), | ||
146 | dev->pdev->bus->number, | ||
147 | PCI_SLOT(dev->pdev->devfn), | ||
148 | PCI_FUNC(dev->pdev->devfn)); | ||
149 | if (len >= master->unique_len) | ||
150 | DRM_ERROR("buffer overflow"); | ||
151 | else | ||
152 | master->unique_len = len; | ||
153 | 170 | ||
154 | dev->devname = kmalloc(strlen(dev->driver->pci_driver.name) + | 171 | if (master->unique == NULL) |
155 | master->unique_len + 2, GFP_KERNEL); | 172 | return -ENOMEM; |
156 | if (dev->devname == NULL) | ||
157 | return -ENOMEM; | ||
158 | 173 | ||
159 | sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name, | 174 | len = snprintf(master->unique, master->unique_len, |
160 | master->unique); | 175 | "platform:%s", dev->platformdev->name); |
176 | |||
177 | if (len > master->unique_len) { | ||
178 | DRM_ERROR("Unique buffer overflowed\n"); | ||
179 | ret = -EINVAL; | ||
180 | goto err; | ||
181 | } | ||
182 | |||
183 | dev->devname = | ||
184 | kmalloc(strlen(dev->platformdev->name) + | ||
185 | master->unique_len + 2, GFP_KERNEL); | ||
186 | |||
187 | if (dev->devname == NULL) { | ||
188 | ret = -ENOMEM; | ||
189 | goto err; | ||
190 | } | ||
191 | |||
192 | sprintf(dev->devname, "%s@%s", dev->platformdev->name, | ||
193 | master->unique); | ||
194 | |||
195 | } else { | ||
196 | master->unique_len = 40; | ||
197 | master->unique_size = master->unique_len; | ||
198 | master->unique = kmalloc(master->unique_size, GFP_KERNEL); | ||
199 | if (master->unique == NULL) | ||
200 | return -ENOMEM; | ||
201 | |||
202 | len = snprintf(master->unique, master->unique_len, | ||
203 | "pci:%04x:%02x:%02x.%d", | ||
204 | drm_get_pci_domain(dev), | ||
205 | dev->pdev->bus->number, | ||
206 | PCI_SLOT(dev->pdev->devfn), | ||
207 | PCI_FUNC(dev->pdev->devfn)); | ||
208 | if (len >= master->unique_len) { | ||
209 | DRM_ERROR("buffer overflow"); | ||
210 | ret = -EINVAL; | ||
211 | goto err; | ||
212 | } else | ||
213 | master->unique_len = len; | ||
214 | |||
215 | dev->devname = | ||
216 | kmalloc(strlen(dev->driver->pci_driver.name) + | ||
217 | master->unique_len + 2, GFP_KERNEL); | ||
218 | |||
219 | if (dev->devname == NULL) { | ||
220 | ret = -ENOMEM; | ||
221 | goto err; | ||
222 | } | ||
223 | |||
224 | sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name, | ||
225 | master->unique); | ||
226 | } | ||
161 | 227 | ||
162 | return 0; | 228 | return 0; |
229 | |||
230 | err: | ||
231 | drm_unset_busid(dev, master); | ||
232 | return ret; | ||
163 | } | 233 | } |
164 | 234 | ||
165 | /** | 235 | /** |
@@ -323,7 +393,9 @@ int drm_setversion(struct drm_device *dev, void *data, struct drm_file *file_pri | |||
323 | /* | 393 | /* |
324 | * Version 1.1 includes tying of DRM to specific device | 394 | * Version 1.1 includes tying of DRM to specific device |
325 | */ | 395 | */ |
326 | drm_set_busid(dev, file_priv); | 396 | retcode = drm_set_busid(dev, file_priv); |
397 | if (retcode) | ||
398 | goto done; | ||
327 | } | 399 | } |
328 | } | 400 | } |
329 | 401 | ||