drm/ttm: Add a virtual ttm sysfs device.

The device directory will be the base directory of the
sysfs representation of other ttm subsystems.

Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
Signed-off-by: Dave Airlie <airlied@linux.ie>
diff --git a/drivers/gpu/drm/ttm/ttm_module.c b/drivers/gpu/drm/ttm/ttm_module.c
index 59ce819..9a6edbf 100644
--- a/drivers/gpu/drm/ttm/ttm_module.c
+++ b/drivers/gpu/drm/ttm/ttm_module.c
@@ -29,16 +29,72 @@
  * 	    Jerome Glisse
  */
 #include <linux/module.h>
-#include <ttm/ttm_module.h>
+#include <linux/device.h>
+#include <linux/sched.h>
+#include "ttm/ttm_module.h"
+#include "drm_sysfs.h"
+
+static DECLARE_WAIT_QUEUE_HEAD(exit_q);
+atomic_t device_released;
+
+static struct device_type ttm_drm_class_type = {
+	.name = "ttm",
+	/**
+	 * Add pm ops here.
+	 */
+};
+
+static void ttm_drm_class_device_release(struct device *dev)
+{
+	atomic_set(&device_released, 1);
+	wake_up_all(&exit_q);
+}
+
+static struct device ttm_drm_class_device = {
+	.type = &ttm_drm_class_type,
+	.release = &ttm_drm_class_device_release
+};
+
+struct kobject *ttm_get_kobj(void)
+{
+	struct kobject *kobj = &ttm_drm_class_device.kobj;
+	BUG_ON(kobj == NULL);
+	return kobj;
+}
 
 static int __init ttm_init(void)
 {
+	int ret;
+
+	ret = dev_set_name(&ttm_drm_class_device, "ttm");
+	if (unlikely(ret != 0))
+		return ret;
+
 	ttm_global_init();
+
+	atomic_set(&device_released, 0);
+	ret = drm_class_device_register(&ttm_drm_class_device);
+	if (unlikely(ret != 0))
+		goto out_no_dev_reg;
+
 	return 0;
+out_no_dev_reg:
+	atomic_set(&device_released, 1);
+	wake_up_all(&exit_q);
+	ttm_global_release();
+	return ret;
 }
 
 static void __exit ttm_exit(void)
 {
+	drm_class_device_unregister(&ttm_drm_class_device);
+
+	/**
+	 * Refuse to unload until the TTM device is released.
+	 * Not sure this is 100% needed.
+	 */
+
+	wait_event(exit_q, atomic_read(&device_released) == 1);
 	ttm_global_release();
 }