drm: reorganise minor number handling using backported modesetting code.
[safe/jmp/linux-2.6] / drivers / char / drm / drm_stub.c
index 59a9e7e..c2f584f 100644 (file)
 #include "drmP.h"
 #include "drm_core.h"
 
-unsigned int drm_cards_limit = 16;     /* Enough for one machine */
 unsigned int drm_debug = 0;    /* 1 to enable debug output */
 EXPORT_SYMBOL(drm_debug);
 
 MODULE_AUTHOR(CORE_AUTHOR);
 MODULE_DESCRIPTION(CORE_DESC);
 MODULE_LICENSE("GPL and additional rights");
-MODULE_PARM_DESC(cards_limit, "Maximum number of graphics cards");
 MODULE_PARM_DESC(debug, "Enable debug output");
 
-module_param_named(cards_limit, drm_cards_limit, int, 0444);
 module_param_named(debug, drm_debug, int, 0600);
 
-drm_head_t **drm_heads;
+struct idr drm_minors_idr;
+
 struct class *drm_class;
 struct proc_dir_entry *drm_proc_root;
 
-static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev,
+static int drm_minor_get_id(struct drm_device *dev, int type)
+{
+       int new_id;
+       int ret;
+       int base = 0, limit = 63;
+
+again:
+       if (idr_pre_get(&drm_minors_idr, GFP_KERNEL) == 0) {
+               DRM_ERROR("Out of memory expanding drawable idr\n");
+               return -ENOMEM;
+       }
+       mutex_lock(&dev->struct_mutex);
+       ret = idr_get_new_above(&drm_minors_idr, NULL,
+                               base, &new_id);
+       mutex_unlock(&dev->struct_mutex);
+       if (ret == -EAGAIN) {
+               goto again;
+       } else if (ret) {
+               return ret;
+       }
+
+       if (new_id >= limit) {
+               idr_remove(&drm_minors_idr, new_id);
+               return -EINVAL;
+       }
+       return new_id;
+}
+
+static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev,
                           const struct pci_device_id *ent,
                           struct drm_driver *driver)
 {
        int retcode;
 
        INIT_LIST_HEAD(&dev->filelist);
+       INIT_LIST_HEAD(&dev->ctxlist);
+       INIT_LIST_HEAD(&dev->vmalist);
+       INIT_LIST_HEAD(&dev->maplist);
+
        spin_lock_init(&dev->count_lock);
        spin_lock_init(&dev->drw_lock);
        spin_lock_init(&dev->tasklet_lock);
@@ -68,6 +98,8 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev,
        mutex_init(&dev->struct_mutex);
        mutex_init(&dev->ctxlist_mutex);
 
+       idr_init(&dev->drw_idr);
+
        dev->pdev = pdev;
        dev->pci_device = pdev->device;
        dev->pci_vendor = pdev->vendor;
@@ -81,8 +113,6 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev,
                return -ENOMEM;
        }
 
-       INIT_LIST_HEAD(&dev->maplist);
-
        /* the DRM has 6 basic counters */
        dev->counters = 6;
        dev->types[0] = _DRM_STAT_LOCK;
@@ -94,10 +124,6 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev,
 
        dev->driver = driver;
 
-       if (dev->driver->load)
-               if ((retcode = dev->driver->load(dev, ent->driver_data)))
-                       goto error_out_unreg;
-
        if (drm_core_has_AGP(dev)) {
                if (drm_device_is_agp(dev))
                        dev->agp = drm_agp_init(dev);
@@ -116,6 +142,10 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev,
                }
        }
 
