public inbox for linux-acpi@vger.kernel.org
 help / color / mirror / Atom feed
* [RFC]convert ACPI driver model to Linux driver model - takes 2
@ 2005-10-13  6:37 Shaohua Li
       [not found] ` <1129185454.9074.15.camel-ECwVeV2eNyQD0+JXs3kMbRL4W9x8LtSr@public.gmane.org>
  0 siblings, 1 reply; 15+ messages in thread
From: Shaohua Li @ 2005-10-13  6:37 UTC (permalink / raw)
  To: acpi-dev; +Cc: Len, Dominik Brodowski, Adam Belay

Hi,
This is the updated patch for the topic. In this version, I completely
convert devices in ACPI bus into Linux driver model. Now the device
driver for ACPI bus device should be a 'struct acpi_phys_driver'. Old
style driver (struct acpi_driver) now can't work for ACPI bus devices.
Here I still regard devices listed in DSDT but not belonging to any
physical bus as ACPI bus devices.
For back compatibility, old style driver model still applies to non-ACPI
bus devices. In the implementation, we register an old style driver
(acpi_dummy) for each acpi bus device, whose goal is to enumerate acpi
bus devices and prevent new old style driver binding with the devices. 
I tried to convert one ACPI driver (link device driver) to the new
model. It's quite easy.
I'm looking forward to your comments/suggestions.

Thanks,
Shaohua
---

 linux-2.6.14-rc3-root/drivers/acpi/scan.c     |  231 +++++++++++++++++++++++++-
 linux-2.6.14-rc3-root/include/acpi/acpi_bus.h |   34 +++
 2 files changed, 263 insertions(+), 2 deletions(-)

diff -puN drivers/acpi/scan.c~acpi_bus drivers/acpi/scan.c
--- linux-2.6.14-rc3/drivers/acpi/scan.c~acpi_bus	2005-10-11 14:13:26.000000000 +0800
+++ linux-2.6.14-rc3-root/drivers/acpi/scan.c	2005-10-13 13:59:08.000000000 +0800
@@ -112,6 +112,234 @@ static struct kset acpi_namespace_kset =
 	.hotplug_ops = &namespace_hotplug_ops,
 };
 
+/* ACPI phys bus */
+static int acpi_phys_bus_match(struct device *dev, struct device_driver *drv)
+{
+	struct acpi_phys_device *phys_dev = to_acpi_phys_dev(dev);
+	struct acpi_phys_driver *phys_drv = to_acpi_phys_drv(drv);
+	return !acpi_match_ids(phys_dev->acpi_dev, phys_drv->ids);
+}
+
+static int acpi_phys_bus_hotplug(struct device *dev, char **envp,
+	int num_envp, char *buffer, int buffer_size)
+{
+	int i = 0;
+	struct acpi_device *acpi_dev = to_acpi_phys_dev(dev)->acpi_dev;
+	char *scratch;
+	int length = 0;
+	struct acpi_compatible_id_list *cid_list;
+
+	scratch = buffer;
+	if (acpi_dev->flags.hardware_id) {
+		envp[i++] = scratch;
+		length += scnprintf(scratch, buffer_size - length, "HWID=%s",
+			acpi_dev->pnp.hardware_id);
+		if ((buffer_size - length <=0) || (i > num_envp))
+			return -ENOMEM;
+		++length;
+		scratch += length;
+	}
+	if (acpi_dev->flags.compatible_ids) {
+		int j;
+		cid_list = acpi_dev->pnp.cid_list;
+
+		/* multiple _CID entries */
+		for (j = 0; j < cid_list->count; j++)
+		{
+			envp[i++] = scratch;
+			length += scnprintf(scratch, buffer_size - length,
+				"COMPTID=%s", cid_list->id[j].value);
+			if ((buffer_size - length <=0) || (i > num_envp))
+				return -ENOMEM;
+			++length;
+			scratch += length;
+		}
+	}
+	envp[i] = NULL;
+
+	return 0;
+}
+
+static int acpi_phys_bus_suspend(struct device * dev, pm_message_t state)
+{
+	struct acpi_phys_device *phys_dev = to_acpi_phys_dev(dev);
+
+	if (!phys_dev->driver || !phys_dev->driver->suspend)
+		return 0;
+	return phys_dev->driver->suspend(phys_dev, state);
+}
+
+static int acpi_phys_bus_resume(struct device * dev)
+{
+	struct acpi_phys_device *phys_dev = to_acpi_phys_dev(dev);
+
+	if (!phys_dev->driver || !phys_dev->driver->resume)
+		return 0;
+	return phys_dev->driver->resume(phys_dev);
+}
+
+static struct bus_type acpi_phys_bus_type = {
+	.name = "acpi",
+	.match = acpi_phys_bus_match,
+	.hotplug = acpi_phys_bus_hotplug,
+	.suspend = acpi_phys_bus_suspend,
+	.resume = acpi_phys_bus_resume,
+};
+
+static LIST_HEAD(acpi_phys_devices);
+static DEFINE_SPINLOCK(acpi_phys_bus_lock);
+static struct acpi_phys_device *phys_root;
+
+static void acpi_phys_device_release(struct device *dev)
+{
+	struct acpi_phys_device *phys_dev = to_acpi_phys_dev(dev);
+	kfree(phys_dev);
+}
+
+static int acpi_phys_bus_add(struct acpi_device *acpi_dev)
+{
+	struct acpi_phys_device *phys_dev;
+
+	phys_dev = kzalloc(sizeof(struct acpi_phys_device), GFP_KERNEL);
+	if (!phys_dev)
+		return -ENOMEM;
+
+	spin_lock(&acpi_phys_bus_lock);
+	list_add_tail(&phys_dev->node, &acpi_phys_devices);
+	spin_unlock(&acpi_phys_bus_lock);
+
+	phys_dev->acpi_dev = acpi_dev;
+	phys_dev->phys_dev.parent = &phys_root->phys_dev;
+	phys_dev->phys_dev.bus = &acpi_phys_bus_type;
+	device_initialize(&phys_dev->phys_dev);
+	sprintf(phys_dev->phys_dev.bus_id, "%s", acpi_dev->pnp.bus_id);
+	phys_dev->phys_dev.release = acpi_phys_device_release;
+	device_add(&phys_dev->phys_dev);
+	return 0;
+}
+
+static int acpi_phys_bus_remove(struct acpi_device *acpi_dev, int type)
+{
+	struct acpi_phys_device *phys_dev, *tmp, *find = NULL;
+
+	spin_lock(&acpi_phys_bus_lock);
+	list_for_each_entry_safe(phys_dev, tmp, &acpi_phys_devices, node) {
+		if (phys_dev->acpi_dev == acpi_dev) {
+			find = phys_dev;
+			list_del(&find->node);
+			break;
+		}
+	}
+	spin_unlock(&acpi_phys_bus_lock);
+	if (find)
+		device_unregister(&find->phys_dev);
+	return 0;
+}
+
+/* this driver is linking acpi device with acpi phys device */
+static struct acpi_driver dummy_driver = {
+	.name = "acpi_dummy",
+	/* List all ids of ACPI phys devices */
+	.ids =
+//		"PNP0C09," /* EC */
+//		"ACPI0003," /* AC */
+//		"PNP0C0F," /* Link */
+//		"PNP0C0A," /* battery */
+//		"PNP0C0C,PNP0C0E,PNP0C0D,ACPI_FPB,ACPI_FSB," /* button */
+//		"PNP0C0B," /* fan */
+//		"PNP0A03," /* PCI root */
+//		ACPI_POWER_HID"," /* power */
+//		ACPI_PROCESSOR_HID"," /* CPU */
+//		ACPI_THERMAL_HID"," /* thermal */
+		"",
+	.ops = {
+		.add = acpi_phys_bus_add,
+		.remove = acpi_phys_bus_remove,
+	},
+};
+
+static int __init acpi_phys_bus_init(void)
+{
+	bus_register(&acpi_phys_bus_type);
+
+	phys_root = kzalloc(sizeof(struct acpi_phys_device), GFP_KERNEL);
+	if (!phys_root)
+		return -ENOMEM;
+
+	phys_root->acpi_dev = acpi_root;
+	phys_root->phys_dev.release = acpi_phys_device_release;
+	sprintf(phys_root->phys_dev.bus_id, "%s", acpi_root->pnp.bus_id);
+	device_register(&phys_root->phys_dev);
+
+	/* enumerate devices */
+	acpi_bus_register_driver(&dummy_driver);
+	return 0;
+}
+
+
+static int acpi_phys_device_probe(struct device *dev)
+{
+	int error = -ENODEV;
+	struct acpi_phys_device *phys_dev = to_acpi_phys_dev(dev);
+	struct acpi_phys_driver *phys_drv = to_acpi_phys_drv(dev->driver);
+
+	get_device(dev);
+	if (!phys_dev->driver && phys_drv->probe) {
+		error = phys_drv->probe(phys_dev);
+		if (error >= 0)
+			phys_dev->driver = phys_drv;
+	}
+	if (error < 0)
+		put_device(dev);
+	return error;
+}
+
+static int acpi_phys_device_remove(struct device * dev)
+{
+	struct acpi_phys_device *phys_dev = to_acpi_phys_dev(dev);
+	struct acpi_phys_driver *phys_drv = phys_dev->driver;
+
+	if (phys_drv) {
+		if (phys_drv->remove)
+			phys_drv->remove(phys_dev);
+		phys_dev->driver = NULL;
+	}
+	put_device(dev);
+	return 0;
+}
+
+static void acpi_phys_device_shutdown(struct device *dev)
+{
+	struct acpi_phys_device *phys_dev = to_acpi_phys_dev(dev);
+
+	if (!phys_dev->driver || !phys_dev->driver->shutdown)
+		return;
+
+	phys_dev->driver->shutdown(phys_dev);
+}
+
+int acpi_phys_driver_register(struct acpi_phys_driver *drv)
+{
+	int error;
+	/*FIXME: add to a list */
+	drv->phys_drv.name = drv->name;
+	drv->phys_drv.bus = &acpi_phys_bus_type;
+	drv->phys_drv.probe = acpi_phys_device_probe;
+	drv->phys_drv.remove = acpi_phys_device_remove;
+	drv->phys_drv.shutdown = acpi_phys_device_shutdown;
+	drv->phys_drv.owner = drv->owner;
+	error = driver_register(&drv->phys_drv);
+	return error;
+}
+EXPORT_SYMBOL(acpi_phys_driver_register);
+
+void acpi_phys_driver_unregister(struct acpi_phys_driver *drv)
+{
+	driver_unregister(&drv->phys_drv);
+}
+EXPORT_SYMBOL(acpi_phys_driver_unregister);
+/*-----------------------------------*/
+
 static void acpi_device_register(struct acpi_device *device,
 				 struct acpi_device *parent)
 {
@@ -1400,8 +1628,9 @@ static int __init acpi_scan_init(void)
 
 	if (result)
 		acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL);
+	acpi_phys_bus_init();
 
-      Done:
+Done:
 	return_VALUE(result);
 }
 
diff -puN include/acpi/acpi_bus.h~acpi_bus include/acpi/acpi_bus.h
--- linux-2.6.14-rc3/include/acpi/acpi_bus.h~acpi_bus	2005-10-11 14:13:26.000000000 +0800
+++ linux-2.6.14-rc3-root/include/acpi/acpi_bus.h	2005-10-13 10:43:21.000000000 +0800
@@ -28,6 +28,7 @@
 
 #include <linux/kobject.h>
 
+#include <linux/device.h>
 #include <acpi/acpi.h>
 
 #define PREFIX			"ACPI: "
@@ -300,6 +301,38 @@ struct acpi_device {
 
 #define acpi_driver_data(d)	((d)->driver_data)
 
+/* acpi bus type for real ACPI device */
+struct acpi_phys_device {
+	struct list_head node;
+	struct acpi_device *acpi_dev;
+	struct device phys_dev;
+	struct acpi_phys_driver *driver;
+	void *driver_data;
+};
+
+#define acpi_phys_driver_data(d) ((d)->driver_data)
+
+struct acpi_phys_driver {
+//	struct list_head node;
+	char name[80];
+	char class[80];
+	struct module *owner;
+	char *ids;
+	int (*probe)(struct acpi_phys_device *dev);
+	void (*remove) (struct acpi_phys_device *dev);
+	int  (*suspend) (struct acpi_phys_device *dev, pm_message_t state);
+	int  (*resume) (struct acpi_phys_device *dev);
+	void (*shutdown) (struct acpi_phys_device *dev);
+
+	struct device_driver    phys_drv;
+};
+
+#define to_acpi_phys_dev(n) container_of(n, struct acpi_phys_device, phys_dev)
+#define to_acpi_phys_drv(n) container_of(n, struct acpi_phys_driver, phys_drv)
+int acpi_phys_driver_register(struct acpi_phys_driver *drv);
+void acpi_phys_driver_unregister(struct acpi_phys_driver *drv);
+
+
 /*
  * Events
  * ------
@@ -339,7 +372,6 @@ void acpi_remove_dir(struct acpi_device 
 /*
  * Bind physical devices with ACPI devices
  */
-#include <linux/device.h>
 struct acpi_bus_type {
 	struct list_head list;
 	struct bus_type *bus;
_




-------------------------------------------------------
This SF.Net email is sponsored by:
Power Architecture Resource Center: Free content, downloads, discussions,
and more. http://solutions.newsforge.com/ibmarch.tmpl

^ permalink raw reply	[flat|nested] 15+ messages in thread
* RE: [RFC]convert ACPI driver model to Linux driver model - takes 2
@ 2005-10-13  7:45 Yu, Luming
  2005-10-13  8:20 ` Shaohua Li
  0 siblings, 1 reply; 15+ messages in thread
