OSDN Git Service

drm: initial mode object groups.
[android-x86/external-libdrm.git] / linux-core / drm_stub.c
index c03a56a..45b8f38 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, S_IRUGO);
-module_param_named(debug, drm_debug, int, S_IRUGO|S_IWUGO);
+module_param_named(debug, drm_debug, int, 0600);
 
-drm_head_t **drm_heads;
-struct drm_sysfs_class *drm_class;
+struct idr drm_minors_idr;
+
+struct class *drm_class;
 struct proc_dir_entry *drm_proc_root;
 
-drm_cache_t drm_cache =
-{ .mm = NULL,
-  .fence_object = NULL
-};
+static int drm_minor_get_id(struct drm_device *dev, int type)
+{
+       int new_id;
+       int ret;
+       int base = 0, limit = 63;
+
+       if (type == DRM_MINOR_CONTROL) {
+               base += 64;
+               limit = base + 127;
+       } else if (type == DRM_MINOR_RENDER) {
+               base += 128;
+               limit = base + 255;
+       }       
+
+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;
+}
+
+int drm_setmaster_ioctl(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv)
+{
+       if (file_priv->minor->master && file_priv->minor->master != file_priv->master)
+               return -EINVAL;
+
+       if (!file_priv->master)
+               return -EINVAL;
+
+       if (!file_priv->minor->master && file_priv->minor->master != file_priv->master)
+               file_priv->minor->master = file_priv->master;
+       return 0;
+}
+
+int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv)
+{
+       if (!file_priv->master)
+               return -EINVAL;
+       file_priv->minor->master = NULL;
+       return 0;
+}
+
+struct drm_master *drm_get_master(struct drm_minor *minor)
+{
+       struct drm_master *master;
+
+       master = drm_calloc(1, sizeof(*master), DRM_MEM_DRIVER);
+       if (!master)
+               return NULL;
+
+//     INIT_LIST_HEAD(&master->filelist);
+       spin_lock_init(&master->lock.spinlock);
+       init_waitqueue_head(&master->lock.lock_queue);
+       drm_ht_create(&master->magiclist, DRM_MAGIC_HASH_ORDER);
+       INIT_LIST_HEAD(&master->magicfree);
+       master->minor = minor;
 
-static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev,
-                      const struct pci_device_id *ent,
-                      struct drm_driver *driver)
+       list_add_tail(&master->head, &minor->master_list);
+
+       return master;
+}
+
+void drm_put_master(struct drm_master *master)
+{
+       struct drm_magic_entry *pt, *next;
+       struct drm_device *dev = master->minor->dev;
+
+       list_del(&master->head);
+
+       if (dev->driver->master_destroy)
+               dev->driver->master_destroy(dev, master);
+
+       if (master->unique) {
+               drm_free(master->unique, strlen(master->unique) + 1, DRM_MEM_DRIVER);
+               master->unique = NULL;
+               master->unique_len = 0;
+       }
+
+       list_for_each_entry_safe(pt, next, &master->magicfree, head) {
+               list_del(&pt->head);
+               drm_ht_remove_item(&master->magiclist, &pt->hash_item);
+               drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
+       }
+
+       drm_ht_remove(&master->magiclist);
+
+       if (master->lock.hw_lock) {
+               if (dev->sigdata.lock == master->lock.hw_lock)
+                       dev->sigdata.lock = NULL;
+               master->lock.hw_lock = NULL;    /* SHM removed */
+               master->lock.file_priv = NULL;
+               wake_up_interruptible(&master->lock.lock_queue);
+       }
+
+       drm_free(master, sizeof(*master), DRM_MEM_DRIVER);
+}
+
+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->ctxlist);
+       INIT_LIST_HEAD(&dev->vmalist);
+       INIT_LIST_HEAD(&dev->maplist);
+       INIT_LIST_HEAD(&dev->filelist);
+
        spin_lock_init(&dev->count_lock);
        spin_lock_init(&dev->drw_lock);
        spin_lock_init(&dev->tasklet_lock);
+//     spin_lock_init(&dev->lock.spinlock);
        init_timer(&dev->timer);
        mutex_init(&dev->struct_mutex);
        mutex_init(&dev->ctxlist_mutex);
-       mutex_init(&dev->bm.init_mutex);
+       mutex_init(&dev->bm.evict_mutex);
+
+       idr_init(&dev->drw_idr);
 
        dev->pdev = pdev;
        dev->pci_device = pdev->device;
@@ -81,30 +196,23 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev,
        dev->hose = pdev->sysdata;
 #endif
        dev->irq = pdev->irq;
+       dev->irq_enabled = 0;
 
-       if (drm_ht_create(&dev->map_hash, DRM_MAP_HASH_ORDER)) {
-               drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS);
+       if (drm_ht_create(&dev->map_hash, DRM_MAP_HASH_ORDER))
                return -ENOMEM;
