diff options
| -rw-r--r-- | drivers/base/Makefile | 1 | ||||
| -rw-r--r-- | drivers/base/isa.c | 180 | ||||
| -rw-r--r-- | include/linux/isa.h | 28 | 
3 files changed, 209 insertions, 0 deletions
diff --git a/drivers/base/Makefile b/drivers/base/Makefile index 659cde6c2fb..b539e5e75b5 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile @@ -5,6 +5,7 @@ obj-y			:= core.o sys.o bus.o dd.o \  			   cpu.o firmware.o init.o map.o dmapool.o \  			   attribute_container.o transport_class.o  obj-y			+= power/ +obj-$(CONFIG_ISA)	+= isa.o  obj-$(CONFIG_FW_LOADER)	+= firmware_class.o  obj-$(CONFIG_NUMA)	+= node.o  obj-$(CONFIG_MEMORY_HOTPLUG) += memory.o diff --git a/drivers/base/isa.c b/drivers/base/isa.c new file mode 100644 index 00000000000..d2222397a40 --- /dev/null +++ b/drivers/base/isa.c @@ -0,0 +1,180 @@ +/* + * ISA bus. + */ + +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/isa.h> + +static struct device isa_bus = { +	.bus_id		= "isa" +}; + +struct isa_dev { +	struct device dev; +	struct device *next; +	unsigned int id; +}; + +#define to_isa_dev(x) container_of((x), struct isa_dev, dev) + +static int isa_bus_match(struct device *dev, struct device_driver *driver) +{ +	struct isa_driver *isa_driver = to_isa_driver(driver); + +	if (dev->platform_data == isa_driver) { +		if (!isa_driver->match || +			isa_driver->match(dev, to_isa_dev(dev)->id)) +			return 1; +		dev->platform_data = NULL; +	} +	return 0; +} + +static int isa_bus_probe(struct device *dev) +{ +	struct isa_driver *isa_driver = dev->platform_data; + +	if (isa_driver->probe) +		return isa_driver->probe(dev, to_isa_dev(dev)->id); + +	return 0; +} + +static int isa_bus_remove(struct device *dev) +{ +	struct isa_driver *isa_driver = dev->platform_data; + +	if (isa_driver->remove) +		return isa_driver->remove(dev, to_isa_dev(dev)->id); + +	return 0; +} + +static void isa_bus_shutdown(struct device *dev) +{ +	struct isa_driver *isa_driver = dev->platform_data; + +	if (isa_driver->shutdown) +		isa_driver->shutdown(dev, to_isa_dev(dev)->id); +} + +static int isa_bus_suspend(struct device *dev, pm_message_t state) +{ +	struct isa_driver *isa_driver = dev->platform_data; + +	if (isa_driver->suspend) +		return isa_driver->suspend(dev, to_isa_dev(dev)->id, state); + +	return 0; +} + +static int isa_bus_resume(struct device *dev) +{ +	struct isa_driver *isa_driver = dev->platform_data; + +	if (isa_driver->resume) +		return isa_driver->resume(dev, to_isa_dev(dev)->id); + +	return 0; +} + +static struct bus_type isa_bus_type = { +	.name		= "isa", +	.match		= isa_bus_match, +	.probe		= isa_bus_probe, +	.remove		= isa_bus_remove, +	.shutdown	= isa_bus_shutdown, +	.suspend	= isa_bus_suspend, +	.resume		= isa_bus_resume +}; + +static void isa_dev_release(struct device *dev) +{ +	kfree(to_isa_dev(dev)); +} + +void isa_unregister_driver(struct isa_driver *isa_driver) +{ +	struct device *dev = isa_driver->devices; + +	while (dev) { +		struct device *tmp = to_isa_dev(dev)->next; +		device_unregister(dev); +		dev = tmp; +	} +	driver_unregister(&isa_driver->driver); +} +EXPORT_SYMBOL_GPL(isa_unregister_driver); + +int isa_register_driver(struct isa_driver *isa_driver, unsigned int ndev) +{ +	int error; +	unsigned int id; + +	isa_driver->driver.bus	= &isa_bus_type; +	isa_driver->devices	= NULL; + +	error = driver_register(&isa_driver->driver); +	if (error) +		return error; + +	for (id = 0; id < ndev; id++) { +		struct isa_dev *isa_dev; + +		isa_dev = kzalloc(sizeof *isa_dev, GFP_KERNEL); +		if (!isa_dev) { +			error = -ENOMEM; +			break; +		} + +		isa_dev->dev.parent	= &isa_bus; +		isa_dev->dev.bus	= &isa_bus_type; + +		snprintf(isa_dev->dev.bus_id, BUS_ID_SIZE, "%s.%u", +				isa_driver->driver.name, id); + +		isa_dev->dev.platform_data	= isa_driver; +		isa_dev->dev.release		= isa_dev_release; +		isa_dev->id			= id; + +		error = device_register(&isa_dev->dev); +		if (error) { +			put_device(&isa_dev->dev); +			break; +		} + +		if (isa_dev->dev.platform_data) { +			isa_dev->next = isa_driver->devices; +			isa_driver->devices = &isa_dev->dev; +		} else +			device_unregister(&isa_dev->dev); +	} + +	if (!error && !isa_driver->devices) +		error = -ENODEV; + +	if (error) +		isa_unregister_driver(isa_driver); + +	return error; +} +EXPORT_SYMBOL_GPL(isa_register_driver); + +static int __init isa_bus_init(void) +{ +	int error; + +	error = bus_register(&isa_bus_type); +	if (!error) { +		error = device_register(&isa_bus); +		if (error) +			bus_unregister(&isa_bus_type); +	} +	return error; +} + +device_initcall(isa_bus_init); diff --git a/include/linux/isa.h b/include/linux/isa.h new file mode 100644 index 00000000000..1b855335cb1 --- /dev/null +++ b/include/linux/isa.h @@ -0,0 +1,28 @@ +/* + * ISA bus. + */ + +#ifndef __LINUX_ISA_H +#define __LINUX_ISA_H + +#include <linux/device.h> +#include <linux/kernel.h> + +struct isa_driver { +	int (*match)(struct device *, unsigned int); +	int (*probe)(struct device *, unsigned int); +	int (*remove)(struct device *, unsigned int); +	void (*shutdown)(struct device *, unsigned int); +	int (*suspend)(struct device *, unsigned int, pm_message_t); +	int (*resume)(struct device *, unsigned int); + +	struct device_driver driver; +	struct device *devices; +}; + +#define to_isa_driver(x) container_of((x), struct isa_driver, driver) + +int isa_register_driver(struct isa_driver *, unsigned int); +void isa_unregister_driver(struct isa_driver *); + +#endif /* __LINUX_ISA_H */  |