⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ocp.c

📁 linux-2.4.29操作系统的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * ocp.c * *      (c) Benjamin Herrenschmidt (benh@kernel.crashing.org) *          Mipsys - France * "          Derived from work (c) Armin Kuster akuster@pacbell.net * * * This program is free software; you can redistribute  it and/or modify it *  under  the terms of  the GNU General Public License as published by the *  Free Software Foundation;  either version 2 of the  License, or (at your *  option) any later version. * *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR   IMPLIED *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT, *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *  You should have received a copy of the  GNU General Public License along *  with this program; if not, write  to the Free Software Foundation, Inc., *  675 Mass Ave, Cambridge, MA 02139, USA. * */#include <linux/module.h>#include <linux/config.h>#include <linux/list.h>#include <linux/miscdevice.h>#include <linux/slab.h>#include <linux/types.h>#include <linux/init.h>#include <linux/pm.h>#include <linux/bootmem.h>#include <asm/io.h>#include <asm/ocp.h>#include <asm/errno.h>#include <asm/rwsem.h>#include <asm/semaphore.h>//#define DBG(x)	printk x#define DBG(x)extern int mem_init_done;extern struct ocp_def core_ocp[];	/* Static list of devices, provided by					   CPU core */LIST_HEAD(ocp_devices);			/* List of all OCP devices */LIST_HEAD(ocp_drivers);			/* List of all OCP drivers */DECLARE_RWSEM(ocp_devices_sem);		/* Global semaphores for those lists */DECLARE_MUTEX(ocp_drivers_sem);		/* Global semaphores for those lists */static int ocp_inited;/** *	ocp_driver_match	-	Match one driver to one device *	@drv: driver to match *	@dev: device to match * *	This function returns 0 if the driver and device don't match */static intocp_driver_match(struct ocp_driver *drv, struct ocp_device *dev){	const struct ocp_device_id *ids = drv->id_table;	if (!ids)		return 0;	while (ids->vendor || ids->function) {		if ((ids->vendor == OCP_ANY_ID		     || ids->vendor == dev->def->vendor)		    && (ids->function == OCP_ANY_ID			|| ids->function == dev->def->function))		        return 1;		ids++;	}	return 0;}/** *	ocp_bind_drivers	-	Match all drivers with all devices *	@candidate: driver beeing registered * *	This function is called on driver registration and device discovery, *	it redo the matching of all "driverless" devices with all possible *	driver candidates. *	The driver beeing registered can be optionally passed in, in which *	case, the function will return -ENODEV is no match have been found *	or if all matches failed with a different code than -EAGAIN */static intocp_bind_drivers(struct ocp_driver *candidate){	struct list_head	*deventry, *drventry;	struct ocp_device	*dev;	struct ocp_driver	*drv;	int			one_again, one_match;	int			count = 0;	DBG(("ocp: binding drivers...\n"));	do {		/* We re-do the match loop if we had a sucess match and got one -EAGAIN		 */		one_match = one_again = 0;		down_read(&ocp_devices_sem);		list_for_each(deventry, &ocp_devices) {			dev = list_entry(deventry, struct ocp_device, link);			if (dev->driver != NULL)				continue;			DBG(("ocp: device %s unmatched, trying to match...\n", dev->name));			list_for_each(drventry, &ocp_drivers) {				drv = list_entry(drventry, struct ocp_driver, link);				if (ocp_driver_match(drv, dev)) {					int rc;					/* Hrm... shall we set dev->driver after or before ? */					DBG(("ocp: match with driver %s, calling probe...\n", drv->name));					rc = drv->probe(dev);					DBG(("ocp: probe result: %d\n", rc));					if (rc == 0) {						/* Driver matched, next device */						dev->driver = drv;						one_match = 1;						if (drv == candidate)							count++;						break;					} else if (rc == -EAGAIN) {						/* Driver matched but asked for later call, next device */						one_again = 1;						if (drv == candidate)							count++;						break;					}				}			}		}		up_read(&ocp_devices_sem);	} while(one_match && one_again);	DBG(("ocp: binding drivers... done.\n"));	return count;}/** *	ocp_register_driver	-	Register an OCP driver *	@drv: pointer to statically defined ocp_driver structure * *	The driver's probe() callback is called either recursively *	by this function or upon later call of ocp_driver_init * *      NOTE: Probe is called with ocp_drivers_sem held, it shouldn't *      call ocp_register/unregister_driver on his own code path. *      however, it _can_ call ocp_find_device(). * *	NOTE2: Detection of devices is a 2 pass step on this implementation, *	hotswap isn't supported. First, all OCP devices are put in the device *	list, _then_ all drivers are probed on each match. * *      NOTE3: Drivers are allowed to return -EAGAIN from the probe() routine. *      this will cause them to be called again for this specific device as *	soon as another device have been probed or another driver registered. *	this, gives a simple way for a driver like EMAC to wait for another driver, *	like MAL to be up. There is potentially a small race if MAL happens to *	unregister, but this is hopefully never happening. * *	This function returns a count of how many devices actually matched *	(wether the probe routine returned 0 or -EAGAIN, a different error *	code isn't considered as a match). */intocp_register_driver(struct ocp_driver *drv){	int	rc = 0;	DBG(("ocp: ocp_register_driver(%s)...\n", drv->name));	/* Add to driver list */	down(&ocp_drivers_sem);	list_add_tail(&drv->link, &ocp_drivers);	/* Check matching devices */	rc = ocp_bind_drivers(drv);	up(&ocp_drivers_sem);	DBG(("ocp: ocp_register_driver(%s)... done, count: %d.\n", drv->name, rc));	return rc;}/** *	ocp_unregister_driver	-	Unregister an OCP driver *	@drv: pointer to statically defined ocp_driver structure * *	The driver's remove() callback is called recursively *	by this function for any device already registered */voidocp_unregister_driver(struct ocp_driver *drv){	struct ocp_device	*dev;	struct list_head	*entry;	DBG(("ocp: ocp_unregister_driver(%s)...\n", drv->name));	/* Call remove() routine for all devices using it */	down(&ocp_drivers_sem);	down_read(&ocp_devices_sem);	list_for_each(entry, &ocp_devices) {		dev = list_entry(entry, struct ocp_device, link);		if (dev->driver == drv) {			drv->remove(dev);			dev->driver = NULL;			dev->drvdata = NULL;		}	}	up_read(&ocp_devices_sem);	/* Unlink driver structure */	list_del_init(&drv->link);	up(&ocp_drivers_sem);	DBG(("ocp: ocp_unregister_driver(%s)... done.\n", drv->name));}/* Core of ocp_find_device(). Caller must hold ocp_devices_sem */static struct ocp_device *__ocp_find_device(unsigned int vendor, unsigned int function, int index){	struct list_head	*entry;	struct ocp_device	*dev, *found = NULL;	DBG(("ocp: __ocp_find_device(vendor: %x, function: %x, index: %d)...\n", vendor, function, index));	list_for_each(entry, &ocp_devices) {		dev = list_entry(entry, struct ocp_device, link);		if (vendor != OCP_ANY_ID && vendor != dev->def->vendor)			continue;		if (function != OCP_ANY_ID && function != dev->def->function)			continue;		if (index != OCP_ANY_INDEX && index != dev->def->index)			continue;		found = dev;		break;	}	DBG(("ocp: __ocp_find_device(vendor: %x, function: %x, index: %d)... done\n", vendor, function, index));	return found;}/** *	ocp_find_device	-	Find a device by function & index *      @vendor: vendor ID of the device (or OCP_ANY_ID) *	@function: function code of the device (or OCP_ANY_ID) *	@idx: index of the device (or OCP_ANY_INDEX) * *	This function allows a lookup of a given function by it's *	index, it's typically used to find the MAL or ZMII associated *	with an EMAC or similar horrors. *      You can pass vendor, though you usually want OCP_ANY_ID there... */struct ocp_device *ocp_find_device(unsigned int vendor, unsigned int function, int index){	struct ocp_device	*dev;	down_read(&ocp_devices_sem);	dev = __ocp_find_device(vendor, function, index);

⌨️ 快捷键说明

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