fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / char / drm / drm_stub.c
index 1ff4213..120d102 100644 (file)
 #include "drm_core.h"
 
 unsigned int drm_cards_limit = 16;     /* Enough for one machine */
-unsigned int drm_debug = 0;            /* 1 to enable debug output */
+unsigned int drm_debug = 0;    /* 1 to enable debug output */
 EXPORT_SYMBOL(drm_debug);
 
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_AUTHOR(CORE_AUTHOR);
+MODULE_DESCRIPTION(CORE_DESC);
 MODULE_LICENSE("GPL and additional rights");
-MODULE_PARM_DESC(drm_cards_limit, "Maximum number of graphics cards");
-MODULE_PARM_DESC(drm_debug, "Enable debug output");
+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, 0666);
+module_param_named(debug, drm_debug, int, 0600);
 
-drm_minor_t *drm_minors;
-struct drm_sysfs_class *drm_class;
+drm_head_t **drm_heads;
+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, const struct pci_device_id *ent, struct drm_driver *driver)
+static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev,
+                          const struct pci_device_id *ent,
+                          struct drm_driver *driver)
 {
        int retcode;
 
        spin_lock_init(&dev->count_lock);
-       init_timer( &dev->timer );
-       sema_init( &dev->struct_sem, 1 );
-       sema_init( &dev->ctxlist_sem, 1 );
+       spin_lock_init(&dev->drw_lock);
+       spin_lock_init(&dev->tasklet_lock);
+       init_timer(&dev->timer);
+       mutex_init(&dev->struct_mutex);
+       mutex_init(&dev->ctxlist_mutex);
 
-       dev->pdev   = pdev;
+       dev->pdev = pdev;
+       dev->pci_device = pdev->device;
+       dev->pci_vendor = pdev->vendor;
 
 #ifdef __alpha__
-       dev->hose   = pdev->sysdata;
-       dev->pci_domain = dev->hose->bus->number;
-#else
-       dev->pci_domain = 0;
+       dev->hose = pdev->sysdata;
 #endif
-       dev->pci_bus = pdev->bus->number;
-       dev->pci_slot = PCI_SLOT(pdev->devfn);
-       dev->pci_func = PCI_FUNC(pdev->devfn);
        dev->irq = pdev->irq;
 
+       dev->maplist = drm_calloc(1, sizeof(*dev->maplist), DRM_MEM_MAPS);
+       if (dev->maplist == NULL)
+               return -ENOMEM;
+       INIT_LIST_HEAD(&dev->maplist->head);
+       if (drm_ht_create(&dev->map_hash, 12)) {
+               drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS);
+               return -ENOMEM;
+       }
+
        /* the DRM has 6 basic counters */
        dev->counters = 6;
-       dev->types[0]  = _DRM_STAT_LOCK;
-       dev->types[1]  = _DRM_STAT_OPENS;
-       dev->types[2]  = _DRM_STAT_CLOSES;
-       dev->types[3]  = _DRM_STAT_IOCTLS;
-       dev->types[4]  = _DRM_STAT_LOCKS;
-       dev->types[5]  = _DRM_STAT_UNLOCKS;
+       dev->types[0] = _DRM_STAT_LOCK;
+       dev->types[1] = _DRM_STAT_OPENS;
+       dev->types[2] = _DRM_STAT_CLOSES;
+       dev->types[3] = _DRM_STAT_IOCTLS;
+       dev->types[4] = _DRM_STAT_LOCKS;
+       dev->types[5] = _DRM_STAT_UNLOCKS;
 
        dev->driver = driver;
