Merge branch 'devel' of master.kernel.org:/home/rmk/linux-2.6-arm
[pandora-kernel.git] / drivers / gpu / drm / drm_pci.c
index f5bd9e5..e1aee4f 100644 (file)
@@ -125,6 +125,176 @@ void drm_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah)
 EXPORT_SYMBOL(drm_pci_free);
 
 #ifdef CONFIG_PCI
+
+static int drm_get_pci_domain(struct drm_device *dev)
+{
+#ifndef __alpha__
+       /* For historical reasons, drm_get_pci_domain() is busticated
+        * on most archs and has to remain so for userspace interface
+        * < 1.4, except on alpha which was right from the beginning
+        */
+       if (dev->if_version < 0x10004)
+               return 0;
+#endif /* __alpha__ */
+
+       return pci_domain_nr(dev->pdev->bus);
+}
+
+static int drm_pci_get_irq(struct drm_device *dev)
+{
+       return dev->pdev->irq;
+}
+
+static const char *drm_pci_get_name(struct drm_device *dev)
+{
+       struct pci_driver *pdriver = dev->driver->kdriver.pci;
+       return pdriver->name;
+}
+
+int drm_pci_set_busid(struct drm_device *dev, struct drm_master *master)
+{
+       int len, ret;
+       struct pci_driver *pdriver = dev->driver->kdriver.pci;
+       master->unique_len = 40;
+       master->unique_size = master->unique_len;
+       master->unique = kmalloc(master->unique_size, GFP_KERNEL);
+       if (master->unique == NULL)
+               return -ENOMEM;
+
+
+       len = snprintf(master->unique, master->unique_len,
+                      "pci:%04x:%02x:%02x.%d",
+                      drm_get_pci_domain(dev),
+                      dev->pdev->bus->number,
+                      PCI_SLOT(dev->pdev->devfn),
+                      PCI_FUNC(dev->pdev->devfn));
+
+       if (len >= master->unique_len) {
+               DRM_ERROR("buffer overflow");
+               ret = -EINVAL;
+               goto err;
+       } else
+               master->unique_len = len;
+
+       dev->devname =
+               kmalloc(strlen(pdriver->name) +
+                       master->unique_len + 2, GFP_KERNEL);
+
+       if (dev->devname == NULL) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       sprintf(dev->devname, "%s@%s", pdriver->name,
+               master->unique);
+
+       return 0;
+err:
+       return ret;
+}
+
+int drm_pci_set_unique(struct drm_device *dev,
+                      struct drm_master *master,
+                      struct drm_unique *u)
+{
+       int domain, bus, slot, func, ret;
+       const char *bus_name;
+
+       master->unique_len = u->unique_len;
+       master->unique_size = u->unique_len + 1;
+       master->unique = kmalloc(master->unique_size, GFP_KERNEL);
+       if (!master->unique) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       if (copy_from_user(master->unique, u->unique, master->unique_len)) {
+               ret = -EFAULT;
+               goto err;
+       }
+
+       master->unique[master->unique_len] = '\0';
+
+       bus_name = dev->driver->bus->get_name(dev);
+       dev->devname = kmalloc(strlen(bus_name) +
+                              strlen(master->unique) + 2, GFP_KERNEL);
+       if (!dev->devname) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       sprintf(dev->devname, "%s@%s", bus_name,
+               master->unique);
+
+       /* Return error if the busid submitted doesn't match the device's actual
+        * busid.
+        */
+       ret = sscanf(master->unique, "PCI:%d:%d:%d", &bus, &slot, &func);
+       if (ret != 3) {
+               ret = -EINVAL;
+               goto err;
+       }
+
+       domain = bus >> 8;
+       bus &= 0xff;
+
+       if ((domain != drm_get_pci_domain(dev)) ||
+           (bus != dev->pdev->bus->number) ||
+           (slot != PCI_SLOT(dev->pdev->devfn)) ||
+           (func != PCI_FUNC(dev->pdev->devfn))) {
+               ret = -EINVAL;
+               goto err;
+       }
+       return 0;
+err:
+       return ret;
+}
+
+
+int drm_pci_irq_by_busid(struct drm_device *dev, struct drm_irq_busid *p)
+{
+       if ((p->busnum >> 8) != drm_get_pci_domain(dev) ||
+           (p->busnum & 0xff) != dev->pdev->bus->number ||
+           p->devnum != PCI_SLOT(dev->pdev->devfn) || p->funcnum != PCI_FUNC(dev->pdev->devfn))
+               return -EINVAL;
+
+       p->irq = dev->pdev->irq;
+
+       DRM_DEBUG("%d:%d:%d => IRQ %d\n", p->busnum, p->devnum, p->funcnum,
+                 p->irq);
+       return 0;
+}
+
+int drm_pci_agp_init(struct drm_device *dev)
+{
+       if (drm_core_has_AGP(dev)) {
+               if (drm_pci_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");
+                       return -EINVAL;
+               }
+               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);
+               }
+       }
+       return 0;
+}
+
+static struct drm_bus drm_pci_bus = {
+       .bus_type = DRIVER_BUS_PCI,
+       .get_irq = drm_pci_get_irq,
+       .get_name = drm_pci_get_name,
+       .set_busid = drm_pci_set_busid,
+       .set_unique = drm_pci_set_unique,
+       .agp_init = drm_pci_agp_init,
+};
+
 /**
  * Register.
  *
@@ -219,7 +389,7 @@ err_g1:
 EXPORT_SYMBOL(drm_get_pci_dev);
 
 /**
- * PCI device initialization. Called via drm_init at module load time,
+ * PCI device initialization. Called direct from modules at load time.
  *
  * \return zero on success or a negative number on failure.
  *
@@ -229,18 +399,24 @@ EXPORT_SYMBOL(drm_get_pci_dev);
  * Expands the \c DRIVER_PREINIT and \c DRIVER_POST_INIT macros before and
  * after the initialization for driver customization.
  */