-       }
-       if (drm_mm_init(&dev->offset_manager, DRM_FILE_PAGE_OFFSET_START, 
+
+       if (drm_mm_init(&dev->offset_manager, DRM_FILE_PAGE_OFFSET_START,
                        DRM_FILE_PAGE_OFFSET_SIZE)) {
-               drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS);
                drm_ht_remove(&dev->map_hash);
                return -ENOMEM;
        }
 
        if (drm_ht_create(&dev->object_hash, DRM_OBJECT_HASH_ORDER)) {
-                drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS);
                drm_ht_remove(&dev->map_hash);
                drm_mm_takedown(&dev->offset_manager);
                return -ENOMEM;
        }
 
-       dev->maplist = drm_calloc(1, sizeof(*dev->maplist), DRM_MEM_MAPS);
-       if (dev->maplist == NULL)
-               return -ENOMEM;
-       INIT_LIST_HEAD(&dev->maplist->head);
-
        /* the DRM has 6 counters */
        dev->counters = 6;
        dev->types[0] = _DRM_STAT_LOCK;
@@ -116,10 +224,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);
@@ -164,50 +268,61 @@ error_out_unreg:
  * 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;
+       INIT_LIST_HEAD(&new_minor->master_list);
+
+       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;
+       *minor = new_minor;
+       
+       DRM_DEBUG("new minor assigned %d\n", minor_id);
+       return 0;
+
+
 err_g2:
-       drm_proc_cleanup(minor, drm_proc_root, head->dev_root);
-err_g1:
-       *head = (drm_head_t) {
-               .dev = NULL};
+       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;
 }
 
@@ -223,9 +338,9 @@ err_g1:
  * Try and register, if we fail to register, backout previous work.
  */
 int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
-             struct drm_driver *driver)
+               struct drm_driver *driver)
 {
-       drm_device_t *dev;
+       struct drm_device *dev;
        int ret;
 
        DRM_DEBUG("\n");
@@ -236,31 +351,58 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
 
        if (!drm_fb_loaded) {
                pci_set_drvdata(pdev, dev);
-               pci_request_regions(pdev, driver->pci_driver.name);
+               ret = pci_request_regions(pdev, driver->pci_driver.name);
+               if (ret)
+                       goto err_g1;
        }
 
-       pci_enable_device(pdev);
+       ret = pci_enable_device(pdev);
+       if (ret)
+               goto err_g2;
        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_g1;
+               goto err_g3;
        }
-       if ((ret = drm_get_head(dev, &dev->primary)))
-               goto err_g1;
 
-       DRM_INFO("Initialized %s %d.%d.%d %s on minor %d: %s\n",
+       /* only add the control node on a modesetting platform */
+       if (drm_core_check_feature(dev, DRIVER_MODESET))
+               if ((ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL)))
+                       goto err_g3;
+
+       if ((ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_LEGACY)))
+               goto err_g4;
+
+       if (dev->driver->load)
+               if ((ret = dev->driver->load(dev, ent->driver_data)))
+                       goto err_g5;
+
+       /* setup the grouping for the legacy output */
+       if (drm_core_check_feature(dev, DRIVER_MODESET))
+               if (drm_mode_group_init_legacy_group(dev, &dev->primary->mode_group))
+                   goto err_g5;
+
+       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, pci_pretty_name(dev->pdev));
+                driver->date, dev->primary->index);
 
        return 0;
-
+err_g5:
+       drm_put_minor(&dev->primary);
+err_g4:
+       if (drm_core_check_feature(dev, DRIVER_MODESET))
+               drm_put_minor(&dev->control);
+err_g3:
+       if (!drm_fb_loaded)
+               pci_disable_device(pdev);
+err_g2:
+       if (!drm_fb_loaded)
+               pci_release_regions(pdev);
 err_g1:
-       if (!drm_fb_loaded) {
+       if (!drm_fb_loaded)
                pci_set_drvdata(pdev, NULL);
-               pci_release_regions(pdev);
-               pci_disable_device(pdev);
-       }
+
        drm_free(dev, sizeof(*dev), DRM_MEM_STUB);
        printk(KERN_ERR "DRM: drm_get_dev failed.\n");
        return ret;
@@ -278,15 +420,10 @@ EXPORT_SYMBOL(drm_get_dev);
  * "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);
 
-       if (dev->unique) {
-               drm_free(dev->unique, strlen(dev->unique) + 1, DRM_MEM_DRIVER);
-               dev->unique = NULL;
-               dev->unique_len = 0;
-       }
        if (dev->devname) {
                drm_free(dev->devname, strlen(dev->devname) + 1,
                         DRM_MEM_DRIVER);
@@ -306,17 +443,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);
+       struct drm_minor *minor = *minor_p;
+       DRM_DEBUG("release secondary minor %d\n", minor->index);
 
-       drm_proc_cleanup(minor, drm_proc_root, head->dev_root);
-       drm_sysfs_device_remove(head->dev_class);
+       if (minor->type == DRM_MINOR_LEGACY)
+               drm_proc_cleanup(minor, drm_proc_root);
+       drm_sysfs_device_remove(minor);
 
-       *head = (drm_head_t){.dev = NULL};
+       idr_remove(&drm_minors_idr, minor->index);
 
-       drm_heads[minor] = NULL;
+       kfree(minor);
+       *minor_p = NULL;
        return 0;
 }