aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/drm/drm_stub.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/drm/drm_stub.c')
-rw-r--r--drivers/char/drm/drm_stub.c138
1 files changed, 88 insertions, 50 deletions
diff --git a/drivers/char/drm/drm_stub.c b/drivers/char/drm/drm_stub.c
index d93a217f856a..c2f584f3b46c 100644
--- a/drivers/char/drm/drm_stub.c
+++ b/drivers/char/drm/drm_stub.c
@@ -36,23 +36,49 @@
36#include "drmP.h" 36#include "drmP.h"
37#include "drm_core.h" 37#include "drm_core.h"
38 38
39unsigned int drm_cards_limit = 16; /* Enough for one machine */
40unsigned int drm_debug = 0; /* 1 to enable debug output */ 39unsigned int drm_debug = 0; /* 1 to enable debug output */
41EXPORT_SYMBOL(drm_debug); 40EXPORT_SYMBOL(drm_debug);
42 41
43MODULE_AUTHOR(CORE_AUTHOR); 42MODULE_AUTHOR(CORE_AUTHOR);
44MODULE_DESCRIPTION(CORE_DESC); 43MODULE_DESCRIPTION(CORE_DESC);
45MODULE_LICENSE("GPL and additional rights"); 44MODULE_LICENSE("GPL and additional rights");
46MODULE_PARM_DESC(cards_limit, "Maximum number of graphics cards");
47MODULE_PARM_DESC(debug, "Enable debug output"); 45MODULE_PARM_DESC(debug, "Enable debug output");
48 46
49module_param_named(cards_limit, drm_cards_limit, int, 0444);
50module_param_named(debug, drm_debug, int, 0600); 47module_param_named(debug, drm_debug, int, 0600);
51 48
52struct drm_head **drm_heads; 49struct idr drm_minors_idr;
50
53struct class *drm_class; 51struct class *drm_class;
54struct proc_dir_entry *drm_proc_root; 52struct proc_dir_entry *drm_proc_root;
55 53
54static int drm_minor_get_id(struct drm_device *dev, int type)
55{
56 int new_id;
57 int ret;
58 int base = 0, limit = 63;
59
60again:
61 if (idr_pre_get(&drm_minors_idr, GFP_KERNEL) == 0) {
62 DRM_ERROR("Out of memory expanding drawable idr\n");
63 return -ENOMEM;
64 }
65 mutex_lock(&dev->struct_mutex);
66 ret = idr_get_new_above(&drm_minors_idr, NULL,
67 base, &new_id);
68 mutex_unlock(&dev->struct_mutex);
69 if (ret == -EAGAIN) {
70 goto again;
71 } else if (ret) {
72 return ret;
73 }
74
75 if (new_id >= limit) {
76 idr_remove(&drm_minors_idr, new_id);
77 return -EINVAL;
78 }
79 return new_id;
80}
81
56static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev, 82static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev,
57 const struct pci_device_id *ent, 83 const struct pci_device_id *ent,
58 struct drm_driver *driver) 84 struct drm_driver *driver)
@@ -145,48 +171,60 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev,
145 * create the proc init entry via proc_init(). This routines assigns 171 * create the proc init entry via proc_init(). This routines assigns
146 * minor numbers to secondary heads of multi-headed cards 172 * minor numbers to secondary heads of multi-headed cards
147 */ 173 */
148static int drm_get_head(struct drm_device * dev, struct drm_head * head) 174static int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, int type)
149{ 175{
150 struct drm_head **heads = drm_heads; 176 struct drm_minor *new_minor;
151 int ret; 177 int ret;
152 int minor; 178 int minor_id;
153 179
154 DRM_DEBUG("\n"); 180 DRM_DEBUG("\n");
155 181
156 for (minor = 0; minor < drm_cards_limit; minor++, heads++) { 182 minor_id = drm_minor_get_id(dev, type);
157 if (!*heads) { 183 if (minor_id < 0)
158 184 return minor_id;
159 *head = (struct drm_head) { 185
160 .dev = dev,.device = 186 new_minor = kzalloc(sizeof(struct drm_minor), GFP_KERNEL);
161 MKDEV(DRM_MAJOR, minor),.minor = minor,}; 187 if (!new_minor) {
162 188 ret = -ENOMEM;
163 if ((ret = 189 goto err_idr;
164 drm_proc_init(dev, minor, drm_proc_root, 190 }
165 &head->dev_root))) { 191
166 printk(KERN_ERR 192 new_minor->type = type;
167 "DRM: Failed to initialize /proc/dri.\n"); 193 new_minor->device = MKDEV(DRM_MAJOR, minor_id);
168 goto err_g1; 194 new_minor->dev = dev;
169 } 195 new_minor->index = minor_id;
170 196
171 ret = drm_sysfs_device_add(dev, head); 197 idr_replace(&drm_minors_idr, new_minor, minor_id);
172 if (ret) { 198
173 printk(KERN_ERR 199 if (type == DRM_MINOR_LEGACY) {
174 "DRM: Error sysfs_device_add.\n"); 200 ret = drm_proc_init(new_minor, minor_id, drm_proc_root);
175 goto err_g2; 201 if (ret) {
176 } 202 DRM_ERROR("DRM: Failed to initialize /proc/dri.\n");
177 *heads = head; 203 goto err_mem;
178
179 DRM_DEBUG("new minor assigned %d\n", minor);
180 return 0;
181 } 204 }
205 } else
206 new_minor->dev_root = NULL;
207
208 ret = drm_sysfs_device_add(new_minor);
209 if (ret) {
210 printk(KERN_ERR
211 "DRM: Error sysfs_device_add.\n");
212 goto err_g2;
182 } 213 }
183 DRM_ERROR("out of minors\n"); 214 *minor = new_minor;
184 return -ENOMEM; 215
185 err_g2: 216 DRM_DEBUG("new minor assigned %d\n", minor_id);
186 drm_proc_cleanup(minor, drm_proc_root, head->dev_root); 217 return 0;
187 err_g1: 218
188 *head = (struct drm_head) { 219
189 .dev = NULL}; 220err_g2:
221 if (new_minor->type == DRM_MINOR_LEGACY)
222 drm_proc_cleanup(new_minor, drm_proc_root);
223err_mem:
224 kfree(new_minor);
225err_idr:
226 idr_remove(&drm_minors_idr, minor_id);
227 *minor = NULL;
190 return ret; 228 return ret;
191} 229}
192 230
@@ -222,12 +260,12 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
222 printk(KERN_ERR "DRM: Fill_in_dev failed.\n"); 260 printk(KERN_ERR "DRM: Fill_in_dev failed.\n");
223 goto err_g2; 261 goto err_g2;
224 } 262 }
225 if ((ret = drm_get_head(dev, &dev->primary))) 263 if ((ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_LEGACY)))
226 goto err_g2; 264 goto err_g2;
227 265
228 DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", 266 DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",
229 driver->name, driver->major, driver->minor, driver->patchlevel, 267 driver->name, driver->major, driver->minor, driver->patchlevel,
230 driver->date, dev->primary.minor); 268 driver->date, dev->primary->index);
231 269
232 return 0; 270 return 0;
233 271
@@ -276,18 +314,18 @@ int drm_put_dev(struct drm_device * dev)
276 * last minor released. 314 * last minor released.
277 * 315 *
278 */ 316 */
279int drm_put_head(struct drm_head * head) 317int drm_put_minor(struct drm_minor **minor_p)
280{ 318{
281 int minor = head->minor; 319 struct drm_minor *minor = *minor_p;
282 320 DRM_DEBUG("release secondary minor %d\n", minor->index);
283 DRM_DEBUG("release secondary minor %d\n", minor);
284
285 drm_proc_cleanup(minor, drm_proc_root, head->dev_root);
286 drm_sysfs_device_remove(head->dev);
287 321
288 *head = (struct drm_head) {.dev = NULL}; 322 if (minor->type == DRM_MINOR_LEGACY)
323 drm_proc_cleanup(minor, drm_proc_root);
324 drm_sysfs_device_remove(minor);
289 325
290 drm_heads[minor] = NULL; 326 idr_remove(&drm_minors_idr, minor->index);
291 327
328 kfree(minor);
329 *minor_p = NULL;
292 return 0; 330 return 0;
293} 331}