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

📄 pci.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *	$Id: pci.c,v 1.91 1999/01/21 13:34:01 davem Exp $ * *	PCI Bus Services, see include/linux/pci.h for further explanation. * *	Copyright 1993 -- 1997 Drew Eckhardt, Frederic Potter, *	David Mosberger-Tang * *	Copyright 1997 -- 2000 Martin Mares <mj@suse.cz> */#include <linux/config.h>#include <linux/module.h>#include <linux/types.h>#include <linux/kernel.h>#include <linux/pci.h>#include <linux/string.h>#include <linux/init.h>#include <linux/malloc.h>#include <linux/ioport.h>#include <linux/spinlock.h>#include <linux/pm.h>#include <linux/slab.h>#include <linux/kmod.h>		/* for hotplug_path */#include <asm/page.h>#include <asm/dma.h>	/* isa_dma_bridge_buggy */#undef DEBUG#ifdef DEBUG#define DBG(x...) printk(x)#else#define DBG(x...)#endifLIST_HEAD(pci_root_buses);LIST_HEAD(pci_devices);/** * pci_find_slot - locate PCI device from a given PCI slot * @bus: number of PCI bus on which desired PCI device resides * @devfn:  number of PCI slot in which desired PCI device resides * * Given a PCI bus and slot number, the desired PCI device is * located in system global list of PCI devices.  If the device * is found, a pointer to its data structure is returned.  If no  * device is found, %NULL is returned. */struct pci_dev *pci_find_slot(unsigned int bus, unsigned int devfn){	struct pci_dev *dev;	pci_for_each_dev(dev) {		if (dev->bus->number == bus && dev->devfn == devfn)			return dev;	}	return NULL;}struct pci_dev *pci_find_subsys(unsigned int vendor, unsigned int device,		unsigned int ss_vendor, unsigned int ss_device,		const struct pci_dev *from){	struct list_head *n = from ? from->global_list.next : pci_devices.next;	while (n != &pci_devices) {		struct pci_dev *dev = pci_dev_g(n);		if ((vendor == PCI_ANY_ID || dev->vendor == vendor) &&		    (device == PCI_ANY_ID || dev->device == device) &&		    (ss_vendor == PCI_ANY_ID || dev->subsystem_vendor == ss_vendor) &&		    (ss_device == PCI_ANY_ID || dev->subsystem_device == ss_device))			return dev;		n = n->next;	}	return NULL;}/** * pci_find_device - begin or continue searching for a PCI device by vendor/device id * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids * @device: PCI device id to match, or %PCI_ANY_ID to match all vendor ids * @from: Previous PCI device found in search, or %NULL for new search. * * Iterates through the list of known PCI devices.  If a PCI device is * found with a matching @vendor and @device, a pointer to its device structure is * returned.  Otherwise, %NULL is returned. * * A new search is initiated by passing %NULL to the @from argument. * Otherwise if @from is not null, searches continue from that point. */struct pci_dev *pci_find_device(unsigned int vendor, unsigned int device, const struct pci_dev *from){	return pci_find_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from);}/** * pci_find_class - begin or continue searching for a PCI device by class * @class: search for a PCI device with this class designation * @from: Previous PCI device found in search, or %NULL for new search. * * Iterates through the list of known PCI devices.  If a PCI device is * found with a matching @class, a pointer to its device structure is * returned.  Otherwise, %NULL is returned. * * A new search is initiated by passing %NULL to the @from argument. * Otherwise if @from is not null, searches continue from that point. */struct pci_dev *pci_find_class(unsigned int class, const struct pci_dev *from){	struct list_head *n = from ? from->global_list.next : pci_devices.next;	while (n != &pci_devices) {		struct pci_dev *dev = pci_dev_g(n);		if (dev->class == class)			return dev;		n = n->next;	}	return NULL;}intpci_find_capability(struct pci_dev *dev, int cap){	u16 status;	u8 pos, id;	int ttl = 48;	pci_read_config_word(dev, PCI_STATUS, &status);	if (!(status & PCI_STATUS_CAP_LIST))		return 0;	switch (dev->hdr_type) {	case PCI_HEADER_TYPE_NORMAL:	case PCI_HEADER_TYPE_BRIDGE:		pci_read_config_byte(dev, PCI_CAPABILITY_LIST, &pos);		break;	case PCI_HEADER_TYPE_CARDBUS:		pci_read_config_byte(dev, PCI_CB_CAPABILITY_LIST, &pos);		break;	default:		return 0;	}	while (ttl-- && pos >= 0x40) {		pos &= ~3;		pci_read_config_byte(dev, pos + PCI_CAP_LIST_ID, &id);		if (id == 0xff)			break;		if (id == cap)			return pos;		pci_read_config_byte(dev, pos + PCI_CAP_LIST_NEXT, &pos);	}	return 0;}/** * pci_find_parent_resource - return resource region of parent bus of given region * @dev: PCI device structure contains resources to be searched * @res: child resource record for which parent is sought * *  For given resource region of given device, return the resource *  region of parent bus the given region is contained in or where *  it should be allocated from. */struct resource *pci_find_parent_resource(const struct pci_dev *dev, struct resource *res){	const struct pci_bus *bus = dev->bus;	int i;	struct resource *best = NULL;	for(i=0; i<4; i++) {		struct resource *r = bus->resource[i];		if (!r)			continue;		if (res->start && !(res->start >= r->start && res->end <= r->end))			continue;	/* Not contained */		if ((res->flags ^ r->flags) & (IORESOURCE_IO | IORESOURCE_MEM))			continue;	/* Wrong type */		if (!((res->flags ^ r->flags) & IORESOURCE_PREFETCH))			return r;	/* Exact match */		if ((res->flags & IORESOURCE_PREFETCH) && !(r->flags & IORESOURCE_PREFETCH))			best = r;	/* Approximating prefetchable by non-prefetchable */	}	return best;}/** * pci_set_power_state - Set power management state of a device. * @dev: PCI device for which PM is set * @new_state: new power management statement (0 == D0, 3 == D3, etc.) * *  Set power management state of a device.  For transitions from state D3 *  it isn't as straightforward as one could assume since many devices forget *  their configuration space during wakeup.  Returns old power state. */intpci_set_power_state(struct pci_dev *dev, int new_state){	u32 base[5], romaddr;	u16 pci_command, pwr_command;	u8  pci_latency, pci_cacheline;	int i, old_state;	int pm = pci_find_capability(dev, PCI_CAP_ID_PM);	if (!pm)		return 0;	pci_read_config_word(dev, pm + PCI_PM_CTRL, &pwr_command);	old_state = pwr_command & PCI_PM_CTRL_STATE_MASK;	if (old_state == new_state)		return old_state;	DBG("PCI: %s goes from D%d to D%d\n", dev->slot_name, old_state, new_state);	if (old_state == 3) {		pci_read_config_word(dev, PCI_COMMAND, &pci_command);		pci_write_config_word(dev, PCI_COMMAND, pci_command & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY));		for (i = 0; i < 5; i++)			pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + i*4, &base[i]);		pci_read_config_dword(dev, PCI_ROM_ADDRESS, &romaddr);		pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency);		pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &pci_cacheline);		pci_write_config_word(dev, pm + PCI_PM_CTRL, new_state);		for (i = 0; i < 5; i++)			pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + i*4, base[i]);		pci_write_config_dword(dev, PCI_ROM_ADDRESS, romaddr);		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);		pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, pci_cacheline);		pci_write_config_byte(dev, PCI_LATENCY_TIMER, pci_latency);		pci_write_config_word(dev, PCI_COMMAND, pci_command);	} else		pci_write_config_word(dev, pm + PCI_PM_CTRL, (pwr_command & ~PCI_PM_CTRL_STATE_MASK) | new_state);	return old_state;}/** * pci_enable_device - Initialize device before it's used by a driver. * @dev: PCI device to be initialized * *  Initialize device before it's used by a driver. Ask low-level code *  to enable I/O and memory. Wake up the device if it was suspended. *  Beware, this function can fail. */intpci_enable_device(struct pci_dev *dev){	int err;	if ((err = pcibios_enable_device(dev)) < 0)		return err;	pci_set_power_state(dev, 0);	return 0;}intpci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge){	u8 pin;	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);	if (!pin)		return -1;	pin--;	while (dev->bus->self) {		pin = (pin + PCI_SLOT(dev->devfn)) % 4;		dev = dev->bus->self;	}	*bridge = dev;	return pin;}/* *  Registration of PCI drivers and handling of hot-pluggable devices. */static LIST_HEAD(pci_drivers);const struct pci_device_id *pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev){	while (ids->vendor || ids->subvendor || ids->class_mask) {		if ((ids->vendor == PCI_ANY_ID || ids->vendor == dev->vendor) &&		    (ids->device == PCI_ANY_ID || ids->device == dev->device) &&		    (ids->subvendor == PCI_ANY_ID || ids->subvendor == dev->subsystem_vendor) &&		    (ids->subdevice == PCI_ANY_ID || ids->subdevice == dev->subsystem_device) &&		    !((ids->class ^ dev->class) & ids->class_mask))			return ids;		ids++;	}	return NULL;}static intpci_announce_device(struct pci_driver *drv, struct pci_dev *dev){	const struct pci_device_id *id;	int ret = 0;	if (drv->id_table) {		id = pci_match_device(drv->id_table, dev);		if (!id) {			ret = 0;			goto out;		}	} else		id = NULL;	dev_probe_lock();	if (drv->probe(dev, id) >= 0) {		dev->driver = drv;		ret = 1;	}	dev_probe_unlock();out:	return ret;}intpci_register_driver(struct pci_driver *drv){	struct pci_dev *dev;	int count = 0;	list_add_tail(&drv->node, &pci_drivers);	pci_for_each_dev(dev) {		if (!pci_dev_driver(dev))			count += pci_announce_device(drv, dev);	}	return count;}voidpci_unregister_driver(struct pci_driver *drv){	struct pci_dev *dev;	list_del(&drv->node);	pci_for_each_dev(dev) {		if (dev->driver == drv) {			if (drv->remove)				drv->remove(dev);			dev->driver = NULL;		}	}}#ifdef CONFIG_HOTPLUG#ifndef FALSE#define FALSE	(0)#define TRUE	(!FALSE)#endifstatic voidrun_sbin_hotplug(struct pci_dev *pdev, int insert){	int i;	char *argv[3], *envp[8];	char id[20], sub_id[24], bus_id[24], class_id[20];	if (!hotplug_path[0])		return;	sprintf(class_id, "PCI_CLASS=%04X", pdev->class);	sprintf(id, "PCI_ID=%04X:%04X", pdev->vendor, pdev->device);	sprintf(sub_id, "PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor, pdev->subsystem_device);	sprintf(bus_id, "PCI_SLOT_NAME=%s", pdev->slot_name);	i = 0;	argv[i++] = hotplug_path;	argv[i++] = "pci";	argv[i] = 0;	i = 0;	/* minimal command environment */	envp[i++] = "HOME=/";	envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";		/* other stuff we want to pass to /sbin/hotplug */	envp[i++] = class_id;	envp[i++] = id;	envp[i++] = sub_id;	envp[i++] = bus_id;	if (insert)		envp[i++] = "ACTION=add";	else		envp[i++] = "ACTION=remove";	envp[i] = 0;	call_usermodehelper (argv [0], argv, envp);}voidpci_insert_device(struct pci_dev *dev, struct pci_bus *bus){	struct list_head *ln;	list_add_tail(&dev->bus_list, &bus->devices);	list_add_tail(&dev->global_list, &pci_devices);#ifdef CONFIG_PROC_FS	pci_proc_attach_device(dev);#endif	for(ln=pci_drivers.next; ln != &pci_drivers; ln=ln->next) {		struct pci_driver *drv = list_entry(ln, struct pci_driver, node);		if (drv->remove && pci_announce_device(drv, dev))			break;	}

⌨️ 快捷键说明

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