Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b9d8be78 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6

* master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6: (40 commits)
  [SPARC64]: Update defconfig.
  [SPARC64]: Make auxio a real driver.
  [PARPORT] sunbpp: Convert to new SBUS device framework.
  [Documentation]: Update probing info in sbus_drivers.txt
  [SCSI] qlogicpti: Convert to new SBUS device framework.
  [SCSI] esp: Fix bug in esp_remove_common.
  [NET] sunhme: Kill useless loop over sdevs in quattro_sbus_find().
  [NET] myri_sbus: Kill unused next_module struct member.
  [NET] myri_sbus: Convert to new SBUS device layer.
  [NET] sunqe: Convert to new SBUS driver layer.
  [NET] sunbmac: Convert over to new SBUS device framework.
  [NET] sunlance: Convert to new SBUS driver framework.
  [NET] sunhme: Convert to new SBUS driver framework.
  [NET] sunhme: Kill __sparc__ and __sparc_v9__ ifdefs.
  [SCSI] sparc: Port esp to new SBUS driver layer.
  [SOUND] sparc: Port amd7930 to new SBUS device layer.
  [SBUS]: Rewrite and plug into of_device framework.
  [SPARC]: Port of_device layer and make ebus use it.
  [SPARC]: Port sparc64 in-kernel device tree code to sparc32.
  [SPARC64]: Add of_device layer and make ebus/isa use it.
  ...
parents d02f40e8 1812fd40
Loading
Loading
Loading
Loading
+65 −30
Original line number Diff line number Diff line
@@ -25,42 +25,84 @@ the bits necessary to run your device. The most commonly
used members of this structure, and their typical usage,
will be detailed below.

	Here is how probing is performed by an SBUS driver
under Linux:
	Here is a piece of skeleton code for perofming a device