-       
-       if (dev->driver->preinit)
-               if ((retcode = dev->driver->preinit(dev, ent->driver_data)))
+
+       if (dev->driver->load)
+               if ((retcode = dev->driver->load(dev, ent->driver_data)))
                        goto error_out_unreg;
 
        if (drm_core_has_AGP(dev)) {
-               dev->agp = drm_agp_init();
-               if (drm_core_check_feature(dev, DRIVER_REQUIRE_AGP) && (dev->agp == NULL)) {
-                       DRM_ERROR( "Cannot initialize the agpgart module.\n" );
+               if (drm_device_is_agp(dev))
+                       dev->agp = drm_agp_init(dev);
+               if (drm_core_check_feature(dev, DRIVER_REQUIRE_AGP)
+                   && (dev->agp == NULL)) {
+                       DRM_ERROR("Cannot initialize the agpgart module.\n");
                        retcode = -EINVAL;
                        goto error_out_unreg;
                }
                if (drm_core_has_MTRR(dev)) {
                        if (dev->agp)
-                               dev->agp->agp_mtrr = mtrr_add( dev->agp->agp_info.aper_base,
-                                                              dev->agp->agp_info.aper_size*1024*1024,
-                                                              MTRR_TYPE_WRCOMB,
-                                                              1 );
+                               dev->agp->agp_mtrr =
+                                   mtrr_add(dev->agp->agp_info.aper_base,
+                                            dev->agp->agp_info.aper_size *
+                                            1024 * 1024, MTRR_TYPE_WRCOMB, 1);
                }
        }
 
-       retcode = drm_ctxbitmap_init( dev );
-       if( retcode ) {
-               DRM_ERROR( "Cannot allocate memory for context bitmap.\n" );
+       retcode = drm_ctxbitmap_init(dev);
+       if (retcode) {
+               DRM_ERROR("Cannot allocate memory for context bitmap.\n");
                goto error_out_unreg;
        }
 
-       dev->device = MKDEV(DRM_MAJOR, dev->minor );
-
-       /* postinit is a required function to display the signon banner */
-       if ((retcode = dev->driver->postinit(dev, ent->driver_data)))
-               goto error_out_unreg;
-
        return 0;
-       
-error_out_unreg:
-       drm_takedown(dev);
+
+      error_out_unreg:
+       drm_lastclose(dev);
        return retcode;
 }
 
+
 /**
- * File \c open operation.
+ * Get a secondary minor number.
  *
- * \param inode device inode.
- * \param filp file pointer.
+ * \param dev device data structure
+ * \param sec-minor structure to hold the assigned minor
+ * \return negative number on failure.
  *
- * Puts the dev->fops corresponding to the device minor number into
- * \p filp, call the \c open method, and restore the file operations.
+ * Search an empty entry and initialize it to the given parameters, and
+ * create the proc init entry via proc_init(). This routines assigns
+ * minor numbers to secondary heads of multi-headed cards
  */
-int drm_stub_open(struct inode *inode, struct file *filp)
+static int drm_get_head(drm_device_t * dev, drm_head_t * head)
 {
-       drm_device_t *dev = NULL;
-       int minor = iminor(inode);
-       int err = -ENODEV;
-       struct file_operations *old_fops;
-       
+       drm_head_t **heads = drm_heads;
+       int ret;
+       int minor;
+
        DRM_DEBUG("\n");
 
-       if (!((minor >= 0) && (minor < drm_cards_limit)))
-               return -ENODEV;
+       for (minor = 0; minor < drm_cards_limit; minor++, heads++) {
+               if (!*heads) {
 
-       dev = drm_minors[minor].dev;
-       if (!dev)
-               return -ENODEV;
+                       *head = (drm_head_t) {
+                       .dev = dev,.device =
+                                   MKDEV(DRM_MAJOR, minor),.minor = minor,};
 
-       old_fops = filp->f_op;
-       filp->f_op = fops_get(&dev->driver->fops);
-       if (filp->f_op->open && (err = filp->f_op->open(inode, filp))) {
-               fops_put(filp->f_op);
-               filp->f_op = fops_get(old_fops);
-       }
-       fops_put(old_fops);
+                       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;
 
-       return err;
+                       DRM_DEBUG("new minor assigned %d\n", minor);
+                       return 0;
+               }
+       }
+       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};
+       return ret;
 }
 
 /**
- * Get a device minor number.
+ * Register.
  *
- * \param pdev PCI device structure
+ * \param pdev PCI device structure
  * \param ent entry from the PCI ID table with device type flags
  * \return zero on success or a negative number on failure.
  *
@@ -172,88 +199,92 @@ int drm_stub_open(struct inode *inode, struct file *filp)
  * then register the character device and inter module information.
  * Try and register, if we fail to register, backout previous work.
  */