From: Yu, Luming @ 2005-10-13  7:45 UTC (permalink / raw)
  To: Li, Shaohua, acpi-dev; +Cc: Brown, Len, Dominik Brodowski, Adam Belay

>+static int __init acpi_phys_bus_init(void)
>+{
>+	bus_register(&acpi_phys_bus_type);
>+
>+	phys_root = kzalloc(sizeof(struct acpi_phys_device), 
>GFP_KERNEL);
>+	if (!phys_root)
>+		return -ENOMEM;
>+
>+	phys_root->acpi_dev = acpi_root;
>+	phys_root->phys_dev.release = acpi_phys_device_release;
>+	sprintf(phys_root->phys_dev.bus_id, "%s", 
>acpi_root->pnp.bus_id);
>+	device_register(&phys_root->phys_dev);
>+
>+	/* enumerate devices */
>+	acpi_bus_register_driver(&dummy_driver);
>+	return 0;
>+}

The structure is in a mess. why not cut bus.c?

I like this:

acpi_bus_init(void)
{
...
bus_register(&acpi_bus_type);
...
driver_register(&acpi_bus_driver);
...
}



-------------------------------------------------------
This SF.Net email is sponsored by:
Power Architecture Resource Center: Free content, downloads, discussions,
and more. http://solutions.newsforge.com/ibmarch.tmpl

