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

📄 pci.c

📁 DOS_PCI_DRIVER,DOS环境下运行的PCI驱动程序,个人觉得比较好用.
💻 C
📖 第 1 页 / 共 5 页
字号:
			new->parent = root;
			return NULL;
		}

		p = &tmp->sibling;
		if (tmp->end < start)
			continue;
		return tmp;
	}
}

struct resource far * request_resource(struct resource far * root, 
	struct resource far * new)
{
	struct resource far * tmp;

	local_irq_save(0);

	tmp = __request_resource(root,new);

	local_irq_restore(0);

	return tmp;
}

long __release_resource(struct resource far * old)
{
	struct resource far *tmp;
	struct resource far **p;

	p = &old->parent->child;
	for (;;) 
	{
		tmp = *p;
		if (!tmp)
			break;
		if (tmp == old) 
		{
			*p = tmp->sibling;
			old->parent = NULL;
			return 0;
		}

		p = &tmp->sibling;
	}

	return -EINVAL;
}

long release_resource(struct resource far * old)
{
	long tmp;

	local_irq_save(0);

	tmp = __release_resource(old);

	local_irq_restore(0);

	return tmp;
}

/*
 *  Handle resources of PCI devices.  If the world were perfect, we could
 *  just allocate all the resource regions and do nothing more.  It isn't.
 *  On the other hand, we cannot just re-allocate all devices, as it would
 *  require us to know lots of host bridge internals.  So we attempt to
 *  keep as much of the original configuration as possible, but tweak it
 *  when it's found to be wrong.
 *
 *  Known BIOS problems we have to work around:
 *	- I/O or memory regions not configured
 *	- regions configured, but not enabled in the command register
 *	- bogus I/O addresses above 64K used
 *	- expansion ROMs left enabled (this may sound harmless, but given
 *	  the fact the PCI specs explicitly allow address decoders to be
 *	  shared between expansion ROMs and other resource regions, it's
 *	  at least dangerous)
 *
 *  Our solution:
 *	(1) Allocate resources for all buses behind PCI-to-PCI bridges.
 *	    This gives us fixed barriers on where we can allocate.
 *	(2) Allocate resources for all enabled devices.  If there is
 *	    a collision, just mark the resource as unallocated. Also
 *	    disable expansion ROMs during this step.
 *	(3) Try to allocate resources for disabled devices.  If the
 *	    resources were assigned correctly, everything goes well,
 *	    if they weren't, they won't disturb allocation of other
 *	    resources.
 *	(4) Assign new addresses to resources which were either
 *	    not configured at all or misconfigured.  If explicitly
 *	    requested by the user, configure expansion ROM address
 *	    as well.
 */

void pcibios_allocate_bus_resources(struct list_head *bus_list)
{
	struct list_head far * ln;
	struct pci_bus far * bus;
	struct pci_dev far * dev;
	int idx;
	struct resource far * r;
	struct resource far * pr;

	/* Depth-First Search on bus tree */
	for (ln=bus_list->next; ln != bus_list; ln=ln->next) {
		bus = pci_bus_b(ln);

		if ((dev = bus->self)) 
		{
			for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) 
			{
				r = &dev->resource[idx];
				if (!r->start)
					continue;
				pr = pci_find_parent_resource(dev, r);
				if (!pr || request_resource(pr, r) < 0)
				{
					#ifdef DEBUG_VERSION
						safe_printf("PCI: Cannot allocate resource region %d of bridge %s\n", 
							idx, dev->slot_name);
					#endif
					r->start = 0L;
					r->end = 0L;
				}
			}
		}

		pcibios_allocate_bus_resources(&bus->children);
	}
}

void pcibios_allocate_resources(long pass)
{
	struct pci_dev far * dev;
	long idx, disabled;
	u16 command;
	struct resource far * r;
	struct resource far * pr;

	pci_for_each_dev(dev) 
	{
		pci_read_config_word(dev, PCI_COMMAND, &command);
		for(idx = 0; idx < 6; idx++) 
		{
			r = &dev->resource[idx];
			if (r->parent)		/* Already allocated */
				continue;
			if (!r->start)		/* Address not assigned at all */
				continue;
			if (r->flags & IORESOURCE_IO)
				disabled = !(command & PCI_COMMAND_IO);
			else
				disabled = !(command & PCI_COMMAND_MEMORY);

			if (pass == disabled) 
			{
				#ifdef DEBUG_VERSION
					safe_printf("PCI: Resource %08lx-%08lx (f=%lx, d=%d, p=%d)\n",
						r->start, r->end, r->flags, disabled, pass);
				#endif

				pr = pci_find_parent_resource(dev, r);
				if (!pr || request_resource(pr, r) < 0) 
				{
					#ifdef DEBUG_VERSION
						safe_printf("PCI: Cannot allocate resource region %d of device %s\n", (unsigned short)idx,
							   dev->slot_name);
					#endif
					/* We'll assign a new address later */
					r->end -= r->start;
					r->start = 0;
				}
			}
		}

		if (!pass) 
		{
			r = &dev->resource[PCI_ROM_RESOURCE];
			if (r->flags & PCI_ROM_ADDRESS_ENABLE) 
			{
				/* Turn the ROM off, leave the resource region, but keep it unregistered. */
				u32 reg;

				#ifdef DEBUG_VERSION
					safe_printf("PCI: Switching off ROM of %s\n", dev->slot_name);
				#endif

				r->flags &= ~PCI_ROM_ADDRESS_ENABLE;
				pci_read_config_dword(dev, dev->rom_base_reg, &reg);
				pci_write_config_dword(dev, dev->rom_base_reg, 
					reg & ~PCI_ROM_ADDRESS_ENABLE);
			}
		}
	}
}

