diff options
Diffstat (limited to 'drivers/char/drm/drm_fops.c')
-rw-r--r-- | drivers/char/drm/drm_fops.c | 289 |
1 files changed, 166 insertions, 123 deletions
diff --git a/drivers/char/drm/drm_fops.c b/drivers/char/drm/drm_fops.c index b73543c694a9..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,6 +43,7 @@ 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 | ||
@@ -51,6 +53,11 @@ static int drm_setup(drm_device_t * dev) | |||
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; |
@@ -152,10 +159,168 @@ int drm_open(struct inode *inode, struct file *filp) | |||
152 | 159 | ||
153 | return retcode; | 160 | return retcode; |
154 | } | 161 | } |
155 | |||
156 | EXPORT_SYMBOL(drm_open); | 162 | EXPORT_SYMBOL(drm_open); |
157 | 163 | ||
158 | /** | 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 | /** | ||
159 | * Release file. | 324 | * Release file. |
160 | * | 325 | * |
161 | * \param inode device inode | 326 | * \param inode device inode |
@@ -291,7 +456,6 @@ int drm_release(struct inode *inode, struct file *filp) | |||
291 | 456 | ||
292 | if (dev->driver->postclose) | 457 | if (dev->driver->postclose) |
293 | dev->driver->postclose(dev, priv); | 458 | dev->driver->postclose(dev, priv); |
294 | |||
295 | drm_free(priv, sizeof(*priv), DRM_MEM_FILES); | 459 | drm_free(priv, sizeof(*priv), DRM_MEM_FILES); |
296 | 460 | ||
297 | /* ======================================================== | 461 | /* ======================================================== |
@@ -318,132 +482,11 @@ int drm_release(struct inode *inode, struct file *filp) | |||
318 | 482 | ||
319 | return retcode; | 483 | return retcode; |
320 | } | 484 | } |
321 | |||
322 | EXPORT_SYMBOL(drm_release); | 485 | EXPORT_SYMBOL(drm_release); |
323 | 486 | ||
324 | /** | ||
325 | * Check whether DRI will run on this CPU. | ||
326 | * | ||
327 | * \return non-zero if the DRI will run on this CPU, or zero otherwise. | ||
328 | */ | ||
329 | static int drm_cpu_valid(void) | ||
330 | { | ||
331 | #if defined(__i386__) | ||
332 | if (boot_cpu_data.x86 == 3) | ||
333 | return 0; /* No cmpxchg on a 386 */ | ||
334 | #endif | ||
335 | #if defined(__sparc__) && !defined(__sparc_v9__) | ||
336 | return 0; /* No cmpxchg before v9 sparc. */ | ||
337 | #endif | ||
338 | return 1; | ||
339 | } | ||
340 | |||
341 | /** | ||
342 | * Called whenever a process opens /dev/drm. | ||
343 | * | ||
344 | * \param inode device inode. | ||
345 | * \param filp file pointer. | ||
346 | * \param dev device. | ||
347 | * \return zero on success or a negative number on failure. | ||
348 | * | ||
349 | * Creates and initializes a drm_file structure for the file private data in \p | ||
350 | * filp and add it into the double linked list in \p dev. | ||
351 | */ | ||
352 | static int drm_open_helper(struct inode *inode, struct file *filp, | ||
353 | drm_device_t * dev) | ||
354 | { | ||
355 | int minor = iminor(inode); | ||
356 | drm_file_t *priv; | ||
357 | int ret; | ||
358 | |||
359 | if (filp->f_flags & O_EXCL) | ||
360 | return -EBUSY; /* No exclusive opens */ | ||
361 | if (!drm_cpu_valid()) | ||
362 | return -EINVAL; | ||
363 | |||
364 | DRM_DEBUG("pid = %d, minor = %d\n", current->pid, minor); | ||
365 | |||
366 | priv = drm_alloc(sizeof(*priv), DRM_MEM_FILES); | ||
367 | if (!priv) | ||
368 | return -ENOMEM; | ||
369 | |||
370 | memset(priv, 0, sizeof(*priv)); | ||
371 | filp->private_data = priv; | ||
372 | priv->uid = current->euid; | ||
373 | priv->pid = current->pid; | ||
374 | priv->minor = minor; | ||
375 | priv->head = drm_heads[minor]; | ||
376 | priv->ioctl_count = 0; | ||
377 | priv->authenticated = capable(CAP_SYS_ADMIN); | ||
378 | priv->lock_count = 0; | ||
379 | |||
380 | if (dev->driver->open) { | ||
381 | ret = dev->driver->open(dev, priv); | ||
382 | if (ret < 0) | ||
383 | goto out_free; | ||
384 | } | ||
385 | |||
386 | down(&dev->struct_sem); | ||
387 | if (!dev->file_last) { | ||
388 | priv->next = NULL; | ||
389 | priv->prev = NULL; | ||
390 | dev->file_first = priv; | ||
391 | dev->file_last = priv; | ||
392 | } else { | ||
393 | priv->next = NULL; | ||
394 | priv->prev = dev->file_last; | ||
395 | dev->file_last->next = priv; | ||
396 | dev->file_last = priv; | ||
397 | } | ||
398 | up(&dev->struct_sem); | ||
399 | |||
400 | #ifdef __alpha__ | ||
401 | /* | ||
402 | * Default the hose | ||
403 | */ | ||
404 | if (!dev->hose) { | ||
405 | struct pci_dev *pci_dev; | ||
406 | pci_dev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, NULL); | ||
407 | if (pci_dev) { | ||
408 | dev->hose = pci_dev->sysdata; | ||
409 | pci_dev_put(pci_dev); | ||
410 | } | ||
411 | if (!dev->hose) { | ||
412 | struct pci_bus *b = pci_bus_b(pci_root_buses.next); | ||
413 | if (b) | ||
414 | dev->hose = b->sysdata; | ||
415 | } | ||
416 | } | ||
417 | #endif | ||
418 | |||
419 | return 0; | ||
420 | out_free: | ||
421 | drm_free(priv, sizeof(*priv), DRM_MEM_FILES); | ||
422 | filp->private_data = NULL; | ||
423 | return ret; | ||
424 | } | ||
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); |