+       if (dev->driver->load)
+               if ((retcode = dev->driver->load(dev, ent->driver_data)))
+                       goto error_out_unreg;
+
        retcode = drm_ctxbitmap_init(dev);
        if (retcode) {
                DRM_ERROR("Cannot allocate memory for context bitmap.\n");
@@ -141,49 +171,60 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev,
  * create the proc init entry via proc_init(). This routines assigns
  * minor numbers to secondary heads of multi-headed cards
  */
-static int drm_get_head(drm_device_t * dev, drm_head_t * head)
+static int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, int type)
 {
-       drm_head_t **heads = drm_heads;
+       struct drm_minor *new_minor;
        int ret;
-       int minor;
+       int minor_id;
 
        DRM_DEBUG("\n");
 
-       for (minor = 0; minor < drm_cards_limit; minor++, heads++) {
-               if (!*heads) {
-
-                       *head = (drm_head_t) {
-                       .dev = dev,.device =
-                                   MKDEV(DRM_MAJOR, minor),.minor = minor,};
-
-                       if ((ret =
-                            drm_proc_init(dev, minor, drm_proc_root,
-                                          &head->dev_root))) {
-                               printk(KERN_ERR
-                                      "DRM: Failed to initialize /proc/dri.\n");
-                               goto err_g1;
-                       }
-
-                       head->dev_class = drm_sysfs_device_add(drm_class, head);
-                       if (IS_ERR(head->dev_class)) {
-                               printk(KERN_ERR
-                                      "DRM: Error sysfs_device_add.\n");
-                               ret = PTR_ERR(head->dev_class);
-                               goto err_g2;
-                       }
-                       *heads = head;
-
-                       DRM_DEBUG("new minor assigned %d\n", minor);
-                       return 0;
+       minor_id = drm_minor_get_id(dev, type);
+       if (minor_id < 0)
+               return minor_id;
+
+       new_minor = kzalloc(sizeof(struct drm_minor), GFP_KERNEL);
+       if (!new_minor) {
+               ret = -ENOMEM;
+               goto err_idr;
+       }
+
+       new_minor->type = type;
+       new_minor->device = MKDEV(DRM_MAJOR, minor_id);
+       new_minor->dev = dev;
+       new_minor->index = minor_id;
+
+       idr_replace(&drm_minors_idr, new_minor, minor_id);
+
+       if (type == DRM_MINOR_LEGACY) {
+               ret = drm_proc_init(new_minor, minor_id, drm_proc_root);
+               if (ret) {
+                       DRM_ERROR("DRM: Failed to initialize /proc/dri.\n");
+                       goto err_mem;
                }
+       } else
+               new_minor->dev_root = NULL;
+
+       ret = drm_sysfs_device_add(new_minor);
+       if (ret) {
+               printk(KERN_ERR
+                      "DRM: Error sysfs_device_add.\n");
+               goto err_g2;
        }
-       DRM_ERROR("out of minors\n");
-       return -ENOMEM;
-      err_g2:
-       drm_proc_cleanup(minor, drm_proc_root, head->dev_root);
-      err_g1:
-       *head = (drm_head_t) {
-       .dev = NULL};
+       *minor = new_minor;
+
+       DRM_DEBUG("new minor assigned %d\n", minor_id);
+       return 0;
+
+
+err_g2:
+       if (new_minor->type == DRM_MINOR_LEGACY)
+               drm_proc_cleanup(new_minor, drm_proc_root);
+err_mem:
+       kfree(new_minor);
+err_idr:
+       idr_remove(&drm_minors_idr, minor_id);
+       *minor = NULL;
        return ret;
 }
 
@@ -201,7 +242,7 @@ static int drm_get_head(drm_device_t * dev, drm_head_t * head)
 int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
                struct drm_driver *driver)
 {
-       drm_device_t *dev;
+       struct drm_device *dev;
        int ret;
 
        DRM_DEBUG("\n");
@@ -214,16 +255,17 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
        if (ret)
                goto err_g1;
 
+       pci_set_master(pdev);
        if ((ret = drm_fill_in_dev(dev, pdev, ent, driver))) {
                printk(KERN_ERR "DRM: Fill_in_dev failed.\n");
                goto err_g2;
        }
-       if ((ret = drm_get_head(dev, &dev->primary)))
+       if ((ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_LEGACY)))
                goto err_g2;
-       
+
        DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",
                 driver->name, driver->major, driver->minor, driver->patchlevel,
-                driver->date, dev->primary.minor);
+                driver->date, dev->primary->index);
 
        return 0;
 
@@ -244,7 +286,7 @@ err_g1:
  * "drm" data, otherwise unregisters the "drm" data, frees the dev list and
  * unregisters the character device.
  */
-int drm_put_dev(drm_device_t * dev)
+int drm_put_dev(struct drm_device * dev)
 {
        DRM_DEBUG("release primary %s\n", dev->driver->pci_driver.name);
 
@@ -272,18 +314,18 @@ int drm_put_dev(drm_device_t * dev)
  * last minor released.
  *
  */
-int drm_put_head(drm_head_t * head)
+int drm_put_minor(struct drm_minor **minor_p)
 {
-       int minor = head->minor;
-
-       DRM_DEBUG("release secondary minor %d\n", minor);
-
-       drm_proc_cleanup(minor, drm_proc_root, head->dev_root);
-       drm_sysfs_device_remove(head->dev_class);
+       struct drm_minor *minor = *minor_p;
+       DRM_DEBUG("release secondary minor %d\n", minor->index);
 
-       *head = (drm_head_t) {.dev = NULL};
+       if (minor->type == DRM_MINOR_LEGACY)
+               drm_proc_cleanup(minor, drm_proc_root);
+       drm_sysfs_device_remove(minor);
 
-       drm_heads[minor] = NULL;
+       idr_remove(&drm_minors_idr, minor->index);
 
+       kfree(minor);
+       *minor_p = NULL;
        return 0;
 }