diff options
Diffstat (limited to 'drivers/char/drm/drm_fops.c')
-rw-r--r-- | drivers/char/drm/drm_fops.c | 317 |
1 files changed, 180 insertions, 137 deletions
diff --git a/drivers/char/drm/drm_fops.c b/drivers/char/drm/drm_fops.c index bf0a740122bf..403f44a1bf01 100644 --- a/drivers/char/drm/drm_fops.c +++ b/drivers/char/drm/drm_fops.c | |||
@@ -35,6 +35,7 @@ | |||
35 | */ | 35 | */ |
36 | 36 | ||
37 | #include "drmP.h" | 37 | #include "drmP.h" |
38 | #include "drm_sarea.h" | ||
38 | #include <linux/poll.h> | 39 | #include <linux/poll.h> |
39 | 40 | ||
40 | static int drm_open_helper(struct inode *inode, struct file *filp, | 41 | static int drm_open_helper(struct inode *inode, struct file *filp, |
@@ -42,15 +43,21 @@ static int drm_open_helper(struct inode *inode, struct file *filp, | |||
42 | 43 | ||
43 | static int drm_setup(drm_device_t * dev) | 44 | static int drm_setup(drm_device_t * dev) |
44 | { | 45 | { |
46 | drm_local_map_t *map; | ||
45 | int i; | 47 | int i; |
46 | int ret; | 48 | int ret; |
47 | 49 | ||
48 | if (dev->driver->presetup) { | 50 | if (dev->driver->firstopen) { |
49 | ret = dev->driver->presetup(dev); | 51 | ret = dev->driver->firstopen(dev); |
50 | if (ret != 0) | 52 | if (ret != 0) |
51 | return ret; | 53 | return ret; |
52 | } | 54 | } |
53 | 55 | ||
56 | /* prebuild the SAREA */ | ||
57 | i = drm_addmap(dev, 0, SAREA_MAX, _DRM_SHM, _DRM_CONTAINS_LOCK, &map); | ||
58 | if (i != 0) | ||
59 | return i; | ||
60 | |||
54 | atomic_set(&dev->ioctl_count, 0); | 61 | atomic_set(&dev->ioctl_count, 0); |
55 | atomic_set(&dev->vma_count, 0); | 62 | atomic_set(&dev->vma_count, 0); |
56 | dev->buf_use = 0; | 63 | dev->buf_use = 0; |
@@ -109,8 +116,6 @@ static int drm_setup(drm_device_t * dev) | |||
109 | * drm_select_queue fails between the time the interrupt is | 116 | * drm_select_queue fails between the time the interrupt is |
110 | * initialized and the time the queues are initialized. | 117 | * initialized and the time the queues are initialized. |
111 | */ | 118 | */ |
112 | if (dev->driver->postsetup) | ||
113 | dev->driver->postsetup(dev); | ||
114 | 119 | ||
115 | return 0; | 120 | return 0; |
116 | } | 121 | } |
@@ -154,10 +159,168 @@ int drm_open(struct inode *inode, struct file *filp) | |||
154 | 159 | ||
155 | return retcode; | 160 | return retcode; |
156 | } | 161 | } |
157 | |||
158 | EXPORT_SYMBOL(drm_open); | 162 | EXPORT_SYMBOL(drm_open); |
159 | 163 | ||
160 | /** | 164 | /** |
165 | * File \c open operation. | ||
166 | * | ||
167 | * \param inode device inode. | ||
168 | * \param filp file pointer. | ||
169 | * | ||
170 | * Puts the dev->fops corresponding to the device minor number into | ||
171 | * \p filp, call the \c open method, and restore the file operations. | ||
172 | */ | ||
173 | int drm_stub_open(struct inode *inode, struct file *filp) | ||
174 | { | ||
175 | drm_device_t *dev = NULL; | ||
176 | int minor = iminor(inode); | ||
177 | int err = -ENODEV; | ||
178 | struct file_operations *old_fops; | ||
179 | |||
180 | DRM_DEBUG("\n"); | ||
181 | |||
182 | if (!((minor >= 0) && (minor < drm_cards_limit))) | ||
183 | return -ENODEV; | ||
184 | |||
185 | if (!drm_heads[minor]) | ||
186 | return -ENODEV; | ||
187 | |||
188 | if (!(dev = drm_heads[minor]->dev)) | ||
189 | return -ENODEV; | ||
190 | |||
191 | old_fops = filp->f_op; | ||
192 | filp->f_op = fops_get(&dev->driver->fops); | ||
193 | if (filp->f_op->open && (err = filp->f_op->open(inode, filp))) { | ||
194 | fops_put(filp->f_op); | ||
195 | filp->f_op = fops_get(old_fops); | ||
196 | } | ||
197 | fops_put(old_fops); | ||
198 | |||
199 | return err; | ||
200 | } | ||
201 | |||
202 | /** | ||
203 | * Check whether DRI will run on this CPU. | ||
204 | * | ||
205 | * \return non-zero if the DRI will run on this CPU, or zero otherwise. | ||
206 | */ | ||
207 | static int drm_cpu_valid(void) | ||
208 | { | ||
209 | #if defined(__i386__) | ||
210 | if (boot_cpu_data.x86 == 3) | ||
211 | return 0; /* No cmpxchg on a 386 */ | ||
212 | #endif | ||
213 | #if defined(__sparc__) && !defined(__sparc_v9__) | ||
214 | return 0; /* No cmpxchg before v9 sparc. */ | ||
215 | #endif | ||
216 | return 1; | ||
217 | } | ||
218 | |||
219 | /** | ||
220 | * Called whenever a process opens /dev/drm. | ||
221 | * | ||
222 | * \param inode device inode. | ||
223 | * \param filp file pointer. | ||
224 | * \param dev device. | ||
225 | * \return zero on success or a negative number on failure. | ||
226 | * | ||
227 | * Creates and initializes a drm_file structure for the file private data in \p | ||
228 | * filp and add it into the double linked list in \p dev. | ||
229 | */ | ||
230 | static int drm_open_helper(struct inode *inode, struct file *filp, | ||
231 | drm_device_t * dev) | ||
232 | { | ||
233 | int minor = iminor(inode); | ||
234 | drm_file_t *priv; | ||
235 | int ret; | ||
236 | |||
237 | if (filp->f_flags & O_EXCL) | ||
238 | return -EBUSY; /* No exclusive opens */ | ||
239 | if (!drm_cpu_valid()) | ||
240 | return -EINVAL; | ||
241 | |||
242 | DRM_DEBUG("pid = %d, minor = %d\n", current->pid, minor); | ||
243 | |||
244 | priv = drm_alloc(sizeof(*priv), DRM_MEM_FILES); | ||
245 | if (!priv) | ||
246 | return -ENOMEM; | ||
247 | |||
248 | memset(priv, 0, sizeof(*priv)); | ||
249 | filp->private_data = priv; | ||
250 | priv->uid = current->euid; | ||
251 | priv->pid = current->pid; | ||
252 | priv->minor = minor; | ||
253 | priv->head = drm_heads[minor]; | ||
254 | priv->ioctl_count = 0; | ||
255 | /* for compatibility root is always authenticated */ | ||
256 | priv->authenticated = capable(CAP_SYS_ADMIN); | ||
257 | priv->lock_count = 0; | ||
258 | |||
259 | if (dev->driver->open) { | ||
260 | ret = dev->driver->open(dev, priv); | ||
261 | if (ret < 0) | ||
262 | goto out_free; | ||
263 | } | ||
264 | |||
265 | down(&dev->struct_sem); | ||
266 | if (!dev->file_last) { | ||
267 | priv->next = NULL; | ||
268 | priv->prev = NULL; | ||
269 | dev->file_first = priv; | ||
270 | dev->file_last = priv; | ||
271 | /* first opener automatically becomes master */ | ||
272 | priv->master = 1; | ||
273 | } else { | ||
274 | priv->next = NULL; | ||
275 | priv->prev = dev->file_last; | ||
276 | dev->file_last->next = priv; | ||
277 | dev->file_last = priv; | ||
278 | } | ||
279 | up(&dev->struct_sem); | ||
280 | |||
281 | #ifdef __alpha__ | ||
282 | /* | ||
283 | * Default the hose | ||
284 | */ | ||
285 | if (!dev->hose) { | ||
286 | struct pci_dev *pci_dev; | ||
287 | pci_dev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, NULL); | ||
288 | if (pci_dev) { | ||
289 | dev->hose = pci_dev->sysdata; | ||
290 | pci_dev_put(pci_dev); | ||
291 | } | ||
292 | if (!dev->hose) { | ||
293 | struct pci_bus *b = pci_bus_b(pci_root_buses.next); | ||
294 | if (b) | ||
295 | dev->hose = b->sysdata; | ||
296 | } | ||
297 | } | ||
298 | #endif | ||
299 | |||
300 | return 0; | ||
301 | out_free: | ||
302 | drm_free(priv, sizeof(*priv), DRM_MEM_FILES); | ||
303 | filp->private_data = NULL; | ||
304 | return ret; | ||
305 | } | ||
306 | |||
307 | /** No-op. */ | ||
308 | int drm_fasync(int fd, struct file *filp, int on) | ||
309 | { | ||
310 | drm_file_t *priv = filp->private_data; | ||
311 | drm_device_t *dev = priv->head->dev; | ||
312 | int retcode; | ||
313 | |||
314 | DRM_DEBUG("fd = %d, device = 0x%lx\n", fd, | ||
315 | (long)old_encode_dev(priv->head->device)); | ||
316 | retcode = fasync_helper(fd, filp, on, &dev->buf_async); | ||
317 | if (retcode < 0) | ||
318 | return retcode; | ||
319 | return 0; | ||
320 | } | ||
321 | EXPORT_SYMBOL(drm_fasync); | ||
322 | |||
323 | /** | ||
161 | * Release file. | 324 | * Release file. |
162 | * | 325 | * |
163 | * \param inode device inode | 326 | * \param inode device inode |
@@ -167,7 +330,7 @@ EXPORT_SYMBOL(drm_open); | |||
167 | * If the hardware lock is held then free it, and take it again for the kernel | 330 | * If the hardware lock is held then free it, and take it again for the kernel |
168 | * context since it's necessary to reclaim buffers. Unlink the file private | 331 | * context since it's necessary to reclaim buffers. Unlink the file private |
169 | * data from its list and free it. Decreases the open count and if it reaches | 332 | * data from its list and free it. Decreases the open count and if it reaches |
170 | * zero calls takedown(). | 333 | * zero calls drm_lastclose(). |
171 | */ | 334 | */ |
172 | int drm_release(struct inode *inode, struct file *filp) | 335 | int drm_release(struct inode *inode, struct file *filp) |
173 | { | 336 | { |
@@ -180,8 +343,8 @@ int drm_release(struct inode *inode, struct file *filp) | |||
180 | 343 | ||
181 | DRM_DEBUG("open_count = %d\n", dev->open_count); | 344 | DRM_DEBUG("open_count = %d\n", dev->open_count); |
182 | 345 | ||
183 | if (dev->driver->prerelease) | 346 | if (dev->driver->preclose) |
184 | dev->driver->prerelease(dev, filp); | 347 | dev->driver->preclose(dev, filp); |
185 | 348 | ||
186 | /* ======================================================== | 349 | /* ======================================================== |
187 | * Begin inline drm_release | 350 | * Begin inline drm_release |
@@ -197,8 +360,8 @@ int drm_release(struct inode *inode, struct file *filp) | |||
197 | DRM_DEBUG("File %p released, freeing lock for context %d\n", | 360 | DRM_DEBUG("File %p released, freeing lock for context %d\n", |
198 | filp, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); | 361 | filp, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); |
199 | 362 | ||
200 | if (dev->driver->release) | 363 | if (dev->driver->reclaim_buffers_locked) |
201 | dev->driver->release(dev, filp); | 364 | dev->driver->reclaim_buffers_locked(dev, filp); |
202 | 365 | ||
203 | drm_lock_free(dev, &dev->lock.hw_lock->lock, | 366 | drm_lock_free(dev, &dev->lock.hw_lock->lock, |
204 | _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); | 367 | _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); |
@@ -207,7 +370,7 @@ int drm_release(struct inode *inode, struct file *filp) | |||
207 | hardware at this point, possibly | 370 | hardware at this point, possibly |
208 | processed via a callback to the X | 371 | processed via a callback to the X |
209 | server. */ | 372 | server. */ |
210 | } else if (dev->driver->release && priv->lock_count | 373 | } else if (dev->driver->reclaim_buffers_locked && priv->lock_count |
211 | && dev->lock.hw_lock) { | 374 | && dev->lock.hw_lock) { |
212 | /* The lock is required to reclaim buffers */ | 375 | /* The lock is required to reclaim buffers */ |
213 | DECLARE_WAITQUEUE(entry, current); | 376 | DECLARE_WAITQUEUE(entry, current); |
@@ -237,15 +400,14 @@ int drm_release(struct inode *inode, struct file *filp) | |||
237 | __set_current_state(TASK_RUNNING); | 400 | __set_current_state(TASK_RUNNING); |
238 | remove_wait_queue(&dev->lock.lock_queue, &entry); | 401 | remove_wait_queue(&dev->lock.lock_queue, &entry); |
239 | if (!retcode) { | 402 | if (!retcode) { |
240 | if (dev->driver->release) | 403 | dev->driver->reclaim_buffers_locked(dev, filp); |
241 | dev->driver->release(dev, filp); | ||
242 | drm_lock_free(dev, &dev->lock.hw_lock->lock, | 404 | drm_lock_free(dev, &dev->lock.hw_lock->lock, |
243 | DRM_KERNEL_CONTEXT); | 405 | DRM_KERNEL_CONTEXT); |
244 | } | 406 | } |
245 | } | 407 | } |
246 | 408 | ||
247 | if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) | 409 | if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) && |
248 | && !dev->driver->release) { | 410 | !dev->driver->reclaim_buffers_locked) { |
249 | dev->driver->reclaim_buffers(dev, filp); | 411 | dev->driver->reclaim_buffers(dev, filp); |
250 | } | 412 | } |
251 | 413 | ||
@@ -292,9 +454,8 @@ int drm_release(struct inode *inode, struct file *filp) | |||
292 | } | 454 | } |
293 | up(&dev->struct_sem); | 455 | up(&dev->struct_sem); |
294 | 456 | ||
295 | if (dev->driver->free_filp_priv) | 457 | if (dev->driver->postclose) |
296 | dev->driver->free_filp_priv(dev, priv); | 458 | dev->driver->postclose(dev, priv); |
297 | |||
298 | drm_free(priv, sizeof(*priv), DRM_MEM_FILES); | 459 | drm_free(priv, sizeof(*priv), DRM_MEM_FILES); |
299 | 460 | ||
300 | /* ======================================================== | 461 | /* ======================================================== |
@@ -313,7 +474,7 @@ int drm_release(struct inode *inode, struct file *filp) | |||
313 | } | 474 | } |
314 | spin_unlock(&dev->count_lock); | 475 | spin_unlock(&dev->count_lock); |
315 | unlock_kernel(); | 476 | unlock_kernel(); |
316 | return drm_takedown(dev); | 477 | return drm_lastclose(dev); |
317 | } | 478 | } |
318 | spin_unlock(&dev->count_lock); | 479 | spin_unlock(&dev->count_lock); |
319 | 480 | ||
@@ -321,129 +482,11 @@ int drm_release(struct inode *inode, struct file *filp) | |||
321 | 482 | ||
322 | return retcode; | 483 | return retcode; |
323 | } | 484 | } |
324 | |||
325 | EXPORT_SYMBOL(drm_release); | 485 | EXPORT_SYMBOL(drm_release); |
326 | 486 | ||
327 | /** | ||
328 | * Called whenever a process opens /dev/drm. | ||
329 | * | ||
330 | * \param inode device inode. | ||
331 | * \param filp file pointer. | ||
332 | * \param dev device. | ||
333 | * \return zero on success or a negative number on failure. | ||
334 | * | ||
335 | * Creates and initializes a drm_file structure for the file private data in \p | ||
336 | * filp and add it into the double linked list in \p dev. | ||
337 | */ | ||
338 | static int drm_open_helper(struct inode *inode, struct file *filp, | ||
339 | drm_device_t * dev) | ||
340 | { | ||
341 | int minor = iminor(inode); | ||
342 | drm_file_t *priv; | ||
343 | int ret; | ||
344 | |||
345 | if (filp->f_flags & O_EXCL) | ||
346 | return -EBUSY; /* No exclusive opens */ | ||
347 | if (!drm_cpu_valid()) | ||
348 | return -EINVAL; | ||
349 | |||
350 | DRM_DEBUG("pid = %d, minor = %d\n", current->pid, minor); | ||
351 | |||
352 | priv = drm_alloc(sizeof(*priv), DRM_MEM_FILES); | ||
353 | if (!priv) | ||
354 | return -ENOMEM; | ||
355 | |||
356 | memset(priv, 0, sizeof(*priv)); | ||
357 | filp->private_data = priv; | ||
358 | priv->uid = current->euid; | ||
359 | priv->pid = current->pid; | ||
360 | priv->minor = minor; | ||
361 | priv->head = drm_heads[minor]; | ||
362 | priv->ioctl_count = 0; | ||
363 | priv->authenticated = capable(CAP_SYS_ADMIN); | ||
364 | priv->lock_count = 0; | ||
365 | |||
366 | if (dev->driver->open_helper) { | ||
367 | ret = dev->driver->open_helper(dev, priv); | ||
368 | if (ret < 0) | ||
369 | goto out_free; | ||
370 | } | ||
371 | |||
372 | down(&dev->struct_sem); | ||
373 | if (!dev->file_last) { | ||
374 | priv->next = NULL; | ||
375 | priv->prev = NULL; | ||
376 | dev->file_first = priv; | ||
377 | dev->file_last = priv; | ||
378 | } else { | ||
379 | priv->next = NULL; | ||
380 | priv->prev = dev->file_last; | ||
381 | dev->file_last->next = priv; | ||
382 | dev->file_last = priv; | ||
383 | } | ||
384 | up(&dev->struct_sem); | ||
385 | |||
386 | #ifdef __alpha__ | ||
387 | /* | ||
388 | * Default the hose | ||
389 | */ | ||
390 | if (!dev->hose) { | ||
391 | struct pci_dev *pci_dev; | ||
392 | pci_dev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, NULL); | ||
393 | if (pci_dev) { | ||
394 | dev->hose = pci_dev->sysdata; | ||
395 | pci_dev_put(pci_dev); | ||
396 | } | ||
397 | if (!dev->hose) { | ||
398 | struct pci_bus *b = pci_bus_b(pci_root_buses.next); | ||
399 | if (b) | ||
400 | dev->hose = b->sysdata; | ||
401 | } | ||
402 | } | ||
403 | #endif | ||
404 | |||
405 | return 0; | ||
406 | out_free: | ||
407 | drm_free(priv, sizeof(*priv), DRM_MEM_FILES); | ||
408 | filp->private_data = NULL; | ||
409 | return ret; | ||
410 | } | ||
411 | |||
412 | /** No-op. */ | ||
413 | int drm_flush(struct file *filp) | ||
414 | { | ||
415 | drm_file_t *priv = filp->private_data; | ||
416 | drm_device_t *dev = priv->head->dev; | ||
417 | |||
418 | DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n", | ||
419 | current->pid, (long)old_encode_dev(priv->head->device), | ||
420 | dev->open_count); | ||
421 | return 0; | ||
422 | } | ||
423 | |||
424 | EXPORT_SYMBOL(drm_flush); | ||
425 | |||
426 | /** No-op. */ | ||
427 | int drm_fasync(int fd, struct file *filp, int on) | ||
428 | { | ||
429 | drm_file_t *priv = filp->private_data; | ||
430 | drm_device_t *dev = priv->head->dev; | ||
431 | int retcode; | ||
432 | |||
433 | DRM_DEBUG("fd = %d, device = 0x%lx\n", fd, | ||
434 | (long)old_encode_dev(priv->head->device)); | ||
435 | retcode = fasync_helper(fd, filp, on, &dev->buf_async); | ||
436 | if (retcode < 0) | ||
437 | return retcode; | ||
438 | return 0; | ||
439 | } | ||
440 | |||
441 | EXPORT_SYMBOL(drm_fasync); | ||
442 | |||
443 | /** No-op. */ | 487 | /** No-op. */ |
444 | unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait) | 488 | unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait) |
445 | { | 489 | { |
446 | return 0; | 490 | return 0; |
447 | } | 491 | } |
448 | |||
449 | EXPORT_SYMBOL(drm_poll); | 492 | EXPORT_SYMBOL(drm_poll); |