From 8b755139164c05fcff5e56617d2fa9886fea1825 Mon Sep 17 00:00:00 2001
From: Patrick Mochel <mochel@osdl.org>
Date: Mon, 23 Sep 2002 01:19:20 -0700
Subject: [PATCH] Driver model: improve support for system devices.

- Create struct sys_device to describe system-level devices (CPUs, PICs, etc.). This
  structure includes a 'name' and 'id' field for drivers to fill in with a simple
  canonical name (like 'pic' or 'floppy') and the id of the device relative to its
  discovery in the system (it's enumerated value).

  The core then constructs the bus_id for the device from these, giving them meaningful
  names when exporting them to userspace:

# tree -d /sys/root/sys/
/sys/root/sys/
|-- pic0
`-- rtc0

- Replace
	int register_sys_device(struct device * dev);
	with
	int sys_device_register(struct sys_device * sysdev);

- Fixup the users of the API.

- Add a system_bus_type for devices to associate themselves with. This provides a
  bus/system/ directory in driverfs that looks like:

# tree -d /sys/bus/system/
/sys/bus/system/
|-- devices
|   |-- pic0 -> ../../../root/sys/pic0
|   `-- rtc0 -> ../../../root/sys/rtc0
`-- drivers
    `-- pic
---
 arch/i386/kernel/i8259.c | 20 +++++++-----
 arch/i386/kernel/time.c  | 15 +++++----
 drivers/base/sys.c       | 68 ++++++++++++++++++++++++++++++----------
 drivers/block/floppy.c   | 13 +++++---
 include/linux/device.h   | 14 +++++++--
 5 files changed, 93 insertions(+), 37 deletions(-)

diff --git a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c
index eb3fdd05b638..499b58a347c2 100644
--- a/arch/i386/kernel/i8259.c
+++ b/arch/i386/kernel/i8259.c
@@ -246,22 +246,28 @@ static int i8259A_resume(struct device *dev, u32 level)
 	return 0;
 }
 
