linux-old/drivers/char/drm-4.0/fops.c
<<
>>
Prefs
   1/* fops.c -- File operations for DRM -*- linux-c -*-
   2 * Created: Mon Jan  4 08:58:31 1999 by faith@precisioninsight.com
   3 *
   4 * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
   5 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
   6 * All Rights Reserved.
   7 *
   8 * Permission is hereby granted, free of charge, to any person obtaining a
   9 * copy of this software and associated documentation files (the "Software"),
  10 * to deal in the Software without restriction, including without limitation
  11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  12 * and/or sell copies of the Software, and to permit persons to whom the
  13 * Software is furnished to do so, subject to the following conditions:
  14 * 
  15 * The above copyright notice and this permission notice (including the next
  16 * paragraph) shall be included in all copies or substantial portions of the
  17 * Software.
  18 * 
  19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  22 * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  23 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  24 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  25 * DEALINGS IN THE SOFTWARE.
  26 * 
  27 * Authors:
  28 *    Rickard E. (Rik) Faith <faith@valinux.com>
  29 *    Daryll Strauss <daryll@valinux.com>
  30 *
  31 */
  32
  33#define __NO_VERSION__
  34#include "drmP.h"
  35#include <linux/poll.h>
  36
  37/* drm_open is called whenever a process opens /dev/drm. */
  38
  39int drm_open_helper(struct inode *inode, struct file *filp, drm_device_t *dev)
  40{
  41        kdev_t       minor = MINOR(inode->i_rdev);
  42        drm_file_t   *priv;
  43
  44        if (filp->f_flags & O_EXCL)   return -EBUSY; /* No exclusive opens */
  45        if (!drm_cpu_valid())         return -EINVAL;
  46
  47        DRM_DEBUG("pid = %d, minor = %d\n", current->pid, minor);
  48
  49        priv                = drm_alloc(sizeof(*priv), DRM_MEM_FILES);
  50        if(priv == NULL)
  51                return -ENOMEM;
  52        memset(priv, 0, sizeof(*priv));
  53
  54        filp->private_data  = priv;
  55        priv->uid           = current->euid;
  56        priv->pid           = current->pid;
  57        priv->minor         = minor;
  58        priv->dev           = dev;
  59        priv->ioctl_count   = 0;
  60        priv->authenticated = capable(CAP_SYS_ADMIN);
  61
  62        down(&dev->struct_sem);
  63        if (!dev->file_last) {
  64                priv->next      = NULL;
  65                priv->prev      = NULL;
  66                dev->file_first = priv;
  67                dev->file_last  = priv;
  68        } else {
  69                priv->next           = NULL;
  70                priv->prev           = dev->file_last;
  71                dev->file_last->next = priv;
  72                dev->file_last       = priv;
  73        }
  74        up(&dev->struct_sem);
  75        
  76        return 0;
  77}
  78
  79int drm_flush(struct file *filp)
  80{
  81        drm_file_t    *priv   = filp->private_data;
  82        drm_device_t  *dev    = priv->dev;
  83
  84        DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d\n",
  85                  current->pid, dev->device, dev->open_count);
  86        return 0;
  87}
  88
  89/* drm_release is called whenever a process closes /dev/drm*.  Linux calls
  90   this only if any mappings have been closed. */
  91
  92int drm_release(struct inode *inode, struct file *filp)
  93{
  94        drm_file_t    *priv   = filp->private_data;
  95        drm_device_t  *dev    = priv->dev;
  96
  97        DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d\n",
  98                  current->pid, dev->device, dev->open_count);
  99
 100        if (dev->lock.hw_lock
 101            && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)
 102            && dev->lock.pid == current->pid) {
 103                DRM_ERROR("Process %d dead, freeing lock for context %d\n",
 104                          current->pid,
 105                          _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
 106                drm_lock_free(dev,
 107                              &dev->lock.hw_lock->lock,
 108                              _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
 109                
 110                                /* FIXME: may require heavy-handed reset of
 111                                   hardware at this point, possibly
 112                                   processed via a callback to the X
 113                                   server. */
 114        }
 115        drm_reclaim_buffers(dev, priv->pid);
 116
 117        drm_fasync(-1, filp, 0);
 118
 119        down(&dev->struct_sem);
 120        if (priv->prev) priv->prev->next = priv->next;
 121        else            dev->file_first  = priv->next;
 122        if (priv->next) priv->next->prev = priv->prev;
 123        else            dev->file_last   = priv->prev;
 124        up(&dev->struct_sem);
 125        
 126        drm_free(priv, sizeof(*priv), DRM_MEM_FILES);
 127        
 128        return 0;
 129}
 130
 131int drm_fasync(int fd, struct file *filp, int on)
 132{
 133        drm_file_t    *priv   = filp->private_data;
 134        drm_device_t  *dev    = priv->dev;
 135        int           retcode;
 136        
 137        DRM_DEBUG("fd = %d, device = 0x%x\n", fd, dev->device);
 138        retcode = fasync_helper(fd, filp, on, &dev->buf_async);
 139        if (retcode < 0) return retcode;
 140        return 0;
 141}
 142
 143
 144/* The drm_read and drm_write_string code (especially that which manages
 145   the circular buffer), is based on Alessandro Rubini's LINUX DEVICE
 146   DRIVERS (Cambridge: O'Reilly, 1998), pages 111-113. */
 147
 148ssize_t drm_read(struct file *filp, char *buf, size_t count, loff_t *off)
 149{
 150        drm_file_t    *priv   = filp->private_data;
 151        drm_device_t  *dev    = priv->dev;
 152        int           left;
 153        int           avail;
 154        int           send;
 155        int           cur;
 156
 157        DRM_DEBUG("%p, %p\n", dev->buf_rp, dev->buf_wp);
 158        
 159        while (dev->buf_rp == dev->buf_wp) {
 160                DRM_DEBUG("  sleeping\n");
 161                if (filp->f_flags & O_NONBLOCK) {
 162                        return -EAGAIN;
 163                }
 164                interruptible_sleep_on(&dev->buf_readers);
 165                if (signal_pending(current)) {
 166                        DRM_DEBUG("  interrupted\n");
 167                        return -ERESTARTSYS;
 168                }
 169                DRM_DEBUG("  awake\n");
 170        }
 171
 172        left  = (dev->buf_rp + DRM_BSZ - dev->buf_wp) % DRM_BSZ;
 173        avail = DRM_BSZ - left;
 174        send  = DRM_MIN(avail, count);
 175
 176        while (send) {
 177                if (dev->buf_wp > dev->buf_rp) {
 178                        cur = DRM_MIN(send, dev->buf_wp - dev->buf_rp);
 179                } else {
 180                        cur = DRM_MIN(send, dev->buf_end - dev->buf_rp);
 181                }
 182                if (copy_to_user(buf, dev->buf_rp, cur))
 183                        return -EFAULT;
 184                dev->buf_rp += cur;
 185                if (dev->buf_rp == dev->buf_end) dev->buf_rp = dev->buf;
 186                send -= cur;
 187        }
 188        
 189        wake_up_interruptible(&dev->buf_writers);
 190        return DRM_MIN(avail, count);;
 191}
 192
 193int drm_write_string(drm_device_t *dev, const char *s)
 194{
 195        int left   = (dev->buf_rp + DRM_BSZ - dev->buf_wp) % DRM_BSZ;
 196        int send   = strlen(s);
 197        int count;
 198
 199        DRM_DEBUG("%d left, %d to send (%p, %p)\n",
 200                  left, send, dev->buf_rp, dev->buf_wp);
 201        
 202        if (left == 1 || dev->buf_wp != dev->buf_rp) {
 203                DRM_ERROR("Buffer not empty (%d left, wp = %p, rp = %p)\n",
 204                          left,
 205                          dev->buf_wp,
 206                          dev->buf_rp);
 207        }
 208
 209        while (send) {
 210                if (dev->buf_wp >= dev->buf_rp) {
 211                        count = DRM_MIN(send, dev->buf_end - dev->buf_wp);
 212                        if (count == left) --count; /* Leave a hole */
 213                } else {
 214                        count = DRM_MIN(send, dev->buf_rp - dev->buf_wp - 1);
 215                }
 216                strncpy(dev->buf_wp, s, count);
 217                dev->buf_wp += count;
 218                if (dev->buf_wp == dev->buf_end) dev->buf_wp = dev->buf;
 219                send -= count;
 220        }
 221
 222#if LINUX_VERSION_CODE < 0x020315 && !defined(KILLFASYNCHASTHREEPARAMETERS)
 223        /* The extra parameter to kill_fasync was added in 2.3.21, and is
 224           _not_ present in _stock_ 2.2.14 and 2.2.15.  However, some
 225           distributions patch 2.2.x kernels to add this parameter.  The
 226           Makefile.linux attempts to detect this addition and defines
 227           KILLFASYNCHASTHREEPARAMETERS if three parameters are found. */
 228        if (dev->buf_async) kill_fasync(dev->buf_async, SIGIO);
 229#else
 230
 231                                /* Parameter added in 2.3.21. */
 232#if LINUX_VERSION_CODE < 0x020400
 233        if (dev->buf_async) kill_fasync(dev->buf_async, SIGIO, POLL_IN);
 234#else
 235                                /* Type of first parameter changed in
 236                                   Linux 2.4.0-test2... */
 237        if (dev->buf_async) kill_fasync(&dev->buf_async, SIGIO, POLL_IN);
 238#endif
 239#endif
 240        DRM_DEBUG("waking\n");
 241        wake_up_interruptible(&dev->buf_readers);
 242        return 0;
 243}
 244
 245unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait)
 246{
 247        drm_file_t   *priv = filp->private_data;
 248        drm_device_t *dev  = priv->dev;
 249
 250        poll_wait(filp, &dev->buf_readers, wait);
 251        if (dev->buf_wp != dev->buf_rp) return POLLIN | POLLRDNORM;
 252        return 0;
 253}
 254
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.