macio_asic.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 637 行 · 第 1/2 页

C
637
字号
/* * Bus & driver management routines for devices within * a MacIO ASIC. Interface to new driver model mostly * stolen from the PCI version. *  * TODO: *  *  - Don't probe below media bay by default, but instead provide *    some hooks for media bay to dynamically add/remove it's own *    sub-devices. */ #include <linux/config.h>#include <linux/string.h>#include <linux/kernel.h>#include <linux/pci.h>#include <linux/pci_ids.h>#include <linux/init.h>#include <linux/module.h>#include <asm/machdep.h>#include <asm/macio.h>#include <asm/pmac_feature.h>#include <asm/prom.h>#include <asm/pci-bridge.h>#undef DEBUG#define MAX_NODE_NAME_SIZE (BUS_ID_SIZE - 12)static struct macio_chip      *macio_on_hold;static int macio_bus_match(struct device *dev, struct device_driver *drv) {	struct macio_dev * macio_dev = to_macio_device(dev);	struct macio_driver * macio_drv = to_macio_driver(drv);	const struct of_match * matches = macio_drv->match_table;	if (!matches) 		return 0;	return of_match_device(matches, &macio_dev->ofdev) != NULL;}struct macio_dev *macio_dev_get(struct macio_dev *dev){	struct device *tmp;	if (!dev)		return NULL;	tmp = get_device(&dev->ofdev.dev);	if (tmp)		return to_macio_device(tmp);	else		return NULL;}void macio_dev_put(struct macio_dev *dev){	if (dev)		put_device(&dev->ofdev.dev);}static int macio_device_probe(struct device *dev){	int error = -ENODEV;	struct macio_driver *drv;	struct macio_dev *macio_dev;	const struct of_match *match;	drv = to_macio_driver(dev->driver);	macio_dev = to_macio_device(dev);	if (!drv->probe)		return error;	macio_dev_get(macio_dev);	match = of_match_device(drv->match_table, &macio_dev->ofdev);	if (match)		error = drv->probe(macio_dev, match);	if (error)		macio_dev_put(macio_dev);	return error;}static int macio_device_remove(struct device *dev){	struct macio_dev * macio_dev = to_macio_device(dev);	struct macio_driver * drv = to_macio_driver(dev->driver);	if (dev->driver && drv->remove)		drv->remove(macio_dev);	macio_dev_put(macio_dev);	return 0;}static void macio_device_shutdown(struct device *dev){	struct macio_dev * macio_dev = to_macio_device(dev);	struct macio_driver * drv = to_macio_driver(dev->driver);	if (dev->driver && drv->shutdown)		drv->shutdown(macio_dev);}static int macio_device_suspend(struct device *dev, u32 state){	struct macio_dev * macio_dev = to_macio_device(dev);	struct macio_driver * drv = to_macio_driver(dev->driver);	if (dev->driver && drv->suspend)		return drv->suspend(macio_dev, state);	return 0;}static int macio_device_resume(struct device * dev){	struct macio_dev * macio_dev = to_macio_device(dev);	struct macio_driver * drv = to_macio_driver(dev->driver);	if (dev->driver && drv->resume)		return drv->resume(macio_dev);	return 0;}struct bus_type macio_bus_type = {       .name	= "macio",       .match	= macio_bus_match,       .suspend	= macio_device_suspend,       .resume	= macio_device_resume,};static int __init macio_bus_driver_init(void){	return bus_register(&macio_bus_type);}postcore_initcall(macio_bus_driver_init);/** * macio_release_dev - free a macio 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 macio device are * done. This currently means never as we don't hot remove any macio device yet, * though that will happen with mediabay based devices in a later implementation. */static void macio_release_dev(struct device *dev){	struct macio_dev *mdev;        mdev = to_macio_device(dev);	kfree(mdev);}/** * macio_resource_quirks - tweak or skip some resources for a device * @np: pointer to the device node * @res: resulting resource * @index: index of resource in node * * If this routine returns non-null, then the resource is completely * skipped. */static int macio_resource_quirks(struct device_node *np, struct resource *res, int index){	if (res->flags & IORESOURCE_MEM) {		/* Grand Central has too large resource 0 on some machines */		if (index == 0 && !strcmp(np->name, "gc")) {			np->addrs[0].size = 0x20000;			res->end = res->start + 0x1ffff;		}		/* Airport has bogus resource 2 */		if (index >= 2 && !strcmp(np->name, "radio"))			return 1;		/* DBDMAs may have bogus sizes */		if ((res->start & 0x0001f000) == 0x00008000) {			np->addrs[index].size = 0x100;			res->end = res->start + 0xff;		}		/* ESCC parent eats child resources. We could have added a level of hierarchy,		 * but I don't really feel the need for it */		if (!strcmp(np->name, "escc"))			return 1;		/* ESCC has bogus resources >= 3 */		if (index >= 3 && !(strcmp(np->name, "ch-a") && strcmp(np->name, "ch-b")))			return 1;		/* Media bay has too many resources, keep only first one */		if (index > 0 && !strcmp(np->name, "media-bay"))			return 1;		/* Some older IDE resources have bogus sizes */		if (!(strcmp(np->name, "IDE") && strcmp(np->name, "ATA") &&		      strcmp(np->type, "ide") && strcmp(np->type, "ata"))) {			if (index == 0 && np->addrs[0].size > 0x1000) {				np->addrs[0].size = 0x1000;				res->end = res->start + 0xfff;			}			if (index == 1 && np->addrs[1].size > 0x100) {				np->addrs[1].size = 0x100;				res->end = res->start + 0xff;			}		}	}	return 0;}/** * macio_add_one_device - Add one device from OF node to the device tree * @chip: pointer to the macio_chip holding the device * @np: pointer to the device node in the OF tree * @in_bay: set to 1 if device is part of a media-bay * * When media-bay is changed to hotswap drivers, this function will * be exposed to the bay driver some way... */static struct macio_dev * macio_add_one_device(struct macio_chip *chip, struct device *parent,					       struct device_node *np, struct macio_dev *in_bay,					       struct resource *parent_res){	struct macio_dev *dev;	int i, j;	u32 *reg;		if (np == NULL)		return NULL;	dev = kmalloc(sizeof(*dev), GFP_KERNEL);	if (!dev)		return NULL;	memset(dev, 0, sizeof(*dev));	dev->bus = &chip->lbus;	dev->media_bay = in_bay;	dev->ofdev.node = np;	dev->ofdev.dma_mask = 0xffffffffUL;	dev->ofdev.dev.dma_mask = &dev->ofdev.dma_mask;	dev->ofdev.dev.parent = parent;	dev->ofdev.dev.bus = &macio_bus_type;	dev->ofdev.dev.release = macio_release_dev;#ifdef DEBUG	printk("preparing mdev @%p, ofdev @%p, dev @%p, kobj @%p\n",	       dev, &dev->ofdev, &dev->ofdev.dev, &dev->ofdev.dev.kobj);#endif	/* MacIO itself has a different reg, we use it's PCI base */	if (np == chip->of_node) {		sprintf(dev->ofdev.dev.bus_id, "%1d.%08lx:%.*s", chip->lbus.index,#ifdef CONFIG_PCI			pci_resource_start(chip->lbus.pdev, 0),#else			0, /* NuBus may want to do something better here */#endif			MAX_NODE_NAME_SIZE, np->name);	} else {		reg = (u32 *)get_property(np, "reg", NULL);		sprintf(dev->ofdev.dev.bus_id, "%1d.%08x:%.*s", chip->lbus.index,			reg ? *reg : 0, MAX_NODE_NAME_SIZE, np->name);	}	/* For now, we use pre-parsed entries in the device-tree for	 * interrupt routing and addresses, but we should change that	 * to dynamically parsed entries and so get rid of most of the	 * clutter in struct device_node	 */	for (i = j = 0; i < np->n_intrs; i++) {		struct resource *res = &dev->interrupt[j];		if (j >= MACIO_DEV_COUNT_IRQS)			break;		res->start = np->intrs[i].line;		res->flags = IORESOURCE_IO;		if (np->intrs[j].sense)			res->flags |= IORESOURCE_IRQ_LOWLEVEL;		else			res->flags |= IORESOURCE_IRQ_HIGHEDGE;		res->name = dev->ofdev.dev.bus_id;		if (macio_resource_quirks(np, res, i))			memset(res, 0, sizeof(struct resource));		else			j++;	}	dev->n_interrupts = j;	for (i = j = 0; i < np->n_addrs; i++) {		struct resource *res = &dev->resource[j];				if (j >= MACIO_DEV_COUNT_RESOURCES)			break;		res->start = np->addrs[i].address;		res->end = np->addrs[i].address + np->addrs[i].size - 1;		res->flags = IORESOURCE_MEM;		res->name = dev->ofdev.dev.bus_id;		if (macio_resource_quirks(np, res, i))			memset(res, 0, sizeof(struct resource));		else {			j++;			/* Currently, we consider failure as harmless, this may			 * change in the future, once I've found all the device			 * tree bugs in older machines & worked around them			 */			if (insert_resource(parent_res, res))       				printk(KERN_WARNING "Can't request resource %d for MacIO"				       " device %s\n", i, dev->ofdev.dev.bus_id);		}	}	dev->n_resources = j;	if (of_device_register(&dev->ofdev) != 0) {		printk(KERN_DEBUG"macio: device registration error for %s!\n",		       dev->ofdev.dev.bus_id);		kfree(dev);		return NULL;	}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?