^ permalink raw reply	[flat|nested] 15+ messages in thread
* Re: [RFC]convert ACPI driver model to Linux driver model - takes 2
@ 2005-10-13  8:18 mika.penttila-9Aww8k/80nUxHbG02/KK1g
       [not found] ` <20051013081837.PTGN24578.fep01-app.kolumbus.fi-7B1qVitd7rZYRdgNIgFt/t8DI8KqlI9s@public.gmane.org>
  0 siblings, 1 reply; 15+ messages in thread
From: mika.penttila-9Aww8k/80nUxHbG02/KK1g @ 2005-10-13  8:18 UTC (permalink / raw)
  To: Shaohua Li, acpi-dev; +Cc: Len, Dominik Brodowski, Adam Belay


>+/* this driver is linking acpi device with acpi phys device */
>+static struct acpi_driver dummy_driver = {
>+ .name = "acpi_dummy",
>+ /* List all ids of ACPI phys devices */
>+ .ids =
>+// "PNP0C09," /* EC */
>+// "ACPI0003," /* AC */
>+// "PNP0C0F," /* Link */
>+// "PNP0C0A," /* battery */
>+// "PNP0C0C,PNP0C0E,PNP0C0D,ACPI_FPB,ACPI_FSB," /* button */
>+// "PNP0C0B," /* fan */
>+// "PNP0A03," /* PCI root */
>+// ACPI_POWER_HID"," /* power */
>+// ACPI_PROCESSOR_HID"," /* CPU */
>+// ACPI_THERMAL_HID"," /* thermal */
>+ "",
>+ .ops = {
>+ .add = acpi_phys_bus_add,
>+ .remove = acpi_phys_bus_remove,
>+ },
>+};

Are those ids meant to be commented out in the dummy driver?

--Mika




-------------------------------------------------------
This SF.Net email is sponsored by:
Power Architecture Resource Center: Free content, downloads, discussions,
and more. http://solutions.newsforge.com/ibmarch.tmpl

^ permalink raw reply	[flat|nested] 15+ messages in thread
* RE: [RFC]convert ACPI driver model to Linux driver model -      takes 2
@ 2005-10-14  9:35 Li, Shaohua
  2005-10-14 12:47 ` Matthew Wilcox
  2005-10-14 15:54 ` Bjorn Helgaas
  0 siblings, 2 replies; 15+ messages in thread
From: Li, Shaohua @ 2005-10-14  9:35 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: acpi-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Brown, Len,
	Dominik Brodowski, Adam Belay

Hi,
>
>> On Fri, 2005-10-14 at 04:43 +0800, Bjorn Helgaas wrote:
>>> You now have both 'acpi_driver' and 'acpi_phys_driver' (and
>>> 'acpi_device' and 'acpi_phys_device').  What exactly is the
>>> distinction?  Is the distinction necessary?  Can you just stuff
>>> the generic device stuff into 'struct acpi_device' itself?
>
>> Devices in ACPI bus use acpi_phys_driver, other devices use
acpi_driver.
>
>I'm sorry to be dense, but this doesn't help me.  What do you
>mean by "devices in ACPI bus" as opposed to other ACPI devices?
>
>Let's say I want to write a driver for something in ACPI, like
>a fan.  How do I decide whether to use acpi_phys_driver or
>acpi_driver?
>
>Do you mean that I can use either one, and that you want to
>migrate drivers from acpi_driver to acpi_phys_driver over time?
>
In my mind, the devices which don't belong to other physical buses (such
as PCI, PNP) are ACPI bus devices. These devices are:
+//		"PNP0C09," /* EC */
+//		"ACPI0003," /* AC */
+//		"PNP0C0F," /* Link */
+//		"PNP0C0A," /* battery */
+//		"PNP0C0C,PNP0C0E,PNP0C0D,ACPI_FPB,ACPI_FSB," /* button
*/
+//		"PNP0C0B," /* fan */
+//		"PNP0A03," /* PCI root */
+//		ACPI_POWER_HID"," /* power */
+//		ACPI_PROCESSOR_HID"," /* CPU */
+//		ACPI_THERMAL_HID"," /* thermal */
The devices only can use acpi_phys_driver. Other devices still use
acpi_driver.

>If that's the case, I think we should end up with acpi_driver,
>not acpi_phys_driver, because "phys" doesn't tell me anything
>useful.  And there aren't very many ACPI drivers, so I don't
>really see the problem with just moving them all at once.
I agree we should just have acpi_driver. Non ACPI bus devices should
directly use ACPI services instead of registering an acpi_driver. The
issue is there are some ACPI drivers whose devices are hard to catalog,
such as video, hotkey. Anyway, the change should be slow.
The other issue is some ACPI drivers such as pci_root.c processor.c now
support hotplug. They require two call backs (.add, .start). The
callbacks are called in different sequence at the hotplug time and boot
time. Linux driver model provides .probe callback, so it's hard to
convert pci_root.c and processor.c.
For the acpi_device/acpi_phys_device, do you think we should just have
acpi_device as well?

Thanks,
Shaohua


-------------------------------------------------------
This SF.Net email is sponsored by:
Power Architecture Resource Center: Free content, downloads, discussions,
and more. http://solutions.newsforge.com/ibmarch.tmpl

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2005-10-20 17:04 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-10-13  6:37 [RFC]convert ACPI driver model to Linux driver model - takes 2 Shaohua Li
     [not found] ` <1129185454.9074.15.camel-ECwVeV2eNyQD0+JXs3kMbRL4W9x8LtSr@public.gmane.org>
