diff options
Diffstat (limited to 'drivers/char/drm/drm_stub.c')
-rw-r--r-- | drivers/char/drm/drm_stub.c | 319 |
1 files changed, 319 insertions, 0 deletions
diff --git a/drivers/char/drm/drm_stub.c b/drivers/char/drm/drm_stub.c new file mode 100644 index 000000000000..8ccbdef7bb3e --- /dev/null +++ b/drivers/char/drm/drm_stub.c | |||
@@ -0,0 +1,319 @@ | |||
1 | /** | ||
2 | * \file drm_stub.h | ||
3 | * Stub support | ||
4 | * | ||
5 | * \author Rickard E. (Rik) Faith <faith@valinux.com> | ||
6 | */ | ||
7 | |||
8 | /* | ||
9 | * Created: Fri Jan 19 10:48:35 2001 by faith@acm.org | ||
10 | * | ||
11 | * Copyright 2001 VA Linux Systems, Inc., Sunnyvale, California. | ||
12 | * All Rights Reserved. | ||
13 | * | ||
14 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
15 | * copy of this software and associated documentation files (the "Software"), | ||
16 | * to deal in the Software without restriction, including without limitation | ||
17 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
18 | * and/or sell copies of the Software, and to permit persons to whom the | ||
19 | * Software is furnished to do so, subject to the following conditions: | ||
20 | * | ||
21 | * The above copyright notice and this permission notice (including the next | ||
22 | * paragraph) shall be included in all copies or substantial portions of the | ||
23 | * Software. | ||
24 | * | ||
25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
26 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
27 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
28 | * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
29 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
30 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
31 | * DEALINGS IN THE SOFTWARE. | ||
32 | */ | ||
33 | |||
34 | #include <linux/module.h> | ||
35 | #include <linux/moduleparam.h> | ||
36 | #include "drmP.h" | ||
37 | #include "drm_core.h" | ||
38 | |||
39 | unsigned int drm_cards_limit = 16; /* Enough for one machine */ | ||
40 | unsigned int drm_debug = 0; /* 1 to enable debug output */ | ||
41 | EXPORT_SYMBOL(drm_debug); | ||
42 | |||
43 | MODULE_AUTHOR( CORE_AUTHOR ); | ||
44 | MODULE_DESCRIPTION( CORE_DESC ); | ||
45 | MODULE_LICENSE("GPL and additional rights"); | ||
46 | MODULE_PARM_DESC(cards_limit, "Maximum number of graphics cards"); | ||
47 | MODULE_PARM_DESC(debug, "Enable debug output"); | ||
48 | |||
49 | module_param_named(cards_limit, drm_cards_limit, int, 0444); | ||
50 | module_param_named(debug, drm_debug, int, 0666); | ||
51 | |||
52 | drm_head_t **drm_heads; | ||
53 | struct drm_sysfs_class *drm_class; | ||
54 | struct proc_dir_entry *drm_proc_root; | ||
55 | |||
56 | static int drm_fill_in_dev(drm_device_t *dev, struct pci_dev *pdev, const struct pci_device_id *ent, struct drm_driver *driver) | ||
57 | { | ||
58 | int retcode; | ||
59 | |||
60 | spin_lock_init(&dev->count_lock); | ||
61 | init_timer( &dev->timer ); | ||
62 | sema_init( &dev->struct_sem, 1 ); | ||
63 | sema_init( &dev->ctxlist_sem, 1 ); | ||
64 | |||
65 | dev->pdev = pdev; | ||
66 | |||
67 | #ifdef __alpha__ | ||
68 | dev->hose = pdev->sysdata; | ||
69 | dev->pci_domain = dev->hose->bus->number; | ||
70 | #else | ||
71 | dev->pci_domain = 0; | ||
72 | #endif | ||
73 | dev->pci_bus = pdev->bus->number; | ||
74 | dev->pci_slot = PCI_SLOT(pdev->devfn); | ||
75 | dev->pci_func = PCI_FUNC(pdev->devfn); | ||
76 | dev->irq = pdev->irq; | ||
77 | |||
78 | /* the DRM has 6 basic counters */ | ||
79 | dev->counters = 6; | ||
80 | dev->types[0] = _DRM_STAT_LOCK; | ||
81 | dev->types[1] = _DRM_STAT_OPENS; | ||
82 | dev->types[2] = _DRM_STAT_CLOSES; | ||
83 | dev->types[3] = _DRM_STAT_IOCTLS; | ||
84 | dev->types[4] = _DRM_STAT_LOCKS; | ||
85 | dev->types[5] = _DRM_STAT_UNLOCKS; | ||
86 | |||
87 | dev->driver = driver; | ||
88 | |||
89 | if (dev->driver->preinit) | ||
90 | if ((retcode = dev->driver->preinit(dev, ent->driver_data))) | ||
91 | goto error_out_unreg; | ||
92 | |||
93 | if (drm_core_has_AGP(dev)) { | ||
94 | dev->agp = drm_agp_init(dev); | ||
95 | if (drm_core_check_feature(dev, DRIVER_REQUIRE_AGP) && (dev->agp == NULL)) { | ||
96 | DRM_ERROR( "Cannot initialize the agpgart module.\n" ); | ||
97 | retcode = -EINVAL; | ||
98 | goto error_out_unreg; | ||
99 | } | ||
100 | if (drm_core_has_MTRR(dev)) { | ||
101 | if (dev->agp) | ||
102 | dev->agp->agp_mtrr = mtrr_add( dev->agp->agp_info.aper_base, | ||
103 | dev->agp->agp_info.aper_size*1024*1024, | ||
104 | MTRR_TYPE_WRCOMB, | ||
105 | 1 ); | ||
106 | } | ||
107 | } | ||
108 | |||
109 | retcode = drm_ctxbitmap_init( dev ); | ||
110 | if( retcode ) { | ||
111 | DRM_ERROR( "Cannot allocate memory for context bitmap.\n" ); | ||
112 | goto error_out_unreg; | ||
113 | } | ||
114 | |||
115 | return 0; | ||
116 | |||
117 | error_out_unreg: | ||
118 | drm_takedown(dev); | ||
119 | return retcode; | ||
120 | } | ||
121 | |||
122 | /** | ||
123 | * File \c open operation. | ||
124 | * | ||
125 | * \param inode device inode. | ||
126 | * \param filp file pointer. | ||
127 | * | ||
128 | * Puts the dev->fops corresponding to the device minor number into | ||
129 | * \p filp, call the \c open method, and restore the file operations. | ||
130 | */ | ||
131 | int drm_stub_open(struct inode *inode, struct file *filp) | ||
132 | { | ||
133 | drm_device_t *dev = NULL; | ||
134 | int minor = iminor(inode); | ||
135 | int err = -ENODEV; | ||
136 | struct file_operations *old_fops; | ||
137 | |||
138 | DRM_DEBUG("\n"); | ||
139 | |||
140 | if (!((minor >= 0) && (minor < drm_cards_limit))) | ||
141 | return -ENODEV; | ||
142 | |||
143 | if (!drm_heads[minor]) | ||
144 | return -ENODEV; | ||
145 | |||
146 | if (!(dev = drm_heads[minor]->dev)) | ||
147 | return -ENODEV; | ||
148 | |||
149 | old_fops = filp->f_op; | ||
150 | filp->f_op = fops_get(&dev->driver->fops); | ||
151 | if (filp->f_op->open && (err = filp->f_op->open(inode, filp))) { | ||
152 | fops_put(filp->f_op); | ||
153 | filp->f_op = fops_get(old_fops); | ||
154 | } | ||
155 | fops_put(old_fops); | ||
156 | |||
157 | return err; | ||
158 | } | ||
159 | |||
160 | |||
161 | /** | ||
162 | * Register. | ||
163 | * | ||
164 | * \param pdev - PCI device structure | ||
165 | * \param ent entry from the PCI ID table with device type flags | ||
166 | * \return zero on success or a negative number on failure. | ||
167 | * | ||
168 | * Attempt to gets inter module "drm" information. If we are first | ||
169 | * then register the character device and inter module information. | ||
170 | * Try and register, if we fail to register, backout previous work. | ||
171 | */ | ||
172 | int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, | ||
173 | struct drm_driver *driver) | ||
174 | { | ||
175 | drm_device_t *dev; | ||
176 | int ret; | ||
177 | |||
178 | DRM_DEBUG("\n"); | ||
179 | |||
180 | dev = drm_calloc(1, sizeof(*dev), DRM_MEM_STUB); | ||
181 | if (!dev) | ||
182 | return -ENOMEM; | ||
183 | |||
184 | pci_enable_device(pdev); | ||
185 | |||
186 | if ((ret = drm_fill_in_dev(dev, pdev, ent, driver))) { | ||
187 | printk(KERN_ERR "DRM: Fill_in_dev failed.\n"); | ||
188 | goto err_g1; | ||
189 | } | ||
190 | if ((ret = drm_get_head(dev, &dev->primary))) | ||
191 | goto err_g1; | ||
192 | |||
193 | /* postinit is a required function to display the signon banner */ | ||
194 | /* drivers add secondary heads here if needed */ | ||
195 | if ((ret = dev->driver->postinit(dev, ent->driver_data))) | ||
196 | goto err_g1; | ||
197 | |||
198 | return 0; | ||
199 | |||
200 | err_g1: | ||
201 | drm_free(dev, sizeof(*dev), DRM_MEM_STUB); | ||
202 | return ret; | ||
203 | } | ||
204 | EXPORT_SYMBOL(drm_get_dev); | ||
205 | |||
206 | /** | ||
207 | * Get a secondary minor number. | ||
208 | * | ||
209 | * \param dev device data structure | ||
210 | * \param sec-minor structure to hold the assigned minor | ||
211 | * \return negative number on failure. | ||
212 | * | ||
213 | * Search an empty entry and initialize it to the given parameters, and | ||
214 | * create the proc init entry via proc_init(). This routines assigns | ||
215 | * minor numbers to secondary heads of multi-headed cards | ||
216 | */ | ||
217 | int drm_get_head(drm_device_t *dev, drm_head_t *head) | ||
218 | { | ||
219 | drm_head_t **heads = drm_heads; | ||
220 | int ret; | ||
221 | int minor; | ||
222 | |||
223 | DRM_DEBUG("\n"); | ||
224 | |||
225 | for (minor = 0; minor < drm_cards_limit; minor++, heads++) { | ||
226 | if (!*heads) { | ||
227 | |||
228 | *head = (drm_head_t) { | ||
229 | .dev = dev, | ||
230 | .device = MKDEV(DRM_MAJOR, minor), | ||
231 | .minor = minor, | ||
232 | }; | ||
233 | |||
234 | if ((ret = drm_proc_init(dev, minor, drm_proc_root, &head->dev_root))) { | ||
235 | printk (KERN_ERR "DRM: Failed to initialize /proc/dri.\n"); | ||
236 | goto err_g1; | ||
237 | } | ||
238 | |||
239 | |||
240 | head->dev_class = drm_sysfs_device_add(drm_class, | ||
241 | MKDEV(DRM_MAJOR, | ||
242 | minor), | ||
243 | &dev->pdev->dev, | ||
244 | "card%d", minor); | ||
245 | if (IS_ERR(head->dev_class)) { | ||
246 | printk(KERN_ERR "DRM: Error sysfs_device_add.\n"); | ||
247 | ret = PTR_ERR(head->dev_class); | ||
248 | goto err_g2; | ||
249 | } | ||
250 | *heads = head; | ||
251 | |||
252 | DRM_DEBUG("new minor assigned %d\n", minor); | ||
253 | return 0; | ||
254 | } | ||
255 | } | ||
256 | DRM_ERROR("out of minors\n"); | ||
257 | return -ENOMEM; | ||
258 | err_g2: | ||
259 | drm_proc_cleanup(minor, drm_proc_root, head->dev_root); | ||
260 | err_g1: | ||
261 | *head = (drm_head_t) {.dev = NULL}; | ||
262 | return ret; | ||
263 | } | ||
264 | |||
265 | |||
266 | /** | ||
267 | * Put a device minor number. | ||
268 | * | ||
269 | * \param dev device data structure | ||
270 | * \return always zero | ||
271 | * | ||
272 | * Cleans up the proc resources. If it is the last minor then release the foreign | ||
273 | * "drm" data, otherwise unregisters the "drm" data, frees the dev list and | ||
274 | * unregisters the character device. | ||
275 | */ | ||
276 | int drm_put_dev(drm_device_t * dev) | ||
277 | { | ||
278 | DRM_DEBUG("release primary %s\n", dev->driver->pci_driver.name); | ||
279 | |||
280 | if (dev->unique) { | ||
281 | drm_free(dev->unique, strlen(dev->unique) + 1, DRM_MEM_DRIVER); | ||
282 | dev->unique = NULL; | ||
283 | dev->unique_len = 0; | ||
284 | } | ||
285 | if (dev->devname) { | ||
286 | drm_free(dev->devname, strlen(dev->devname) + 1, | ||
287 | DRM_MEM_DRIVER); | ||
288 | dev->devname = NULL; | ||
289 | } | ||
290 | drm_free(dev, sizeof(*dev), DRM_MEM_STUB); | ||
291 | return 0; | ||
292 | } | ||
293 | |||
294 | /** | ||
295 | * Put a secondary minor number. | ||
296 | * | ||
297 | * \param sec_minor - structure to be released | ||
298 | * \return always zero | ||
299 | * | ||
300 | * Cleans up the proc resources. Not legal for this to be the | ||
301 | * last minor released. | ||
302 | * | ||
303 | */ | ||
304 | int drm_put_head(drm_head_t *head) | ||
305 | { | ||
306 | int minor = head->minor; | ||
307 | |||
308 | DRM_DEBUG("release secondary minor %d\n", minor); | ||
309 | |||
310 | drm_proc_cleanup(minor, drm_proc_root, head->dev_root); | ||
311 | drm_sysfs_device_remove(MKDEV(DRM_MAJOR, head->minor)); | ||
312 | |||
313 | *head = (drm_head_t){.dev = NULL}; | ||
314 | |||
315 | drm_heads[minor] = NULL; | ||
316 | |||
317 | return 0; | ||
318 | } | ||
319 | |||