probe in an SBUS driverunder Linux:

	static void init_one_mydevice(struct sbus_dev *sdev)
	static int __devinit mydevice_probe_one(struct sbus_dev *sdev)
	{
		struct mysdevice *mp = kzalloc(sizeof(*mp), GFP_KERNEL);

		if (!mp)
			return -ENODEV;

		...
		dev_set_drvdata(&sdev->ofdev.dev, mp);
		return 0;
		...
	}

	static int mydevice_match(struct sbus_dev *sdev)
	static int __devinit mydevice_probe(struct of_device *dev,
				            const struct of_device_id *match)
	{
		if (some_criteria(sdev))
			return 1;
		return 0;
		struct sbus_dev *sdev = to_sbus_device(&dev->dev);

		return mydevice_probe_one(sdev);
	}

	static void mydevice_probe(void)
	static int __devexit mydevice_remove(struct of_device *dev)
	{
		struct sbus_bus *sbus;
		struct sbus_dev *sdev;
		struct sbus_dev *sdev = to_sbus_device(&dev->dev);
		struct mydevice *mp = dev_get_drvdata(&dev->dev);

		for_each_sbus(sbus) {
			for_each_sbusdev(sdev, sbus) {
				if (mydevice_match(sdev))
					init_one_mydevice(sdev);
		return mydevice_remove_one(sdev, mp);
	}

	static struct of_device_id mydevice_match[] = {
		{
			.name = "mydevice",
		},
		{},
	};

	MODULE_DEVICE_TABLE(of, mydevice_match);

	static struct of_platform_driver mydevice_driver = {
		.name		= "mydevice",
		.match_table	= mydevice_match,
		.probe		= mydevice_probe,
		.remove		= __devexit_p(mydevice_remove),
	};

	static int __init mydevice_init(void)
	{
		return of_register_driver(&mydevice_driver, &sbus_bus_type);
	}

	static void __exit mydevice_exit(void)
	{
		of_unregister_driver(&mydevice_driver);
	}

	All this does is walk through all SBUS devices in the
system, checks each to see if it is of the type which
your driver is written for, and if so it calls the init
routine to attach the device and prepare to drive it.
	module_init(mydevice_init);
	module_exit(mydevice_exit);

	"init_one_mydevice" might do things like allocate software
state structures, map in I/O registers, place the hardware
into an initialized state, etc.
	The mydevice_match table is a series of entries which
describes what SBUS devices your driver is meant for.  In the
simplest case you specify a string for the 'name' field.  Every
SBUS device with a 'name' property matching your string will
be passed one-by-one to your .probe method.

	You should store away your device private state structure
pointer in the drvdata area so that you can retrieve it later on
in your .remove method.

	Any memory allocated, registers mapped, IRQs registered,
etc. must be undone by your .remove method so that all resources
of your device are relased by the time it returns.

	You should _NOT_ use the for_each_sbus(), for_each_sbusdev(),
and for_all_sbusdev() interfaces.  They are deprecated, will be
removed, and no new driver should reference them ever.

		Mapping and Accessing I/O Registers

@@ -263,10 +305,3 @@ discussed above and plus it handles both PCI and SBUS boards.
	Lance driver abuses consistent mappings for data transfer.
It is a nifty trick which we do not particularly recommend...
Just check it out and know that it's legal.

			Bad examples, do NOT use

	drivers/video/cgsix.c
	This one uses result of sbus_ioremap as if it is an address.
This does NOT work on sparc64 and therefore is broken. We will
convert it at a later date.
+1 −1
Original line number Diff line number Diff line
@@ -12,7 +12,7 @@ obj-y := entry.o wof.o wuf.o etrap.o rtrap.o traps.o $(IRQ_OBJS) \
	    sys_sparc.o sunos_asm.o systbls.o \
	    time.o windows.o cpu.o devices.o sclow.o \
	    tadpole.o tick14.o ptrace.o sys_solaris.o \
	    unaligned.o muldiv.o semaphore.o
	    unaligned.o muldiv.o semaphore.o prom.o of_device.o

obj-$(CONFIG_PCI) += pcic.o
obj-$(CONFIG_SUN4) += sun4setup.o
+105 −80
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
#include <asm/ebus.h>
#include <asm/io.h>
#include <asm/oplib.h>
#include <asm/prom.h>
#include <asm/bpp.h>

struct linux_ebus *ebus_chain = NULL;
@@ -83,79 +84,81 @@ int __init ebus_blacklist_irq(char *name)
	return 0;
}

void __init fill_ebus_child(int node, struct linux_prom_registers *preg,
void __init fill_ebus_child(struct device_node *dp,
			    struct linux_ebus_child *dev)
{
	int regs[PROMREG_MAX];
	int irqs[PROMREG_MAX];
	char lbuf[128];
	int *regs;
	int *irqs;
	int i, len;

	dev->prom_node = node;
	prom_getstring(node, "name", lbuf, sizeof(lbuf));
	strcpy(dev->prom_name, lbuf);

	len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs));
	if (len == -1) len = 0;
	dev->prom_node = dp;
	regs = of_get_property(dp, "reg", &len);
	if (!regs)
		len = 0;
	dev->num_addrs = len / sizeof(regs[0]);

	for (i = 0; i < dev->num_addrs; i++) {
		if (regs[i] >= dev->parent->num_addrs) {
			prom_printf("UGH: property for %s was %d, need < %d\n",
				    dev->prom_name, len, dev->parent->num_addrs);
				    dev->prom_node->name, len,
				    dev->parent->num_addrs);
			panic(__FUNCTION__);
		}
		dev->resource[i].start = dev->parent->resource[regs[i]].start; /* XXX resource */

		/* XXX resource */
		dev->resource[i].start =
			dev->parent->resource[regs[i]].start;
	}

	for (i = 0; i < PROMINTR_MAX; i++)
		dev->irqs[i] = PCI_IRQ_NONE;

	if ((dev->irqs[0] = ebus_blacklist_irq(dev->prom_name)) != 0) {
	if ((dev->irqs[0] = ebus_blacklist_irq(dev->prom_node->name)) != 0) {
		dev->num_irqs = 1;
	} else if ((len = prom_getproperty(node, "interrupts",
	    (char *)&irqs, sizeof(irqs))) == -1 || len == 0) {
	} else {
		irqs = of_get_property(dp, "interrupts", &len);
		if (!irqs) {
			dev->num_irqs = 0;
			dev->irqs[0] = 0;
			if (dev->parent->num_irqs != 0) {
				dev->num_irqs = 1;
				dev->irqs[0] = dev->parent->irqs[0];
/* P3 */ /* printk("EBUS: dev %s irq %d from parent\n", dev->prom_name, dev->irqs[0]); */
			}
		} else {
			dev->num_irqs = len / sizeof(irqs[0]);
			if (irqs[0] == 0 || irqs[0] >= 8) {
				/*
				 * XXX Zero is a valid pin number...
			 * This works as long as Ebus is not wired to INTA#.
				 * This works as long as Ebus is not wired
				 * to INTA#.
				 */
				printk("EBUS: %s got bad irq %d from PROM\n",
			    dev->prom_name, irqs[0]);
				       dev->prom_node->name, irqs[0]);
				dev->num_irqs = 0;
				dev->irqs[0] = 0;
			} else {
			dev->irqs[0] = pcic_pin_to_irq(irqs[0], dev->prom_name);
				dev->irqs[0] =
					pcic_pin_to_irq(irqs[0],
							dev->prom_node->name);
			}
		}
	}
}