2005-10-13 20:43   ` Bjorn Helgaas
     [not found]     ` <200510131443.47844.bjorn.helgaas-VXdhtT5mjnY@public.gmane.org>
2005-10-14  1:13       ` Shaohua Li
     [not found]         ` <1129252436.3948.12.camel-ECwVeV2eNyQD0+JXs3kMbRL4W9x8LtSr@public.gmane.org>
2005-10-14  3:21           ` Bjorn Helgaas
2005-10-20 17:04   ` Bjorn Helgaas
  -- strict thread matches above, loose matches on Subject: below --
2005-10-13  7:45 Yu, Luming
2005-10-13  8:20 ` Shaohua Li
2005-10-13  8:18 mika.penttila-9Aww8k/80nUxHbG02/KK1g
     [not found] ` <20051013081837.PTGN24578.fep01-app.kolumbus.fi-7B1qVitd7rZYRdgNIgFt/t8DI8KqlI9s@public.gmane.org>
2005-10-13  8:32   ` Shaohua Li
2005-10-14  9:35 Li, Shaohua
2005-10-14 12:47 ` Matthew Wilcox
     [not found]   ` <20051014124749.GD16113-6jwH94ZQLHl74goWV3ctuw@public.gmane.org>
2005-10-18  1:30     ` Shaohua Li
     [not found]       ` <1129599034.3965.6.camel-ECwVeV2eNyQD0+JXs3kMbRL4W9x8LtSr@public.gmane.org>
2005-10-18 17:32         ` Rajesh Shah
2005-10-14 15:54 ` Bjorn Helgaas
     [not found]   ` <200510140954.52206.bjorn.helgaas-VXdhtT5mjnY@public.gmane.org>
2005-10-18  3:06     ` Shaohua Li

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox