File: /usr/src/linux/drivers/char/drm/drm_fops.h

1     /* drm_fops.h -- File operations for DRM -*- linux-c -*-
2      * Created: Mon Jan  4 08:58:31 1999 by faith@valinux.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      * VA LINUX SYSTEMS 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
25      * OTHER DEALINGS IN THE SOFTWARE.
26      *
27      * Authors:
28      *    Rickard E. (Rik) Faith <faith@valinux.com>
29      *    Daryll Strauss <daryll@valinux.com>
30      *    Gareth Hughes <gareth@valinux.com>
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     
39     int 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) return -ENOMEM;
51     
52     	memset(priv, 0, sizeof(*priv));
53     	filp->private_data  = priv;
54     	priv->uid	    = current->euid;
55     	priv->pid	    = current->pid;
56     	priv->minor	    = minor;
57     	priv->dev	    = dev;
58     	priv->ioctl_count   = 0;
59     	priv->authenticated = capable(CAP_SYS_ADMIN);
60     
61     	down(&dev->struct_sem);
62     	if (!dev->file_last) {
63     		priv->next	= NULL;
64     		priv->prev	= NULL;
65     		dev->file_first = priv;
66     		dev->file_last	= priv;
67     	} else {
68     		priv->next	     = NULL;
69     		priv->prev	     = dev->file_last;
70     		dev->file_last->next = priv;
71     		dev->file_last	     = priv;
72     	}
73     	up(&dev->struct_sem);
74     
75     #ifdef __alpha__
76     	/*
77     	 * Default the hose
78     	 */
79     	if (!dev->hose) {
80     		struct pci_dev *pci_dev;
81     		pci_dev = pci_find_class(PCI_CLASS_DISPLAY_VGA << 8, NULL);
82     		if (pci_dev) dev->hose = pci_dev->sysdata;
83     		if (!dev->hose) {
84     			struct pci_bus *b = pci_bus_b(pci_root_buses.next);
85     			if (b) dev->hose = b->sysdata;
86     		}
87     	}
88     #endif
89     
90     	return 0;
91     }
92     
93     int DRM(flush)(struct file *filp)
94     {
95     	drm_file_t    *priv   = filp->private_data;
96     	drm_device_t  *dev    = priv->dev;
97     
98     	DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d\n",
99     		  current->pid, dev->device, dev->open_count);
100     	return 0;
101     }
102     
103     int DRM(fasync)(int fd, struct file *filp, int on)
104     {
105     	drm_file_t    *priv   = filp->private_data;
106     	drm_device_t  *dev    = priv->dev;
107     	int	      retcode;
108     
109     	DRM_DEBUG("fd = %d, device = 0x%x\n", fd, dev->device);
110     	retcode = fasync_helper(fd, filp, on, &dev->buf_async);
111     	if (retcode < 0) return retcode;
112     	return 0;
113     }
114     
115     
116     /* The drm_read and drm_write_string code (especially that which manages
117        the circular buffer), is based on Alessandro Rubini's LINUX DEVICE
118        DRIVERS (Cambridge: O'Reilly, 1998), pages 111-113. */
119     
120     ssize_t DRM(read)(struct file *filp, char *buf, size_t count, loff_t *off)
121     {
122     	drm_file_t    *priv   = filp->private_data;
123     	drm_device_t  *dev    = priv->dev;
124     	int	      left;
125     	int	      avail;
126     	int	      send;
127     	int	      cur;
128     
129     	DRM_DEBUG("%p, %p\n", dev->buf_rp, dev->buf_wp);
130     
131     	while (dev->buf_rp == dev->buf_wp) {
132     		DRM_DEBUG("  sleeping\n");
133     		if (filp->f_flags & O_NONBLOCK) {
134     			return -EAGAIN;
135     		}
136     		interruptible_sleep_on(&dev->buf_readers);
137     		if (signal_pending(current)) {
138     			DRM_DEBUG("  interrupted\n");
139     			return -ERESTARTSYS;
140     		}
141     		DRM_DEBUG("  awake\n");
142     	}
143     
144     	left  = (dev->buf_rp + DRM_BSZ - dev->buf_wp) % DRM_BSZ;
145     	avail = DRM_BSZ - left;
146     	send  = DRM_MIN(avail, count);
147     
148     	while (send) {
149     		if (dev->buf_wp > dev->buf_rp) {
150     			cur = DRM_MIN(send, dev->buf_wp - dev->buf_rp);
151     		} else {
152     			cur = DRM_MIN(send, dev->buf_end - dev->buf_rp);
153     		}
154     		if (copy_to_user(buf, dev->buf_rp, cur))
155     			return -EFAULT;
156     		dev->buf_rp += cur;
157     		if (dev->buf_rp == dev->buf_end) dev->buf_rp = dev->buf;
158     		send -= cur;
159     	}
160     
161     	wake_up_interruptible(&dev->buf_writers);
162     	return DRM_MIN(avail, count);;
163     }
164     
165     int DRM(write_string)(drm_device_t *dev, const char *s)
166     {
167     	int left   = (dev->buf_rp + DRM_BSZ - dev->buf_wp) % DRM_BSZ;
168     	int send   = strlen(s);
169     	int count;
170     
171     	DRM_DEBUG("%d left, %d to send (%p, %p)\n",
172     		  left, send, dev->buf_rp, dev->buf_wp);
173     
174     	if (left == 1 || dev->buf_wp != dev->buf_rp) {
175     		DRM_ERROR("Buffer not empty (%d left, wp = %p, rp = %p)\n",
176     			  left,
177     			  dev->buf_wp,
178     			  dev->buf_rp);
179     	}
180     
181     	while (send) {
182     		if (dev->buf_wp >= dev->buf_rp) {
183     			count = DRM_MIN(send, dev->buf_end - dev->buf_wp);
184     			if (count == left) --count; /* Leave a hole */
185     		} else {
186     			count = DRM_MIN(send, dev->buf_rp - dev->buf_wp - 1);
187     		}
188     		strncpy(dev->buf_wp, s, count);
189     		dev->buf_wp += count;
190     		if (dev->buf_wp == dev->buf_end) dev->buf_wp = dev->buf;
191     		send -= count;
192     	}
193     
194     #if LINUX_VERSION_CODE < 0x020315 && !defined(KILLFASYNCHASTHREEPARAMETERS)
195     	/* The extra parameter to kill_fasync was added in 2.3.21, and is
196                _not_ present in _stock_ 2.2.14 and 2.2.15.  However, some
197                distributions patch 2.2.x kernels to add this parameter.  The
198                Makefile.linux attempts to detect this addition and defines
199                KILLFASYNCHASTHREEPARAMETERS if three parameters are found. */
200     	if (dev->buf_async) kill_fasync(dev->buf_async, SIGIO);
201     #else
202     
203     				/* Parameter added in 2.3.21. */
204     #if LINUX_VERSION_CODE < 0x020400
205     	if (dev->buf_async) kill_fasync(dev->buf_async, SIGIO, POLL_IN);
206     #else
207     				/* Type of first parameter changed in
208                                        Linux 2.4.0-test2... */
209     	if (dev->buf_async) kill_fasync(&dev->buf_async, SIGIO, POLL_IN);
210     #endif
211     #endif
212     	DRM_DEBUG("waking\n");
213     	wake_up_interruptible(&dev->buf_readers);
214     	return 0;
215     }
216     
217     unsigned int DRM(poll)(struct file *filp, struct poll_table_struct *wait)
218     {
219     	drm_file_t   *priv = filp->private_data;
220     	drm_device_t *dev  = priv->dev;
221     
222     	poll_wait(filp, &dev->buf_readers, wait);
223     	if (dev->buf_wp != dev->buf_rp) return POLLIN | POLLRDNORM;
224     	return 0;
225     }
226