-static struct device_driver driver_i8259A = {
+static struct device_driver i8259A_driver = {
+	.name		= "pic",
+	.bus		= &system_bus_type,
 	.resume		= i8259A_resume,
 };
 
-static struct device device_i8259A = {
-	.name	       	= "i8259A",
-	.bus_id		= "0020",
-	.driver		= &driver_i8259A,
+static struct sys_device device_i8259A = {
+	.name		= "pic",
+	.id		= 0,
+	.dev		= {
+		.name	= "i8259A PIC",
+		.driver	= &i8259A_driver,
+	},
 };
 
 static int __init init_8259A_devicefs(void)
 {
-	return register_sys_device(&device_i8259A);
+	driver_register(&i8259A_driver);
+	return sys_device_register(&device_i8259A);
 }
 
-__initcall(init_8259A_devicefs);
+device_initcall(init_8259A_devicefs);
 
 void init_8259A(int auto_eoi)
 {
diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c
index 9ad143fcd1c1..add66db72dcd 100644
--- a/arch/i386/kernel/time.c
+++ b/arch/i386/kernel/time.c
@@ -588,17 +588,20 @@ static unsigned long __init calibrate_tsc(void)
 }
 #endif /* CONFIG_X86_TSC */
 
-static struct device device_i8253 = {
-	.name	       	= "i8253",
-	.bus_id		= "0040",
+static struct sys_device device_i8253 = {
+	.name		= "rtc",
+	.id		= 0,
+	.dev	= {
+		.name	= "i8253 Real Time Clock",
+	},
 };
 
-static int time_init_driverfs(void)
+static int time_init_device(void)
 {
-	return register_sys_device(&device_i8253);
+	return sys_device_register(&device_i8253);
 }
 
-__initcall(time_init_driverfs);
+device_initcall(time_init_device);
 
 void __init time_init(void)
 {
diff --git a/drivers/base/sys.c b/drivers/base/sys.c
index 7120cce5cb39..8dfa5b7bfb2b 100644
--- a/drivers/base/sys.c
+++ b/drivers/base/sys.c
@@ -6,44 +6,78 @@
  * 
  * This exports a 'system' bus type. 
  * By default, a 'sys' bus gets added to the root of the system. There will
- * always be core system devices. Devices can use register_sys_device() to
+ * always be core system devices. Devices can use sys_device_register() to
  * add themselves as children of the system bus.
  */
 
 #include <linux/device.h>
 #include <linux/module.h>
+#include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/errno.h>
+#include <linux/err.h>
 
+/* The default system device parent. */
 static struct device system_bus = {
        .name           = "System Bus",
        .bus_id         = "sys",
 };
 
-int register_sys_device(struct device * dev)
+/**
+ *	sys_device_register - add a system device to the tree
+ *	@sysdev:	device in question
+ *
+ *	The hardest part about this is getting the ancestry right.
+ *	If the device has a parent - super! We do nothing.
+ *	If the device doesn't, but @dev->root is set, then we're
+ *	dealing with a NUMA like architecture where each root
+ *	has a system pseudo-bus to foster the device.
+ *	If not, then we fallback to system_bus (at the top of 
+ *	this file). 
+ *
+ *	One way or another, we call device_register() on it and 
+ *	are done.
+ *
+ *	The caller is also responsible for initializing the bus_id 
+ *	and name fields of @sysdev->dev.
+ */
+int sys_device_register(struct sys_device * sysdev)
 {
-       int error = -EINVAL;
-
-       if (dev) {
-               if (!dev->parent)
-                       dev->parent = &system_bus;
-               error = device_register(dev);
-       }
-       return error;
+	if (!sysdev)
+		return -EINVAL;
+
+	if (!sysdev->dev.parent)
+		sysdev->dev.parent = &system_bus;
+
+	/* make sure bus type is set */
+	if (!sysdev->dev.bus)
+		sysdev->dev.bus = &system_bus_type;
+
+	/* construct bus_id */
+	snprintf(sysdev->dev.bus_id,BUS_ID_SIZE,"%s%u",sysdev->name,sysdev->id);
+
+	pr_debug("Registering system device %s\n", sysdev->dev.bus_id);
+
+	return device_register(&sysdev->dev);
 }
 
-void unregister_sys_device(struct device * dev)
+void sys_device_unregister(struct sys_device * sysdev)
 {
-       if (dev)
-               put_device(dev);
+	if (sysdev)
+		put_device(&sysdev->dev);
 }
 
+struct bus_type system_bus_type = {
+	.name		= "system",
+};
+
 static int sys_bus_init(void)
 {
-       return device_register(&system_bus);
+	bus_register(&system_bus_type);
+	return device_register(&system_bus);
 }
 
 postcore_initcall(sys_bus_init);
-EXPORT_SYMBOL(register_sys_device);
-EXPORT_SYMBOL(unregister_sys_device);
+EXPORT_SYMBOL(system_bus_type);
+EXPORT_SYMBOL(sys_device_register);
+EXPORT_SYMBOL(sys_device_unregister);
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 78989bde5cb5..b07e8efd12ea 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -4220,9 +4220,12 @@ static int __init floppy_setup(char *str)
 
 static int have_no_fdc= -ENODEV;
 
-static struct device device_floppy = {
-	name:		"floppy",
-	bus_id:		"03?0",
+static struct sys_device floppy_device = {
+	.name		= "floppy",
+	.id		= 0,
+	.dev		= {
+		.name	= "Floppy Drive",
+	},
 };
 
 static struct gendisk *floppy_find(int minor)
@@ -4376,7 +4379,7 @@ int __init floppy_init(void)
 		add_disk(disks + drive);
 	}
 
-	register_sys_device(&device_floppy);
+	sys_device_register(&floppy_device);
 
 	return have_no_fdc;
 }
@@ -4560,7 +4563,7 @@ void cleanup_module(void)
 {
 	int drive;
 		
-	unregister_sys_device(&device_floppy);
+	sys_device_unregister(&floppy_device);
 	devfs_unregister (devfs_handle);
 	unregister_blkdev(MAJOR_NR, "fd");
 	blk_set_probe(MAJOR_NR, NULL);
diff --git a/include/linux/device.h b/include/linux/device.h
index ea2a790723b3..7abeead7bfe1 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -378,8 +378,18 @@ extern struct device * get_device(struct device * dev);
 extern void put_device(struct device * dev);
 
 /* drivers/base/sys.c */
-extern int register_sys_device(struct device * dev);
-extern void unregister_sys_device(struct device * dev);
+
+struct sys_device {
+	char		* name;
+	u32		id;
+	struct sys_root	* root;
+	struct device	dev;
+};
+
+extern int sys_device_register(struct sys_device *);
+extern void sys_device_unregister(struct sys_device *);
+
+extern struct bus_type system_bus_type;
 
 /* drivers/base/platform.c */
 extern struct bus_type platform_bus;
-- 
2.30.9