drm: add initial support for a drm control device node
authorDave Airlie <airlied@redhat.com>
Fri, 4 Jan 2008 06:49:40 +0000 (17:49 +1100)
committerDave Airlie <airlied@redhat.com>
Fri, 4 Jan 2008 06:49:40 +0000 (17:49 +1100)
linux-core/drmP.h
linux-core/drm_drv.c
linux-core/drm_stub.c
linux-core/drm_sysfs.c

index 962ad4e..5bc4887 100644 (file)
@@ -699,6 +699,7 @@ struct drm_minor {
        int minor;                      /**< Minor device number */
        int type;                       /**< Control or render */
        dev_t device;                   /**< Device number for mknod */
+       struct device kdev;             /**< Linux device */
        struct drm_device *dev;
        /* for render nodes */
        struct proc_dir_entry *dev_root;  /**< proc directory entry */
@@ -711,7 +712,6 @@ struct drm_minor {
  * may contain multiple heads.
  */
 struct drm_device {
-       struct device dev;              /**< Linux device */
        char *unique;                   /**< Unique identifier: e.g., busid */
        int unique_len;                 /**< Length of unique field */
        char *devname;                  /**< For /proc/interrupts */
@@ -1158,7 +1158,7 @@ extern void drm_agp_chipset_flush(struct drm_device *dev);
 extern int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
                     struct drm_driver *driver);
 extern int drm_put_dev(struct drm_device *dev);
-extern int drm_put_head(struct drm_minor *minor);
+extern int drm_put_minor(struct drm_minor *minor);
 extern unsigned int drm_debug; /* 1 to enable debug output */
 extern unsigned int drm_minors_limit;
 extern struct drm_minor **drm_minors;
@@ -1198,8 +1198,8 @@ extern void drm_pci_free(struct drm_device *dev, drm_dma_handle_t *dmah);
 struct drm_sysfs_class;
 extern struct class *drm_sysfs_create(struct module *owner, char *name);
 extern void drm_sysfs_destroy(void);
-extern int drm_sysfs_device_add(struct drm_device *dev, struct drm_minor *minor);
-extern void drm_sysfs_device_remove(struct drm_device *dev);
+extern int drm_sysfs_device_add(struct drm_minor *minor);
+extern void drm_sysfs_device_remove(struct drm_minor *minor);
 
 /*
  * Basic memory manager support (drm_mm.c)
index 29fa18d..58beec6 100644 (file)
@@ -423,7 +423,8 @@ static void drm_cleanup(struct drm_device * dev)
        drm_mm_takedown(&dev->offset_manager);
        drm_ht_remove(&dev->object_hash);
 
-       drm_put_head(&dev->primary);
+       drm_put_minor(&dev->primary);
+       drm_put_minor(&dev->control);
        if (drm_put_dev(dev))
                DRM_ERROR("Cannot unload module\n");
 }
index 433869e..cee00c5 100644 (file)
@@ -160,7 +160,7 @@ 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(struct drm_device * dev, struct drm_minor *minor)
+static int drm_get_minor(struct drm_device *dev, struct drm_minor *minor, int type)
 {
        struct drm_minor **minors = drm_minors;
        int ret;
@@ -172,19 +172,23 @@ static int drm_get_head(struct drm_device * dev, struct drm_minor *minor)
                if (!*minors) {
 
                        *minor = (struct drm_minor) {
+                               .type = type,
                                .dev = dev,
                                .device = MKDEV(DRM_MAJOR, index),
                                .minor = index,
                        };
-                       if ((ret =
-                            drm_proc_init(dev, index, drm_proc_root,
-                                          &minor->dev_root))) {
-                               printk(KERN_ERR
-                                      "DRM: Failed to initialize /proc/dri.\n");
-                               goto err_g1;
-                       }
 
-                       ret = drm_sysfs_device_add(dev, minor);
+                       if (type == DRM_MINOR_RENDER) {
+                               ret = drm_proc_init(dev, index, drm_proc_root,
+                                                   &minor->dev_root);
+                               if (ret) {
+                                       DRM_ERROR("DRM: Failed to initialize /proc/dri.\n");
+                                       goto err_g1;
+                               }
+                       } else
+                               minor->dev_root = NULL;
+
+                       ret = drm_sysfs_device_add(minor);
                        if (ret) {
                                printk(KERN_ERR
                                       "DRM: Error sysfs_device_add.\n");
@@ -199,7 +203,8 @@ static int drm_get_head(struct drm_device * dev, struct drm_minor *minor)
        DRM_ERROR("out of minors\n");
        return -ENOMEM;
 err_g2:
-       drm_proc_cleanup(index, drm_proc_root, minor->dev_root);
+       if (minor->type == DRM_MINOR_RENDER)
+               drm_proc_cleanup(index, drm_proc_root, minor->dev_root);
 err_g1:
        *minor = (struct drm_minor) {
                .dev = NULL};
@@ -245,22 +250,28 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
                printk(KERN_ERR "DRM: fill_in_dev failed\n");
                goto err_g3;
        }
-       if ((ret = drm_get_head(dev, &dev->primary)))
+
+       if ((ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL)))
                goto err_g3;
 
+       if ((ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_RENDER)))
+               goto err_g4;
+
        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);
 
        return 0;
 
- err_g3:
+err_g4:
+       drm_put_minor(&dev->control);
+err_g3:
        if (!drm_fb_loaded)
                pci_disable_device(pdev);
- err_g2:
+err_g2:
        if (!drm_fb_loaded)
                pci_release_regions(pdev);
- err_g1:
+err_g1:
        if (!drm_fb_loaded)
                pci_set_drvdata(pdev, NULL);
 
@@ -315,8 +326,9 @@ int drm_put_minor(struct drm_minor *minor)
 
        DRM_DEBUG("release secondary minor %d\n", index);
 
-       drm_proc_cleanup(index, drm_proc_root, minor->dev_root);
-       drm_sysfs_device_remove(minor->dev);
+       if (minor->type == DRM_MINOR_RENDER)
+               drm_proc_cleanup(index, drm_proc_root, minor->dev_root);
+       drm_sysfs_device_remove(minor);
 
        *minor = (struct drm_minor) {.type = DRM_MINOR_UNASSIGNED,
                                     .dev = NULL};
index 1f2d763..a56e995 100644 (file)
@@ -19,7 +19,7 @@
 #include "drm_core.h"
 #include "drmP.h"
 
-#define to_drm_device(d) container_of(d, struct drm_device, dev)
+#define to_drm_minor(d) container_of(d, struct drm_minor, kdev)
 
 /**
  * drm_sysfs_suspend - DRM class suspend hook
@@ -31,7 +31,8 @@
  */
 static int drm_sysfs_suspend(struct device *dev, pm_message_t state)
 {
-       struct drm_device *drm_dev = to_drm_device(dev);
+       struct drm_minor *drm_minor = to_drm_minor(dev);
+       struct drm_device *drm_dev = drm_minor->dev;
 
        printk(KERN_ERR "%s\n", __FUNCTION__);
 
@@ -50,7 +51,8 @@ static int drm_sysfs_suspend(struct device *dev, pm_message_t state)
  */
 static int drm_sysfs_resume(struct device *dev)
 {
-       struct drm_device *drm_dev = to_drm_device(dev);
+       struct drm_minor *drm_minor = to_drm_minor(dev);
+       struct drm_device *drm_dev = drm_minor->dev;
 
        if (drm_dev->driver->resume)
                return drm_dev->driver->resume(drm_dev);
@@ -122,10 +124,11 @@ void drm_sysfs_destroy(void)
 static ssize_t show_dri(struct device *device, struct device_attribute *attr,
                        char *buf)
 {
-       struct drm_device *dev = to_drm_device(device);
-       if (dev->driver->dri_library_name)
-               return dev->driver->dri_library_name(dev, buf);
-       return snprintf(buf, PAGE_SIZE, "%s\n", dev->driver->pci_driver.name);
+       struct drm_minor *drm_minor = to_drm_minor(device);
+       struct drm_device *drm_dev = drm_minor->dev;
+       if (drm_dev->driver->dri_library_name)
+               return drm_dev->driver->dri_library_name(drm_dev, buf);
+       return snprintf(buf, PAGE_SIZE, "%s\n", drm_dev->driver->pci_driver.name);
 }
 
 static struct device_attribute device_attrs[] = {
@@ -154,25 +157,31 @@ static void drm_sysfs_device_release(struct device *dev)
  * as the parent for the Linux device, and make sure it has a file containing
  * the driver we're using (for userspace compatibility).
  */
-int drm_sysfs_device_add(struct drm_device *dev, struct drm_minor *minor)
+int drm_sysfs_device_add(struct drm_minor *minor)
 {
        int err;
        int i, j;
-
-       dev->dev.parent = &dev->pdev->dev;
-       dev->dev.class = drm_class;
-       dev->dev.release = drm_sysfs_device_release;
-       dev->dev.devt = minor->device;
-       snprintf(dev->dev.bus_id, BUS_ID_SIZE, "card%d", minor->minor);
-
-       err = device_register(&dev->dev);
+       char *minor_str;
+
+       minor->kdev.parent = &minor->dev->pdev->dev;
+       minor->kdev.class = drm_class;
+       minor->kdev.release = drm_sysfs_device_release;
+       minor->kdev.devt = minor->device;
+       if (minor->type == DRM_MINOR_CONTROL)
+               minor_str = "controlD%d";
+       else
+               minor_str = "card%d";
+       
+       snprintf(minor->kdev.bus_id, BUS_ID_SIZE, minor_str, minor->minor);
+
+       err = device_register(&minor->kdev);
        if (err) {
                DRM_ERROR("device add failed: %d\n", err);
                goto err_out;
        }
 
        for (i = 0; i < ARRAY_SIZE(device_attrs); i++) {
-               err = device_create_file(&dev->dev, &device_attrs[i]);
+               err = device_create_file(&minor->kdev, &device_attrs[i]);
                if (err)
                        goto err_out_files;
        }
@@ -182,8 +191,8 @@ int drm_sysfs_device_add(struct drm_device *dev, struct drm_minor *minor)
 err_out_files:
        if (i > 0)
                for (j = 0; j < i; j++)
-                       device_remove_file(&dev->dev, &device_attrs[i]);
-       device_unregister(&dev->dev);
+                       device_remove_file(&minor->kdev, &device_attrs[i]);
+       device_unregister(&minor->kdev);
 err_out:
 
        return err;
@@ -196,11 +205,11 @@ err_out:
  * This call unregisters and cleans up a class device that was created with a
  * call to drm_sysfs_device_add()
  */
-void drm_sysfs_device_remove(struct drm_device *dev)
+void drm_sysfs_device_remove(struct drm_minor *minor)
 {
        int i;
 
        for (i = 0; i < ARRAY_SIZE(device_attrs); i++)
-               device_remove_file(&dev->dev, &device_attrs[i]);
-       device_unregister(&dev->dev);
+               device_remove_file(&minor->kdev, &device_attrs[i]);
+       device_unregister(&minor->kdev);
 }