void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *dev)
{
	struct linux_prom_registers regs[PROMREG_MAX];
	struct linux_prom_registers *regs;
	struct linux_ebus_child *child;
	int irqs[PROMINTR_MAX];
	char lbuf[128];
	int *irqs;
	int i, n, len;
	unsigned long baseaddr;

	dev->prom_node = node;
	prom_getstring(node, "name", lbuf, sizeof(lbuf));
	strcpy(dev->prom_name, lbuf);
	dev->prom_node = dp;

	len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs));
	regs = of_get_property(dp, "reg", &len);
	if (len % sizeof(struct linux_prom_registers)) {
		prom_printf("UGH: proplen for %s was %d, need multiple of %d\n",
			    dev->prom_name, len,
			    dev->prom_node->name, len,
			    (int)sizeof(struct linux_prom_registers));
		panic(__FUNCTION__);
	}
@@ -197,7 +200,7 @@ void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
			if ((baseaddr = (unsigned long) ioremap(baseaddr,
			    regs[i].reg_size)) == 0) {
				panic("ebus: unable to remap dev %s",
				    dev->prom_name);
				      dev->prom_node->name);
			}
		}
		dev->resource[i].start = baseaddr;	/* XXX Unaligned */
@@ -206,10 +209,11 @@ void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
	for (i = 0; i < PROMINTR_MAX; i++)
		dev->irqs[i] = PCI_IRQ_NONE;

	if ((dev->irqs[0] = ebus_blacklist_irq(dev->prom_name)) != 0) {
	if ((dev->irqs[0] = ebus_blacklist_irq(dev->prom_node->name)) != 0) {
		dev->num_irqs = 1;
	} else if ((len = prom_getproperty(node, "interrupts",
	    (char *)&irqs, sizeof(irqs))) == -1 || len == 0) {
	} else {
		irqs = of_get_property(dp, "interrupts", &len);
		if (!irqs) {
			dev->num_irqs = 0;
			if ((dev->irqs[0] = dev->bus->self->irq) != 0) {
				dev->num_irqs = 1;
@@ -220,15 +224,28 @@ void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
			if (irqs[0] == 0 || irqs[0] >= 8) {
				/* See above for the parent. XXX */
				printk("EBUS: %s got bad irq %d from PROM\n",
			    dev->prom_name, irqs[0]);
				       dev->prom_node->name, irqs[0]);
				dev->num_irqs = 0;
				dev->irqs[0] = 0;
			} else {
			dev->irqs[0] = pcic_pin_to_irq(irqs[0], dev->prom_name);
				dev->irqs[0] =
					pcic_pin_to_irq(irqs[0],
							dev->prom_node->name);
			}
		}
	}

	if ((node = prom_getchild(node))) {
	dev->ofdev.node = dp;
	dev->ofdev.dev.parent = &dev->bus->ofdev.dev;
	dev->ofdev.dev.bus = &ebus_bus_type;
	strcpy(dev->ofdev.dev.bus_id, dp->path_component_name);

	/* Register with core */
	if (of_device_register(&dev->ofdev) != 0)
		printk(KERN_DEBUG "ebus: device registration error for %s!\n",
		       dev->ofdev.dev.bus_id);

	if ((dp = dp->child) != NULL) {
		dev->children = (struct linux_ebus_child *)
			ebus_alloc(sizeof(struct linux_ebus_child));

@@ -236,9 +253,9 @@ void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
		child->next = NULL;
		child->parent = dev;
		child->bus = dev->bus;
		fill_ebus_child(node, &regs[0], child);
		fill_ebus_child(dp, child);

		while ((node = prom_getsibling(node)) != 0) {
		while ((dp = dp->sibling) != NULL) {
			child->next = (struct linux_ebus_child *)
				ebus_alloc(sizeof(struct linux_ebus_child));

@@ -246,51 +263,49 @@ void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
			child->next = NULL;
			child->parent = dev;
			child->bus = dev->bus;
			fill_ebus_child(node, &regs[0], child);
			fill_ebus_child(dp, child);
		}
	}
}

void __init ebus_init(void)
{
	struct linux_prom_pci_registers regs[PROMREG_MAX];
	struct linux_prom_pci_registers *regs;
	struct linux_pbm_info *pbm;
	struct linux_ebus_device *dev;
	struct linux_ebus *ebus;
	struct ebus_system_entry *sp;
	struct pci_dev *pdev;
	struct pcidev_cookie *cookie;
	char lbuf[128];
	struct device_node *dp;
	unsigned long addr, *base;
	unsigned short pci_command;
	int nd, len, ebusnd;
	int reg, nreg;
	int len, reg, nreg;
	int num_ebus = 0;

	prom_getstring(prom_root_node, "name", lbuf, sizeof(lbuf));
	dp = of_find_node_by_path("/");
	for (sp = ebus_blacklist; sp->esname != NULL; sp++) {
		if (strcmp(lbuf, sp->esname) == 0) {
		if (strcmp(dp->name, sp->esname) == 0) {
			ebus_blackp = sp->ipt;
			break;
		}
	}

	pdev = pci_get_device(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_EBUS, NULL);
	if (!pdev) {
	if (!pdev)
		return;
	}

	cookie = pdev->sysdata;
	ebusnd = cookie->prom_node;
	dp = cookie->prom_node;

	ebus_chain = ebus = (struct linux_ebus *)
			ebus_alloc(sizeof(struct linux_ebus));
	ebus->next = NULL;

	while (ebusnd) {
	while (dp) {
		struct device_node *nd;

		prom_getstring(ebusnd, "name", lbuf, sizeof(lbuf));
		ebus->prom_node = ebusnd;
		strcpy(ebus->prom_name, lbuf);
		ebus->prom_node = dp;
		ebus->self = pdev;
		ebus->parent = pbm = cookie->pbm;

@@ -299,9 +314,8 @@ void __init ebus_init(void)
		pci_command |= PCI_COMMAND_MASTER;
		pci_write_config_word(pdev, PCI_COMMAND, pci_command);

		len = prom_getproperty(ebusnd, "reg", (void *)regs,
				       sizeof(regs));
		if (len == 0 || len == -1) {
		regs = of_get_property(dp, "reg", &len);
		if (!regs) {
			prom_printf("%s: can't find reg property\n",
				    __FUNCTION__);
			prom_halt();
@@ -317,7 +331,18 @@ void __init ebus_init(void)
			*base++ = addr;
		}

		nd = prom_getchild(ebusnd);
		ebus->ofdev.node = dp;
		ebus->ofdev.dev.parent = &pdev->dev;
		ebus->ofdev.dev.bus = &ebus_bus_type;
		strcpy(ebus->ofdev.dev.bus_id, dp->path_component_name);

		/* Register with core */
		if (of_device_register(&ebus->ofdev) != 0)
			printk(KERN_DEBUG "ebus: device registration error for %s!\n",
			       ebus->ofdev.dev.bus_id);


		nd = dp->child;
		if (!nd)
			goto next_ebus;

@@ -330,7 +355,7 @@ void __init ebus_init(void)
		dev->bus = ebus;
		fill_ebus_device(nd, dev);

		while ((nd = prom_getsibling(nd)) != 0) {
		while ((nd = nd->sibling) != NULL) {
			dev->next = (struct linux_ebus_device *)
				ebus_alloc(sizeof(struct linux_ebus_device));

@@ -348,7 +373,7 @@ void __init ebus_init(void)
			break;

		cookie = pdev->sysdata;
		ebusnd = cookie->prom_node;
		dp = cookie->prom_node;

		ebus->next = (struct linux_ebus *)
			ebus_alloc(sizeof(struct linux_ebus));
+130 −1
Original line number Diff line number Diff line
@@ -39,6 +39,8 @@
#include <asm/io.h>
#include <asm/vaddrs.h>
#include <asm/oplib.h>
#include <asm/prom.h>
#include <asm/sbus.h>
#include <asm/page.h>
#include <asm/pgalloc.h>
#include <asm/dma.h>
@@ -224,10 +226,54 @@ static void _sparc_free_io(struct resource *res)

#ifdef CONFIG_SBUS

void sbus_set_sbus64(struct sbus_dev *sdev, int x) {
void sbus_set_sbus64(struct sbus_dev *sdev, int x)
{
	printk("sbus_set_sbus64: unsupported\n");
}

extern unsigned int sun4d_build_irq(struct sbus_dev *sdev, int irq);
void __init sbus_fill_device_irq(struct sbus_dev *sdev)
{
	struct linux_prom_irqs irqs[PROMINTR_MAX];
	int len;

	len = prom_getproperty(sdev->prom_node, "intr",
			       (char *)irqs, sizeof(irqs));
	if (len != -1) {
		sdev->num_irqs = len / 8;
		if (sdev->num_irqs == 0) {
			sdev->irqs[0] = 0;
		} else if (sparc_cpu_model == sun4d) {
			for (len = 0; len < sdev->num_irqs; len++)
				sdev->irqs[len] =
					sun4d_build_irq(sdev, irqs[len].pri);
		} else {
			for (len = 0; len < sdev->num_irqs; len++)
				sdev->irqs[len] = irqs[len].pri;
		}
	} else {
		int interrupts[PROMINTR_MAX];

		/* No "intr" node found-- check for "interrupts" node.
		 * This node contains SBus interrupt levels, not IPLs
		 * as in "intr", and no vector values.  We convert
		 * SBus interrupt levels to PILs (platform specific).
		 */
		len = prom_getproperty(sdev->prom_node, "interrupts",
				       (char *)interrupts, sizeof(interrupts));
		if (len == -1) {
			sdev->irqs[0] = 0;
			sdev->num_irqs = 0;
		} else {
			sdev->num_irqs = len / sizeof(int);
			for (len = 0; len < sdev->num_irqs; len++) {
				sdev->irqs[len] =
					sbint_to_irq(sdev, interrupts[len]);
			}
		}
	} 
}

/*
 * Allocate a chunk of memory suitable for DMA.
 * Typically devices use them for control blocks.
@@ -414,6 +460,89 @@ void sbus_dma_sync_sg_for_device(struct sbus_dev *sdev, struct scatterlist *sg,
{
	printk("sbus_dma_sync_sg_for_device: not implemented yet\n");
}

/* Support code for sbus_init().  */
/*
 * XXX This functions appears to be a distorted version of
 * prom_sbus_ranges_init(), with all sun4d stuff cut away.
 * Ask DaveM what is going on here, how is sun4d supposed to work... XXX
 */
/* added back sun4d patch from Thomas Bogendoerfer - should be OK (crn) */
void __init sbus_arch_bus_ranges_init(struct device_node *pn, struct sbus_bus *sbus)
{
	int parent_node = pn->node;

	if (sparc_cpu_model == sun4d) {
		struct linux_prom_ranges iounit_ranges[PROMREG_MAX];
		int num_iounit_ranges, len;

		len = prom_getproperty(parent_node, "ranges",
				       (char *) iounit_ranges,
				       sizeof (iounit_ranges));
		if (len != -1) {
			num_iounit_ranges =
				(len / sizeof(struct linux_prom_ranges));
			prom_adjust_ranges(sbus->sbus_ranges,
					   sbus->num_sbus_ranges,
					   iounit_ranges, num_iounit_ranges);
		}
	}
}

void __init sbus_setup_iommu(struct sbus_bus *sbus, struct device_node *dp)
{
	struct device_node *parent = dp->parent;

	if (sparc_cpu_model != sun4d &&
	    parent != NULL &&
	    !strcmp(parent->name, "iommu")) {
		extern void iommu_init(int iommu_node, struct sbus_bus *sbus);

		iommu_init(parent->node, sbus);
	}

	if (sparc_cpu_model == sun4d) {
		extern void iounit_init(int sbi_node, int iounit_node,
					struct sbus_bus *sbus);

		iounit_init(dp->node, parent->node, sbus);
	}
}

void __init sbus_setup_arch_props(struct sbus_bus *sbus, struct device_node *dp)
{
	if (sparc_cpu_model == sun4d) {
		struct device_node *parent = dp->parent;

		sbus->devid = of_getintprop_default(parent, "device-id", 0);
		sbus->board = of_getintprop_default(parent, "board#", 0);
	}
}

int __init sbus_arch_preinit(void)
{
	extern void register_proc_sparc_ioport(void);

	register_proc_sparc_ioport();

#ifdef CONFIG_SUN4
	{
		extern void sun4_dvma_init(void);
		sun4_dvma_init();
	}
	return 1;
#else
	return 0;
#endif
}

void __init sbus_arch_postinit(void)
{
	if (sparc_cpu_model == sun4d) {
		extern void sun4d_init_sbi_irq(void);
		sun4d_init_sbi_irq();
	}
}
#endif /* CONFIG_SBUS */

#ifdef CONFIG_PCI
+268 −0
Original line number Diff line number Diff line
#include <linux/config.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/slab.h>

#include <asm/errno.h>
#include <asm/of_device.h>

/**
 * of_match_device - Tell if an of_device structure has a matching
 * of_match structure
 * @ids: array of of device match structures to search in
 * @dev: the of device structure to match against
 *
 * Used by a driver to check whether an of_device present in the
 * system is in its list of supported devices.
 */
const struct of_device_id *of_match_device(const struct of_device_id *matches,
					const struct of_device *dev)
{
	if (!dev->node)
		return NULL;
	while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
		int match = 1;
		if (matches->name[0])
			match &= dev->node->name
				&& !strcmp(matches->name, dev->node->name);
		if (matches->type[0])
			match &= dev->node->type
				&& !strcmp(matches->type, dev->node->type);
		if (matches->compatible[0])
			match &= of_device_is_compatible(dev->node,
							 matches->compatible);
		if (match)
			return matches;
		matches++;
	}
	return NULL;
}

static int of_platform_bus_match(struct device *dev, struct device_driver *drv)
{
	struct of_device * of_dev = to_of_device(dev);
	struct of_platform_driver * of_drv = to_of_platform_driver(drv);
	const struct of_device_id * matches = of_drv->match_table;

	if (!matches)
		return 0;

	return of_match_device(matches, of_dev) != NULL;
}

struct of_device *of_dev_get(struct of_device *dev)
{
	struct device *tmp;

	if (!dev)
		return NULL;
	tmp = get_device(&dev->dev);
	if (tmp)
		return to_of_device(tmp);
	else
		return NULL;
}

void of_dev_put(struct of_device *dev)
{
	if (dev)
		put_device(&dev->dev);
}


static int of_device_probe(struct device *dev)
{
	int error = -ENODEV;
	struct of_platform_driver *drv;
	struct of_device *of_dev;
	const struct of_device_id *match;

	drv = to_of_platform_driver(dev->driver);
	of_dev = to_of_device(dev);

	if (!drv->probe)
		return error;

	of_dev_get(of_dev);

	match = of_match_device(drv->match_table, of_dev);
	if (match)
		error = drv->probe(of_dev, match);
	if (error)
		of_dev_put(of_dev);

	return error;
}

static int of_device_remove(struct device *dev)
{
	struct of_device * of_dev = to_of_device(dev);
	struct of_platform_driver * drv = to_of_platform_driver(dev->driver);

	if (dev->driver && drv->remove)
		drv->remove(of_dev);
	return 0;
}

static int of_device_suspend(struct device *dev, pm_message_t state)
{
	struct of_device * of_dev = to_of_device(dev);
	struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
	int error = 0;

	if (dev->driver && drv->suspend)
		error = drv->suspend(of_dev, state);
	return error;
}

static int of_device_resume(struct device * dev)
{
	struct of_device * of_dev = to_of_device(dev);
	struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
	int error = 0;

	if (dev->driver && drv->resume)
		error = drv->resume(of_dev);
	return error;
}

#ifdef CONFIG_PCI
struct bus_type ebus_bus_type = {
       .name	= "ebus",
       .match	= of_platform_bus_match,
       .probe	= of_device_probe,
       .remove	= of_device_remove,
       .suspend	= of_device_suspend,
       .resume	= of_device_resume,
};
#endif

#ifdef CONFIG_SBUS
struct bus_type sbus_bus_type = {
       .name	= "sbus",
       .match	= of_platform_bus_match,
       .probe	= of_device_probe,
       .remove	= of_device_remove,
       .suspend	= of_device_suspend,
       .resume	= of_device_resume,
};
#endif

static int __init of_bus_driver_init(void)
{
	int err = 0;

#ifdef CONFIG_PCI
	if (!err)
		err = bus_register(&ebus_bus_type);
#endif
#ifdef CONFIG_SBUS
	if (!err)
		err = bus_register(&sbus_bus_type);
#endif
	return 0;
}

postcore_initcall(of_bus_driver_init);

int of_register_driver(struct of_platform_driver *drv, struct bus_type *bus)
{
	/* initialize common driver fields */
	drv->driver.name = drv->name;
	drv->driver.bus = bus;

	/* register with core */
	return driver_register(&drv->driver);
}

void of_unregister_driver(struct of_platform_driver *drv)
{
	driver_unregister(&drv->driver);
}


static ssize_t dev_show_devspec(struct device *dev, struct device_attribute *attr, char *buf)
{
	struct of_device *ofdev;

	ofdev = to_of_device(dev);
	return sprintf(buf, "%s", ofdev->node->full_name);
}

static DEVICE_ATTR(devspec, S_IRUGO, dev_show_devspec, NULL);

/**
 * of_release_dev - free an of device structure when all users of it are finished.
 * @dev: device that's been disconnected
 *
 * Will be called only by the device core when all users of this of device are
 * done.
 */
void of_release_dev(struct device *dev)
{
	struct of_device *ofdev;

        ofdev = to_of_device(dev);

	kfree(ofdev);
}

int of_device_register(struct of_device *ofdev)
{
	int rc;

	BUG_ON(ofdev->node == NULL);

	rc = device_register(&ofdev->dev);
	if (rc)
		return rc;

	device_create_file(&ofdev->dev, &dev_attr_devspec);

	return 0;
}

void of_device_unregister(struct of_device *ofdev)
{
	device_remove_file(&ofdev->dev, &dev_attr_devspec);
	device_unregister(&ofdev->dev);
}

struct of_device* of_platform_device_create(struct device_node *np,
					    const char *bus_id,
					    struct device *parent,
					    struct bus_type *bus)
{
	struct of_device *dev;

	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
	if (!dev)
		return NULL;
	memset(dev, 0, sizeof(*dev));

	dev->dev.parent = parent;
	dev->dev.bus = bus;
	dev->dev.release = of_release_dev;

	strlcpy(dev->dev.bus_id, bus_id, BUS_ID_SIZE);

	if (of_device_register(dev) != 0) {
		kfree(dev);
		return NULL;
	}

	return dev;
}

EXPORT_SYMBOL(of_match_device);
EXPORT_SYMBOL(of_register_driver);
EXPORT_SYMBOL(of_unregister_driver);
EXPORT_SYMBOL(of_device_register);
EXPORT_SYMBOL(of_device_unregister);
EXPORT_SYMBOL(of_dev_get);
EXPORT_SYMBOL(of_dev_put);
EXPORT_SYMBOL(of_platform_device_create);
EXPORT_SYMBOL(of_release_dev);
Loading