-int drm_probe(struct pci_dev *pdev, const struct pci_device_id *ent, struct drm_driver *driver)
+int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
+               struct drm_driver *driver)
 {
-       struct class_device *dev_class;
        drm_device_t *dev;
        int ret;
-       int minor;
-       drm_minor_t *minors = &drm_minors[0];
 
        DRM_DEBUG("\n");
 
-       for (minor = 0; minor < drm_cards_limit; minor++, minors++) {
-               if (minors->type == DRM_MINOR_FREE) {
-
-                       DRM_DEBUG("assigning minor %d\n", minor);
-                       dev = drm_calloc(1, sizeof(*dev), DRM_MEM_STUB);
-                       if (!dev)
-                               return -ENOMEM;
+       dev = drm_calloc(1, sizeof(*dev), DRM_MEM_STUB);
+       if (!dev)
+               return -ENOMEM;
 
-                       *minors = (drm_minor_t){.dev = dev, .type=DRM_MINOR_PRIMARY};
-                       dev->minor = minor;
+       ret = pci_enable_device(pdev);
+       if (ret)
+               goto err_g1;
 
-                       pci_enable_device(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)))
+               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);
 
-                       if ((ret=drm_fill_in_dev(dev, pdev, ent, driver))) {
-                               printk(KERN_ERR "DRM: Fill_in_dev failed.\n");
-                               goto err_g1;
-                       }
-                       if ((ret = drm_proc_init(dev, minor, drm_proc_root, &minors->dev_root))) {
-                               printk (KERN_ERR "DRM: Failed to initialize /proc/dri.\n");
-                               goto err_g1;
-                       }
+       return 0;
 
-                       
-                       dev_class = drm_sysfs_device_add(drm_class,
-                                                        MKDEV(DRM_MAJOR,
-                                                              minor),
-                                                        &pdev->dev,
-                                                        "card%d", minor);
-                       if (IS_ERR(dev_class)) {
-                               printk(KERN_ERR "DRM: Error sysfs_device_add.\n");
-                               ret = PTR_ERR(dev_class);
-                               goto err_g2;
-                       }
-                       
-                       DRM_DEBUG("new minor assigned %d\n", minor);
-                       return 0;
-               }
-       }
-       DRM_ERROR("out of minors\n");
-       return -ENOMEM;
 err_g2:
-       drm_proc_cleanup(minor, drm_proc_root, minors->dev_root);
+       pci_disable_device(pdev);
 err_g1:
-       *minors = (drm_minor_t){.dev = NULL, .type = DRM_MINOR_FREE};
        drm_free(dev, sizeof(*dev), DRM_MEM_STUB);
        return ret;
 }
-EXPORT_SYMBOL(drm_probe);
-               
 
 /**
  * Put a device minor number.
  *
- * \param minor minor number.
- * \return always zero.
+ * \param dev device data structure
+ * \return always zero
  *
- * Cleans up the proc resources. If a minor is zero then release the foreign
- * "drm" data, otherwise unregisters the "drm" data, frees the stub list and
- * unregisters the character device. 
+ * Cleans up the proc resources. If it is the last minor then release the foreign
+ * "drm" data, otherwise unregisters the "drm" data, frees the dev list and
+ * unregisters the character device.
  */
-int drm_put_minor(drm_device_t *dev)
+int drm_put_dev(drm_device_t * dev)
 {
-       drm_minor_t *minors = &drm_minors[dev->minor];
-       
-       DRM_DEBUG("release minor %d\n", dev->minor);
-       
-       drm_proc_cleanup(dev->minor, drm_proc_root, minors->dev_root);
-       drm_sysfs_device_remove(MKDEV(DRM_MAJOR, dev->minor));
-       
-       *minors = (drm_minor_t){.dev = NULL, .type = DRM_MINOR_FREE};
+       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);
+               dev->devname = NULL;
+       }
        drm_free(dev, sizeof(*dev), DRM_MEM_STUB);
-       
        return 0;
 }
 
+/**
+ * Put a secondary minor number.
+ *
+ * \param sec_minor - structure to be released
+ * \return always zero
+ *
+ * Cleans up the proc resources. Not legal for this to be the
+ * last minor released.
+ *
+ */
+int drm_put_head(drm_head_t * head)
+{
+       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);
+
+       *head = (drm_head_t) {.dev = NULL};
+
+       drm_heads[minor] = NULL;
+
+       return 0;
+}