/*
 * Find empty slot in the resource tree given range and alignment.
 */
long find_resource(struct resource far * root, struct resource far * new,
			 unsigned long size,unsigned long min, unsigned long max,
			 unsigned long align,
			 void (*alignf)(void far *, struct resource far *, unsigned long),
			 void far * alignf_data)
{
	unsigned long temp;
	struct resource far * this = root->child;

	new->start = root->start;
	for(;;) 
	{
		if (this)
			new->end = this->start;
		else
			new->end = root->end;

		if (new->start < min)
			new->start = min;
		if (new->end > max)
			new->end = max;

		new->start = (new->start + align - 1) & ~(align - 1);
		if (alignf)
			alignf(alignf_data, new, size);

		if (new->start < new->end && new->end - new->start + 1 >= size) 
		{
			temp = new->end;

			new->end = new->start + size - 1;

			return 0;
		}

		if (!this)
			break;

		new->start = this->end + 1;
		this = this->sibling;
	}

	return -EBUSY;
}

/*
 * Allocate empty slot in the resource tree given range and alignment.
 */
long allocate_resource(struct resource far * root, struct resource far * new,
		      unsigned long size,unsigned long min, unsigned long max,
		      unsigned long align,
			  void (*alignf)(void *, struct resource *, unsigned long),
		      void far * alignf_data)
{
	long err;

	local_irq_save(0);

	err = find_resource(root, new, size, min, max, align, alignf, alignf_data);

	local_irq_restore(0);

	if (err >= 0 && request_resource(root, new))
		err = -EBUSY;

	return err;
}

void pcibios_update_resource(struct pci_dev far * dev, struct resource far * root,
			struct resource far * res, long resource)
{
	u32 new, check;
	long reg;

	new = res->start | (res->flags & PCI_REGION_FLAG_MASK);
	if (resource < 6) 
	{
		reg = PCI_BASE_ADDRESS_0 + 4 * resource;
	} 
	else if (resource == PCI_ROM_RESOURCE) 
	{
		res->flags |= PCI_ROM_ADDRESS_ENABLE;
		new |= PCI_ROM_ADDRESS_ENABLE;
		reg = dev->rom_base_reg;
	} 
	else 
	{
		/* Somebody might have asked allocation of a non-standard resource */
		return;
	}
	
	pci_write_config_dword(dev, reg, new);
	pci_read_config_dword(dev, reg, &check);
	if ((new ^ check) & ((new & PCI_BASE_ADDRESS_SPACE_IO) 
		? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK)) 
	{
		#ifdef DEBUG_VERSION
			safe_printf("PCI: Error (%08lx != %08lx) while updating region %s %d \n",
				 new,check,dev->slot_name,(unsigned short)resource);
		#endif
	}
}

/*
 * We need to avoid collisions with `mirrored' VGA ports
 * and other strange ISA hardware, so we always want the
 * addresses to be allocated in the 0x000-0x0ff region
 * modulo 0x400.
 *
 * Why? Because some silly external IO cards only decode
 * the low 10 bits of the IO address. The 0x00-0xff region
 * is reserved for motherboard devices that decode all 16
 * bits, so it's ok to allocate at, say, 0x2800-0x28ff,
 * but we want to try to avoid allocating at 0x2900-0x2bff
 * which might have be mirrored at 0x0100-0x03ff..
 */
void pcibios_align_resource(void far * data, struct resource far * res, 
	unsigned long size)
{
	if (res->flags & IORESOURCE_IO) 
	{
		unsigned long start = res->start;

		if (start & 0x300) 
		{
			start = (start + 0x3ff) & ~0x3ff;
			res->start = start;
		}
	}
}

/*
 * Given the PCI bus a device resides on, try to
 * find an acceptable resource allocation for a
 * specific device resource..
 */
