diff options
Diffstat (limited to 'drivers/char/drm/drm_stub.c')
-rw-r--r-- | drivers/char/drm/drm_stub.c | 138 |
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 | ||
39 | unsigned int drm_cards_limit = 16; /* Enough for one machine */ | ||
40 | unsigned int drm_debug = 0; /* 1 to enable debug output */ | 39 | unsigned int drm_debug = 0; /* 1 to enable debug output */ |
41 | EXPORT_SYMBOL(drm_debug); | 40 | EXPORT_SYMBOL(drm_debug); |
42 | 41 | ||
43 | MODULE_AUTHOR(CORE_AUTHOR); | 42 | MODULE_AUTHOR(CORE_AUTHOR); |
44 | MODULE_DESCRIPTION(CORE_DESC); | 43 | MODULE_DESCRIPTION(CORE_DESC); |
45 | MODULE_LICENSE("GPL and additional rights"); | 44 | 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"); | 45 | MODULE_PARM_DESC(debug, "Enable debug output"); |
48 | 46 | ||
49 | module_param_named(cards_limit, drm_cards_limit, int, 0444); | ||
50 | module_param_named(debug, drm_debug, int, 0600); | 47 | module_param_named(debug, drm_debug, int, 0600); |
51 | 48 | ||
52 | struct drm_head **drm_heads; | 49 | struct idr drm_minors_idr; |
50 | |||
53 | struct class *drm_class; | 51 | struct class *drm_class; |
54 | struct proc_dir_entry *drm_proc_root; | 52 | struct proc_dir_entry *drm_proc_root; |
55 | 53 | ||
54 | static 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 | |||
60 | again: | ||
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 | |||
56 | static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev, | 82 | static 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 | */ |
148 | static int drm_get_head(struct drm_device * dev, struct drm_head * head) | 174 | static 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}; | 220 | err_g2: |
221 | if (new_minor->type == DRM_MINOR_LEGACY) | ||
222 | drm_proc_cleanup(new_minor, drm_proc_root); | ||
223 | err_mem: | ||
224 | kfree(new_minor); | ||
225 | err_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 | */ |
279 | int drm_put_head(struct drm_head * head) | 317 | int 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 | } |