diff options
Diffstat (limited to 'drivers/char/drm/drm_fops.c')
-rw-r--r-- | drivers/char/drm/drm_fops.c | 466 |
1 files changed, 0 insertions, 466 deletions
diff --git a/drivers/char/drm/drm_fops.c b/drivers/char/drm/drm_fops.c deleted file mode 100644 index d2e6da85f58a..000000000000 --- a/drivers/char/drm/drm_fops.c +++ /dev/null | |||
@@ -1,466 +0,0 @@ | |||
1 | /** | ||
2 | * \file drm_fops.c | ||
3 | * File operations for DRM | ||
4 | * | ||
5 | * \author Rickard E. (Rik) Faith <faith@valinux.com> | ||
6 | * \author Daryll Strauss <daryll@valinux.com> | ||
7 | * \author Gareth Hughes <gareth@valinux.com> | ||
8 | */ | ||
9 | |||
10 | /* | ||
11 | * Created: Mon Jan 4 08:58:31 1999 by faith@valinux.com | ||
12 | * | ||
13 | * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. | ||
14 | * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. | ||
15 | * All Rights Reserved. | ||
16 | * | ||
17 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
18 | * copy of this software and associated documentation files (the "Software"), | ||
19 | * to deal in the Software without restriction, including without limitation | ||
20 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
21 | * and/or sell copies of the Software, and to permit persons to whom the | ||
22 | * Software is furnished to do so, subject to the following conditions: | ||
23 | * | ||
24 | * The above copyright notice and this permission notice (including the next | ||
25 | * paragraph) shall be included in all copies or substantial portions of the | ||
26 | * Software. | ||
27 | * | ||
28 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
29 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
30 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
31 | * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
32 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
33 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
34 | * OTHER DEALINGS IN THE SOFTWARE. | ||
35 | */ | ||
36 | |||
37 | #include "drmP.h" | ||
38 | #include "drm_sarea.h" | ||
39 | #include <linux/poll.h> | ||
40 | |||
41 | static int drm_open_helper(struct inode *inode, struct file *filp, | ||
42 | struct drm_device * dev); | ||
43 | |||
44 | static int drm_setup(struct drm_device * dev) | ||
45 | { | ||
46 | drm_local_map_t *map; | ||
47 | int i; | ||
48 | int ret; | ||
49 | u32 sareapage; | ||
50 | |||
51 | if (dev->driver->firstopen) { | ||
52 | ret = dev->driver->firstopen(dev); | ||
53 | if (ret != 0) | ||
54 | return ret; | ||
55 | } | ||
56 | |||
57 | dev->magicfree.next = NULL; | ||
58 | |||
59 | /* prebuild the SAREA */ | ||
60 | sareapage = max_t(unsigned, SAREA_MAX, PAGE_SIZE); | ||
61 | i = drm_addmap(dev, 0, sareapage, _DRM_SHM, _DRM_CONTAINS_LOCK, &map); | ||
62 | if (i != 0) | ||
63 | return i; | ||
64 | |||
65 | atomic_set(&dev->ioctl_count, 0); | ||
66 | atomic_set(&dev->vma_count, 0); | ||
67 | dev->buf_use = 0; | ||
68 | atomic_set(&dev->buf_alloc, 0); | ||
69 | |||
70 | if (drm_core_check_feature(dev, DRIVER_HAVE_DMA)) { | ||
71 | i = drm_dma_setup(dev); | ||
72 | if (i < 0) | ||
73 | return i; | ||
74 | } | ||
75 | |||
76 | for (i = 0; i < ARRAY_SIZE(dev->counts); i++) | ||
77 | atomic_set(&dev->counts[i], 0); | ||
78 | |||
79 | drm_ht_create(&dev->magiclist, DRM_MAGIC_HASH_ORDER); | ||
80 | INIT_LIST_HEAD(&dev->magicfree); | ||
81 | |||
82 | dev->sigdata.lock = NULL; | ||
83 | init_waitqueue_head(&dev->lock.lock_queue); | ||
84 | dev->queue_count = 0; | ||
85 | dev->queue_reserved = 0; | ||
86 | dev->queue_slots = 0; | ||
87 | dev->queuelist = NULL; | ||
88 | dev->irq_enabled = 0; | ||
89 | dev->context_flag = 0; | ||
90 | dev->interrupt_flag = 0; | ||
91 | dev->dma_flag = 0; | ||
92 | dev->last_context = 0; | ||
93 | dev->last_switch = 0; | ||
94 | dev->last_checked = 0; | ||
95 | init_waitqueue_head(&dev->context_wait); | ||
96 | dev->if_version = 0; | ||
97 | |||
98 | dev->ctx_start = 0; | ||
99 | dev->lck_start = 0; | ||
100 | |||
101 | dev->buf_async = NULL; | ||
102 | init_waitqueue_head(&dev->buf_readers); | ||
103 | init_waitqueue_head(&dev->buf_writers); | ||
104 | |||
105 | DRM_DEBUG("\n"); | ||
106 | |||
107 | /* | ||
108 | * The kernel's context could be created here, but is now created | ||
109 | * in drm_dma_enqueue. This is more resource-efficient for | ||
110 | * hardware that does not do DMA, but may mean that | ||
111 | * drm_select_queue fails between the time the interrupt is | ||
112 | * initialized and the time the queues are initialized. | ||
113 | */ | ||
114 | |||
115 | return 0; | ||
116 | } | ||
117 | |||
118 | /** | ||
119 | * Open file. | ||
120 | * | ||
121 | * \param inode device inode | ||
122 | * \param filp file pointer. | ||
123 | * \return zero on success or a negative number on failure. | ||
124 | * | ||
125 | * Searches the DRM device with the same minor number, calls open_helper(), and | ||
126 | * increments the device open count. If the open count was previous at zero, | ||
127 | * i.e., it's the first that the device is open, then calls setup(). | ||
128 | */ | ||
129 | int drm_open(struct inode *inode, struct file *filp) | ||
130 | { | ||
131 | struct drm_device *dev = NULL; | ||
132 | int minor_id = iminor(inode); | ||
133 | struct drm_minor *minor; | ||
134 | int retcode = 0; | ||
135 | |||
136 | minor = idr_find(&drm_minors_idr, minor_id); | ||
137 | if (!minor) | ||
138 | return -ENODEV; | ||
139 | |||
140 | if (!(dev = minor->dev)) | ||
141 | return -ENODEV; | ||
142 | |||
143 | retcode = drm_open_helper(inode, filp, dev); | ||
144 | if (!retcode) { | ||
145 | atomic_inc(&dev->counts[_DRM_STAT_OPENS]); | ||
146 | spin_lock(&dev->count_lock); | ||
147 | if (!dev->open_count++) { | ||
148 | spin_unlock(&dev->count_lock); | ||
149 | return drm_setup(dev); | ||
150 | } | ||
151 | spin_unlock(&dev->count_lock); | ||
152 | } | ||
153 | |||
154 | return retcode; | ||
155 | } | ||
156 | EXPORT_SYMBOL(drm_open); | ||
157 | |||
158 | /** | ||
159 | * File \c open operation. | ||
160 | * | ||
161 | * \param inode device inode. | ||
162 | * \param filp file pointer. | ||
163 | * | ||
164 | * Puts the dev->fops corresponding to the device minor number into | ||
165 | * \p filp, call the \c open method, and restore the file operations. | ||
166 | */ | ||
167 | int drm_stub_open(struct inode *inode, struct file *filp) | ||
168 | { | ||
169 | struct drm_device *dev = NULL; | ||
170 | struct drm_minor *minor; | ||
171 | int minor_id = iminor(inode); | ||
172 | int err = -ENODEV; | ||
173 | const struct file_operations *old_fops; | ||
174 | |||
175 | DRM_DEBUG("\n"); | ||
176 | |||
177 | minor = idr_find(&drm_minors_idr, minor_id); | ||
178 | if (!minor) | ||
179 | return -ENODEV; | ||
180 | |||
181 | if (!(dev = minor->dev)) | ||
182 | return -ENODEV; | ||
183 | |||
184 | old_fops = filp->f_op; | ||
185 | filp->f_op = fops_get(&dev->driver->fops); | ||
186 | if (filp->f_op->open && (err = filp->f_op->open(inode, filp))) { | ||
187 | fops_put(filp->f_op); | ||
188 | filp->f_op = fops_get(old_fops); | ||
189 | } | ||
190 | fops_put(old_fops); | ||
191 | |||
192 | return err; | ||
193 | } | ||
194 | |||
195 | /** | ||
196 | * Check whether DRI will run on this CPU. | ||
197 | * | ||
198 | * \return non-zero if the DRI will run on this CPU, or zero otherwise. | ||
199 | */ | ||
200 | static int drm_cpu_valid(void) | ||
201 | { | ||
202 | #if defined(__i386__) | ||
203 | if (boot_cpu_data.x86 == 3) | ||
204 | return 0; /* No cmpxchg on a 386 */ | ||
205 | #endif | ||
206 | #if defined(__sparc__) && !defined(__sparc_v9__) | ||
207 | return 0; /* No cmpxchg before v9 sparc. */ | ||
208 | #endif | ||
209 | return 1; | ||
210 | } | ||
211 | |||
212 | /** | ||
213 | * Called whenever a process opens /dev/drm. | ||
214 | * | ||
215 | * \param inode device inode. | ||
216 | * \param filp file pointer. | ||
217 | * \param dev device. | ||
218 | * \return zero on success or a negative number on failure. | ||
219 | * | ||
220 | * Creates and initializes a drm_file structure for the file private data in \p | ||
221 | * filp and add it into the double linked list in \p dev. | ||
222 | */ | ||
223 | static int drm_open_helper(struct inode *inode, struct file *filp, | ||
224 | struct drm_device * dev) | ||
225 | { | ||
226 | int minor_id = iminor(inode); | ||
227 | struct drm_file *priv; | ||
228 | int ret; | ||
229 | |||
230 | if (filp->f_flags & O_EXCL) | ||
231 | return -EBUSY; /* No exclusive opens */ | ||
232 | if (!drm_cpu_valid()) | ||
233 | return -EINVAL; | ||
234 | |||
235 | DRM_DEBUG("pid = %d, minor = %d\n", task_pid_nr(current), minor_id); | ||
236 | |||
237 | priv = drm_alloc(sizeof(*priv), DRM_MEM_FILES); | ||
238 | if (!priv) | ||
239 | return -ENOMEM; | ||
240 | |||
241 | memset(priv, 0, sizeof(*priv)); | ||
242 | filp->private_data = priv; | ||
243 | priv->filp = filp; | ||
244 | priv->uid = current->euid; | ||
245 | priv->pid = task_pid_nr(current); | ||
246 | priv->minor = idr_find(&drm_minors_idr, minor_id); | ||
247 | priv->ioctl_count = 0; | ||
248 | /* for compatibility root is always authenticated */ | ||
249 | priv->authenticated = capable(CAP_SYS_ADMIN); | ||
250 | priv->lock_count = 0; | ||
251 | |||
252 | INIT_LIST_HEAD(&priv->lhead); | ||
253 | |||
254 | if (dev->driver->open) { | ||
255 | ret = dev->driver->open(dev, priv); | ||
256 | if (ret < 0) | ||
257 | goto out_free; | ||
258 | } | ||
259 | |||
260 | mutex_lock(&dev->struct_mutex); | ||
261 | if (list_empty(&dev->filelist)) | ||
262 | priv->master = 1; | ||
263 | |||
264 | list_add(&priv->lhead, &dev->filelist); | ||
265 | mutex_unlock(&dev->struct_mutex); | ||
266 | |||
267 | #ifdef __alpha__ | ||
268 | /* | ||
269 | * Default the hose | ||
270 | */ | ||
271 | if (!dev->hose) { | ||
272 | struct pci_dev *pci_dev; | ||
273 | pci_dev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, NULL); | ||
274 | if (pci_dev) { | ||
275 | dev->hose = pci_dev->sysdata; | ||
276 | pci_dev_put(pci_dev); | ||
277 | } | ||
278 | if (!dev->hose) { | ||
279 | struct pci_bus *b = pci_bus_b(pci_root_buses.next); | ||
280 | if (b) | ||
281 | dev->hose = b->sysdata; | ||
282 | } | ||
283 | } | ||
284 | #endif | ||
285 | |||
286 | return 0; | ||
287 | out_free: | ||
288 | drm_free(priv, sizeof(*priv), DRM_MEM_FILES); | ||
289 | filp->private_data = NULL; | ||
290 | return ret; | ||
291 | } | ||
292 | |||
293 | /** No-op. */ | ||
294 | int drm_fasync(int fd, struct file *filp, int on) | ||
295 | { | ||
296 | struct drm_file *priv = filp->private_data; | ||
297 | struct drm_device *dev = priv->minor->dev; | ||
298 | int retcode; | ||
299 | |||
300 | DRM_DEBUG("fd = %d, device = 0x%lx\n", fd, | ||
301 | (long)old_encode_dev(priv->minor->device)); | ||
302 | retcode = fasync_helper(fd, filp, on, &dev->buf_async); | ||
303 | if (retcode < 0) | ||
304 | return retcode; | ||
305 | return 0; | ||
306 | } | ||
307 | EXPORT_SYMBOL(drm_fasync); | ||
308 | |||
309 | /** | ||
310 | * Release file. | ||
311 | * | ||
312 | * \param inode device inode | ||
313 | * \param file_priv DRM file private. | ||
314 | * \return zero on success or a negative number on failure. | ||
315 | * | ||
316 | * If the hardware lock is held then free it, and take it again for the kernel | ||
317 | * context since it's necessary to reclaim buffers. Unlink the file private | ||
318 | * data from its list and free it. Decreases the open count and if it reaches | ||
319 | * zero calls drm_lastclose(). | ||
320 | */ | ||
321 | int drm_release(struct inode *inode, struct file *filp) | ||
322 | { | ||
323 | struct drm_file *file_priv = filp->private_data; | ||
324 | struct drm_device *dev = file_priv->minor->dev; | ||
325 | int retcode = 0; | ||
326 | |||
327 | lock_kernel(); | ||
328 | |||
329 | DRM_DEBUG("open_count = %d\n", dev->open_count); | ||
330 | |||
331 | if (dev->driver->preclose) | ||
332 | dev->driver->preclose(dev, file_priv); | ||
333 | |||
334 | /* ======================================================== | ||
335 | * Begin inline drm_release | ||
336 | */ | ||
337 | |||
338 | DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n", | ||
339 | task_pid_nr(current), | ||
340 | (long)old_encode_dev(file_priv->minor->device), | ||
341 | dev->open_count); | ||
342 | |||
343 | if (dev->driver->reclaim_buffers_locked && dev->lock.hw_lock) { | ||
344 | if (drm_i_have_hw_lock(dev, file_priv)) { | ||
345 | dev->driver->reclaim_buffers_locked(dev, file_priv); | ||
346 | } else { | ||
347 | unsigned long endtime = jiffies + 3 * DRM_HZ; | ||
348 | int locked = 0; | ||
349 | |||
350 | drm_idlelock_take(&dev->lock); | ||
351 | |||
352 | /* | ||
353 | * Wait for a while. | ||
354 | */ | ||
355 | |||
356 | do{ | ||
357 | spin_lock_bh(&dev->lock.spinlock); | ||
358 | locked = dev->lock.idle_has_lock; | ||
359 | spin_unlock_bh(&dev->lock.spinlock); | ||
360 | if (locked) | ||
361 | break; | ||
362 | schedule(); | ||
363 | } while (!time_after_eq(jiffies, endtime)); | ||
364 | |||
365 | if (!locked) { | ||
366 | DRM_ERROR("reclaim_buffers_locked() deadlock. Please rework this\n" | ||
367 | "\tdriver to use reclaim_buffers_idlelocked() instead.\n" | ||
368 | "\tI will go on reclaiming the buffers anyway.\n"); | ||
369 | } | ||
370 | |||
371 | dev->driver->reclaim_buffers_locked(dev, file_priv); | ||
372 | drm_idlelock_release(&dev->lock); | ||
373 | } | ||
374 | } | ||
375 | |||
376 | if (dev->driver->reclaim_buffers_idlelocked && dev->lock.hw_lock) { | ||
377 | |||
378 | drm_idlelock_take(&dev->lock); | ||
379 | dev->driver->reclaim_buffers_idlelocked(dev, file_priv); | ||
380 | drm_idlelock_release(&dev->lock); | ||
381 | |||
382 | } | ||
383 | |||
384 | if (drm_i_have_hw_lock(dev, file_priv)) { | ||
385 | DRM_DEBUG("File %p released, freeing lock for context %d\n", | ||
386 | filp, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); | ||
387 | |||
388 | drm_lock_free(&dev->lock, | ||
389 | _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); | ||
390 | } | ||
391 | |||
392 | |||
393 | if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) && | ||
394 | !dev->driver->reclaim_buffers_locked) { | ||
395 | dev->driver->reclaim_buffers(dev, file_priv); | ||
396 | } | ||
397 | |||
398 | drm_fasync(-1, filp, 0); | ||
399 | |||
400 | mutex_lock(&dev->ctxlist_mutex); | ||
401 | if (!list_empty(&dev->ctxlist)) { | ||
402 | struct drm_ctx_list *pos, *n; | ||
403 | |||
404 | list_for_each_entry_safe(pos, n, &dev->ctxlist, head) { | ||
405 | if (pos->tag == file_priv && | ||
406 | pos->handle != DRM_KERNEL_CONTEXT) { | ||
407 | if (dev->driver->context_dtor) | ||
408 | dev->driver->context_dtor(dev, | ||
409 | pos->handle); | ||
410 | |||
411 | drm_ctxbitmap_free(dev, pos->handle); | ||
412 | |||
413 | list_del(&pos->head); | ||
414 | drm_free(pos, sizeof(*pos), DRM_MEM_CTXLIST); | ||
415 | --dev->ctx_count; | ||
416 | } | ||
417 | } | ||
418 | } | ||
419 | mutex_unlock(&dev->ctxlist_mutex); | ||
420 | |||
421 | mutex_lock(&dev->struct_mutex); | ||
422 | if (file_priv->remove_auth_on_close == 1) { | ||
423 | struct drm_file *temp; | ||
424 | |||
425 | list_for_each_entry(temp, &dev->filelist, lhead) | ||
426 | temp->authenticated = 0; | ||
427 | } | ||
428 | list_del(&file_priv->lhead); | ||
429 | mutex_unlock(&dev->struct_mutex); | ||
430 | |||
431 | if (dev->driver->postclose) | ||
432 | dev->driver->postclose(dev, file_priv); | ||
433 | drm_free(file_priv, sizeof(*file_priv), DRM_MEM_FILES); | ||
434 | |||
435 | /* ======================================================== | ||
436 | * End inline drm_release | ||
437 | */ | ||
438 | |||
439 | atomic_inc(&dev->counts[_DRM_STAT_CLOSES]); | ||
440 | spin_lock(&dev->count_lock); | ||
441 | if (!--dev->open_count) { | ||
442 | if (atomic_read(&dev->ioctl_count) || dev->blocked) { | ||
443 | DRM_ERROR("Device busy: %d %d\n", | ||
444 | atomic_read(&dev->ioctl_count), dev->blocked); | ||
445 | spin_unlock(&dev->count_lock); | ||
446 | unlock_kernel(); | ||
447 | return -EBUSY; | ||
448 | } | ||
449 | spin_unlock(&dev->count_lock); | ||
450 | unlock_kernel(); | ||
451 | return drm_lastclose(dev); | ||
452 | } | ||
453 | spin_unlock(&dev->count_lock); | ||
454 | |||
455 | unlock_kernel(); | ||
456 | |||
457 | return retcode; | ||
458 | } | ||
459 | EXPORT_SYMBOL(drm_release); | ||
460 | |||
461 | /** No-op. */ | ||
462 | unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait) | ||
463 | { | ||
464 | return 0; | ||
465 | } | ||
466 | EXPORT_SYMBOL(drm_poll); | ||