long pci_assign_bus_resource(const struct pci_bus far * bus,struct pci_dev far * dev,
	struct resource far * res,unsigned long size,unsigned long min,
	unsigned long type_mask,long resno)
{
	long i;
	unsigned long j;

	type_mask |= IORESOURCE_IO | IORESOURCE_MEM;
	for (i = 0 ; i < 4; i++) 
	{
		struct resource *r = bus->resource[i];
		if (!r)
			continue;

		/* type_mask must match */
		if ((res->flags ^ r->flags) & type_mask)
			continue;

		/* We cannot allocate a non-prefetching resource from a pre-fetching area */
		if ((r->flags & IORESOURCE_PREFETCH) && !(res->flags & IORESOURCE_PREFETCH))
			continue;

		/* Ok, try it out.. */
		if (allocate_resource(r, res, size, min, -1, size, pcibios_align_resource, dev) 
			< 0)
			continue;

		/* Update PCI config space.  */
		pcibios_update_resource(dev, r, res, resno);

		return 0;
	}

	return -EBUSY;
}

long pci_assign_resource(struct pci_dev far * dev, long i)
{
	const struct pci_bus far * bus = dev->bus;
	struct resource far * res = dev->resource + i;
	unsigned long size, min;
	char far * name;

	size = res->end - res->start + 1;
	min = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM;

	/* First, try exact prefetching match.. */
	if (pci_assign_bus_resource(bus, dev, res, size, min, IORESOURCE_PREFETCH, i) < 0) 
	{
		/*
		 * That failed.
		 *
		 * But a prefetching area can handle a non-prefetching
		 * window (it will just not perform as well).
		 */
		if (!(res->flags & IORESOURCE_PREFETCH) || 
			pci_assign_bus_resource(bus, dev, res, size, min, 0, i) < 0) 
		{
			#ifdef DEBUG_VERSION
				safe_printf("PCI: Failed to allocate resource %d(%lx-%lx) for %s\n",
					(unsigned short)i, res->start, res->end, dev->slot_name);
			#endif
			return -EBUSY;
		}
	}

	name = (char far *)(&(dev->name));

	#ifdef DEBUG_VERSION
		safe_printf("  got res[%lx:%lx] for resource %d of %s\n", res->start,
						res->end, (unsigned short)i,
						name);
	#endif

	return 0;
}

void pcibios_assign_resources(void)
{
	struct pci_dev far * dev;
	long idx;
	struct resource far * r;

	pci_for_each_dev(dev) 
	{
		long class = dev->class >> 8;

		/* Don't touch classless devices and host bridges */
		if (!class || class == PCI_CLASS_BRIDGE_HOST)
			continue;

		for(idx=0; idx<6; idx++) 
		{
			r = &dev->resource[idx];

			/*
			 *  Don't touch IDE controllers and I/O ports of video cards!
			 */
			if ((class == PCI_CLASS_STORAGE_IDE && idx < 4) ||
			    (class == PCI_CLASS_DISPLAY_VGA && (r->flags & IORESOURCE_IO)))
				continue;

			/*
			 *  We shall assign a new address to this resource, either because
			 *  the BIOS forgot to do so or because we have decided the old
			 *  address was unusable for some reason.
			 */
			if (!r->start && r->end)
				pci_assign_resource(dev, idx);
		}

		if (pci_probe & PCI_ASSIGN_ROMS) 
		{
			r = &dev->resource[PCI_ROM_RESOURCE];
			r->end -= r->start;
			r->start = 0;
			if (r->end)
				pci_assign_resource(dev, PCI_ROM_RESOURCE);
		}
	}
}

void pcibios_resource_survey(void)
{
	#ifdef DEBUG_VERSION
		safe_printf("PCI: Allocating resources\n");
	#endif

	pcibios_allocate_bus_resources(&pci_root_buses);
	pcibios_allocate_resources(0);
	pcibios_allocate_resources(1);
	pcibios_assign_resources();
}

/*
 * Sort the device list according to PCI BIOS. Nasty hack, but since some
 * fool forgot to define the `correct' device order in the PCI BIOS specs
 * and we want to be (possibly bug-to-bug ;-]) compatible with older kernels
 * which used BIOS ordering, we are bound to do this...
 */

void pcibios_sort(void)
{
	LIST_HEAD(sorted_devices);

	struct list_head *ln;
	struct pci_dev far * dev;
	struct pci_dev far * d;
	long idx, found;
	unsigned char bus, devfn;

	#ifdef DEBUG_VERSION
		safe_printf("PCI: Sorting device list...\n");
	#endif

	while (!list_empty(&pci_devices)) 
	{
		ln = pci_devices.next;
		dev = pci_dev_g(ln);
		idx = found = 0;
		while (pci_bios_find_device(dev->vendor,dev->device,(unsigned short)idx,&bus,
			&devfn) == (long)SUCCESSFUL) 
		{
			idx++;
			for (ln= pci_devices.next; ln != &pci_devices; ln=ln->next) 
			{
				d = pci_dev_g(ln);
				if (d->bus->number == bus && d->devfn == devfn) 
				{

⌨️ 快捷键说明

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