-int drm_pci_init(struct drm_driver *driver)
+int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver)
 {
        struct pci_dev *pdev = NULL;
        const struct pci_device_id *pid;
        int i;
 
+       DRM_DEBUG("\n");
+
+       INIT_LIST_HEAD(&driver->device_list);
+       driver->kdriver.pci = pdriver;
+       driver->bus = &drm_pci_bus;
+
        if (driver->driver_features & DRIVER_MODESET)
-               return pci_register_driver(&driver->pci_driver);
+               return pci_register_driver(pdriver);
 
        /* If not using KMS, fall back to stealth mode manual scanning. */
-       for (i = 0; driver->pci_driver.id_table[i].vendor != 0; i++) {
-               pid = &driver->pci_driver.id_table[i];
+       for (i = 0; pdriver->id_table[i].vendor != 0; i++) {
+               pid = &pdriver->id_table[i];
 
                /* Loop around setting up a DRM device for each PCI device
                 * matching our ID and device class.  If we had the internal
@@ -265,10 +441,27 @@ int drm_pci_init(struct drm_driver *driver)
 
 #else
 
-int drm_pci_init(struct drm_driver *driver)
+int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver)
 {
        return -1;
 }
 
 #endif
+
+EXPORT_SYMBOL(drm_pci_init);
+
 /*@}*/
+void drm_pci_exit(struct drm_driver *driver, struct pci_driver *pdriver)
+{
+       struct drm_device *dev, *tmp;
+       DRM_DEBUG("\n");
+
+       if (driver->driver_features & DRIVER_MODESET) {
+               pci_unregister_driver(pdriver);
+       } else {
+               list_for_each_entry_safe(dev, tmp, &driver->device_list, driver_item)
+                       drm_put_dev(dev);
+       }
+       DRM_INFO("Module unloaded\n");
+}
+EXPORT_SYMBOL(drm_pci_exit);