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

📄 pci.c

📁 IXP425 平台下嵌入式LINUX的PCI总线的驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
int pci_request_regions(struct pci_dev *pdev, char *res_name){	int i;		for (i = 0; i < 6; i++) {		if (pci_resource_len(pdev, i) == 0)			continue;		if (pci_resource_flags(pdev, i) & IORESOURCE_IO) {			if (!request_region(pci_resource_start(pdev, i),					    pci_resource_len(pdev, i), res_name))				goto err_out;		}				else if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) {			if (!request_mem_region(pci_resource_start(pdev, i),					        pci_resource_len(pdev, i), res_name))				goto err_out;		}	}		return 0;err_out:	printk (KERN_WARNING "PCI: Unable to reserve %s region #%d:%lx@%lx for device %s\n",		pci_resource_flags(pdev, i) & IORESOURCE_IO ? "I/O" : "mem",		i + 1, /* PCI BAR # */		pci_resource_len(pdev, i), pci_resource_start(pdev, i),		pdev->slot_name);	pci_release_regions(pdev);	return -EBUSY;}/* *  Registration of PCI drivers and handling of hot-pluggable devices. */static LIST_HEAD(pci_drivers);/** * pci_match_device - Tell if a PCI device structure has a matching PCI device id structure * @ids: array of PCI device id structures to search in * @dev: the PCI device structure to match against *  * Used by a driver to check whether a PCI device present in the * system is in its list of supported devices.Returns the matching * pci_device_id structure or %NULL if there is no match. */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;}/** * pci_register_driver - register a new pci driver * @drv: the driver structure to register *  * Adds the driver structure to the list of registered drivers * Returns the number of pci devices which were claimed by the driver * during registration.  The driver remains registered even if the * return value is zero. */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;}/** * pci_unregister_driver - unregister a pci driver * @drv: the driver structure to unregister *  * Deletes the driver structure from the list of registered PCI drivers, * gives it a chance to clean up by calling its remove() function for * each device it was responsible for, and marks those devices as * driverless. */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);}/** * pci_announce_device_to_drivers - tell the drivers a new device has appeared * @dev: the device that has shown up * * Notifys the drivers that a new device has appeared, and also notifys * userspace through /sbin/hotplug. */voidpci_announce_device_to_drivers(struct pci_dev *dev){	struct list_head *ln;	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;	}	/* notify userspace of new hotplug device */	run_sbin_hotplug(dev, TRUE);}/** * pci_insert_device - insert a hotplug device * @dev: the device to insert * @bus: where to insert it * * Add a new device to the device lists and notify userspace (/sbin/hotplug). */voidpci_insert_device(struct pci_dev *dev, struct pci_bus *bus){	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	pci_announce_device_to_drivers(dev);}static voidpci_free_resources(struct pci_dev *dev){	int i;	for (i = 0; i < PCI_NUM_RESOURCES; i++) {		struct resource *res = dev->resource + i;		if (res->parent)			release_resource(res);	}}/** * pci_remove_device - remove a hotplug device * @dev: the device to remove * * Delete the device structure from the device lists and  * notify userspace (/sbin/hotplug). */voidpci_remove_device(struct pci_dev *dev){	if (dev->driver) {		if (dev->driver->remove)			dev->driver->remove(dev);		dev->driver = NULL;	}	list_del(&dev->bus_list);	list_del(&dev->global_list);	pci_free_resources(dev);#ifdef CONFIG_PROC_FS	pci_proc_detach_device(dev);#endif	/* notify userspace of hotplug device removal */	run_sbin_hotplug(dev, FALSE);}#endifstatic struct pci_driver pci_compat_driver = {	name: "compat"};/** * pci_dev_driver - get the pci_driver of a device * @dev: the device to query * * Returns the appropriate pci_driver structure or %NULL if there is no  * registered driver for the device. */struct pci_driver *pci_dev_driver(const struct pci_dev *dev){	if (dev->driver)		return dev->driver;	else {		int i;		for(i=0; i<=PCI_ROM_RESOURCE; i++)			if (dev->resource[i].flags & IORESOURCE_BUSY)				return &pci_compat_driver;	}	return NULL;}/* * This interrupt-safe spinlock protects all accesses to PCI * configuration space. */static spinlock_t pci_lock = SPIN_LOCK_UNLOCKED;/* *  Wrappers for all PCI configuration access functions.  They just check *  alignment, do locking and call the low-level functions pointed to *  by pci_dev->ops. */#define PCI_byte_BAD 0#define PCI_word_BAD (pos & 1)#define PCI_dword_BAD (pos & 3)#define PCI_OP(rw,size,type) \int pci_##rw##_config_##size (struct pci_dev *dev, int pos, type value) \{									\	int res;							\	unsigned long flags;						\	if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER;	\	spin_lock_irqsave(&pci_lock, flags);				\	res = dev->bus->ops->rw##_##size(dev, pos, value);		\	spin_unlock_irqrestore(&pci_lock, flags);			\	return res;							\}PCI_OP(read, byte, u8 *)PCI_OP(read, word, u16 *)PCI_OP(read, dword, u32 *)PCI_OP(write, byte, u8)PCI_OP(write, word, u16)PCI_OP(write, dword, u32)/** * pci_set_master - enables bus-mastering for device dev * @dev: the PCI device to enable * * Enables bus-mastering on the device and calls pcibios_set_master() * to do the needed arch specific settings. */voidpci_set_master(struct pci_dev *dev){	u16 cmd;	pci_read_config_word(dev, PCI_COMMAND, &cmd);	if (! (cmd & PCI_COMMAND_MASTER)) {		DBG("PCI: Enabling bus mastering for device %s\n", dev->slot_name);		cmd |= PCI_COMMAND_MASTER;		pci_write_config_word(dev, PCI_COMMAND, cmd);	}	pcibios_set_master(dev);}/** * pdev_set_mwi - arch helper function for pcibios_set_mwi * @dev: the PCI device for which MWI is enabled * * Helper function for implementation the arch-specific pcibios_set_mwi * function.  Originally copied from drivers/net/acenic.c. * Copyright 1998-2001 by Jes Sorensen, <jes@trained-monkey.org>. * * RETURNS: An appriopriate -ERRNO error value on eror, or zero for success. */intpdev_set_mwi(struct pci_dev *dev){	int rc = 0;	u8 cache_size;	/*	 * Looks like this is necessary to deal with on all architectures,	 * even this %$#%$# N440BX Intel based thing doesn't get it right.	 * Ie. having two NICs in the machine, one will have the cache	 * line set at boot time, the other will not.	 */	pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &cache_size);	cache_size <<= 2;	if (cache_size != SMP_CACHE_BYTES) {		printk(KERN_WARNING "PCI: %s PCI cache line size set incorrectly "		       "(%i bytes) by BIOS/FW, ",		       dev->slot_name, cache_size);		if (cache_size > SMP_CACHE_BYTES) {			printk("expecting %i\n", SMP_CACHE_BYTES);			rc = -EINVAL;		} else {			printk("correcting to %i\n", SMP_CACHE_BYTES);			pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,					      SMP_CACHE_BYTES >> 2);		}	}	return rc;}/** * pci_set_mwi - enables memory-write-invalidate PCI transaction * @dev: the PCI device for which MWI is enabled * * Enables the Memory-Write-Invalidate transaction in %PCI_COMMAND, * and then calls @pcibios_set_mwi to do the needed arch specific * operations or a generic mwi-prep function. * * RETURNS: An appriopriate -ERRNO error value on eror, or zero for success. */intpci_set_mwi(struct pci_dev *dev){	int rc;	u16 cmd;#ifdef HAVE_ARCH_PCI_MWI	rc = pcibios_set_mwi(dev);#else	rc = pdev_set_mwi(dev);#endif	if (rc)		return rc;	pci_read_config_word(dev, PCI_COMMAND, &cmd);	if (! (cmd & PCI_COMMAND_INVALIDATE)) {		DBG("PCI: Enabling Mem-Wr-Inval for device %s\n", dev->slot_name);		cmd |= PCI_COMMAND_INVALIDATE;		pci_write_config_word(dev, PCI_COMMAND, cmd);	}		return 0;}/** * pci_clear_mwi - disables Memory-Write-Invalidate for device dev * @dev: the PCI device to disable * * Disables PCI Memory-Write-Invalidate transaction on the device */voidpci_clear_mwi(struct pci_dev *dev){	u16 cmd;	pci_read_config_word(dev, PCI_COMMAND, &cmd);	if (cmd & PCI_COMMAND_INVALIDATE) {		cmd &= ~PCI_COMMAND_INVALIDATE;		pci_write_config_word(dev, PCI_COMMAND, cmd);	}}intpci_set_dma_mask(struct pci_dev *dev, u64 mask){	if (!pci_dma_supported(dev, mask))		return -EIO;	dev->dma_mask = mask;	return 0;}    intpci_dac_set_dma_mask(struct pci_dev *dev, u64 mask){	if (!pci_dac_dma_supported(dev, mask))		return -EIO;	dev->dma_mask = mask;	return 0;}    /* * Translate the low bits of the PCI base * to the resource type */static inline unsigned int pci_calc_resource_flags(unsigned int flags){	if (flags & PCI_BASE_ADDRESS_SPACE_IO)		return IORESOURCE_IO;	if (flags & PCI_BASE_ADDRESS_MEM_PREFETCH)		return IORESOURCE_MEM | IORESOURCE_PREFETCH;	return IORESOURCE_MEM;}/* * Find the extent of a PCI decode.. */static u32 pci_size(u32 base, unsigned long mask){	u32 size = mask & base;		/* Find the significant bits */	size = size & ~(size-1);	/* Get the lowest of them to find the decode size */	return size-1;			/* extent = size - 1 */}static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom){	unsigned int pos, reg, next;	u32 l, sz;	struct resource *res;	for(pos=0; pos<howmany; pos = next) {		next = pos+1;		res = &dev->resource[pos];		res->name = dev->name;		reg = PCI_BASE_ADDRESS_0 + (pos << 2);		pci_read_config_dword(dev, reg, &l);		pci_write_config_dword(dev, reg, ~0);		pci_read_config_dword(dev, reg, &sz);		pci_write_config_dword(dev, reg, l);		if (!sz || sz == 0xffffffff)			continue;		if (l == 0xffffffff)			l = 0;		if ((l & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) {			res->start = l & PCI_BASE_ADDRESS_MEM_MASK;			res->flags |= l & ~PCI_BASE_ADDRESS_MEM_MASK;			sz = pci_size(sz, PCI_BASE_ADDRESS_MEM_MASK);		} else {			res->start = l & PCI_BASE_ADDRESS_IO_MASK;			res->flags |= l & ~PCI_BASE_ADDRESS_IO_MASK;			sz = pci_size(sz, PCI_BASE_ADDRESS_IO_MASK & 0xffff);		}		res->end = res->start + (unsigned long) sz;		res->flags |= pci_calc_resource_flags(l);		if ((l & (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK))		    == (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64)) {			pci_read_config_dword(dev, reg+4, &l);			next++;#if BITS_PER_LONG == 64			res->start |= ((unsigned long) l) << 32;			res->end = res->start + sz;			pci_write_config_dword(dev, reg+4, ~0);			pci_read_config_dword(dev, reg+4, &sz);			pci_write_config_dword(dev, reg+4, l);			if (~sz)				res->end = res->start + 0xffffffff +						(((unsigned long) ~sz) << 32);#else			if (l) {				printk(KERN_ERR "PCI: Unable to handle 64-bit address for device %s\n", dev->slot_name);				res->start = 0;				res->flags = 0;				continue;			}#endif		}	}	if (rom) {		dev->rom_base_reg = rom;		res = &dev->resource[PCI_ROM_RESOURCE];		pci_read_config_dword(dev, rom, &l);		pci_write_config_dword(dev, rom, ~PCI_ROM_ADDRESS_ENABLE);

⌨️ 快捷键说明

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