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

📄 pci.c

📁 PCI总线在DOS操作系统下的驱动程序源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
}

struct pci_bus far * pci_add_new_bus(struct pci_bus far * parent, struct pci_dev far *dev, 
	long busnr)
{
	struct pci_bus far * child;
	int i;

	/*
	 * Allocate a new bus, and inherit stuff from the parent..
	 */
	child = pci_alloc_bus();

	list_add_tail(&child->node, &parent->children);
	child->self = dev;
	dev->subordinate = child;
	child->parent = parent;
	child->ops = parent->ops;
	child->sysdata = parent->sysdata;

	/*
	 * Set up the primary, secondary and subordinate
	 * bus numbers.
	 */
	child->number = child->secondary = busnr;
	child->primary = parent->secondary;
	child->subordinate = 0xff;

	/* Set up default resource pointers.. */
	for (i = 0; i < 4; i++)
		child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES + i];

	return child;
}

/*
 * If it's a bridge, configure it and scan the bus behind it.
 * For CardBus bridges, we don't scan behind as the devices will
 * be handled by the bridge driver itself.
 *
 * We need to process bridges in two passes -- first we scan those
 * already configured by the BIOS and after we are done with all of
 * them, we proceed to assigning numbers to the remaining buses in
 * order to avoid overlaps between old and new bus numbers.
 */
long pci_scan_bridge(struct pci_bus far * bus, struct pci_dev far * dev, long max, 
	long pass)
{
	unsigned long buses;
	unsigned short cr;
	struct pci_bus far * child;
	int is_cardbus = (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS);

	pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses);

	#ifdef DEBUG_VERSION
		safe_printf("Scanning behind PCI bridge %s, config %06x, pass %d\n", 
			dev->slot_name, buses & 0xffffff, pass);
	#endif		

	if ((buses & 0xffff00) && !pcibios_assign_all_busses()) 
	{
		/*
		 * Bus already configured by firmware, process it in the first
		 * pass and just note the configuration.
		 */
		if (pass)
			return max;
		child = pci_add_new_bus(bus, dev, 0);
		child->primary = buses & 0xFF;
		child->secondary = (buses >> 8) & 0xFF;
		child->subordinate = (buses >> 16) & 0xFF;
		child->number = child->secondary;
		if (!is_cardbus) 
		{
			unsigned long cmax = pci_do_scan_bus(child);
			if (cmax > max) 
				max = cmax;
		} 
		else 
		{
			unsigned long cmax = child->subordinate;
			if (cmax > max) 
				max = cmax;
		}
	} 
	else 
	{
		/*
		 * We need to assign a number to this bus which we always
		 * do in the second pass. We also keep all address decoders
		 * on the bridge disabled during scanning.  FIXME: Why?
		 */
		if (!pass)
			return max;
		pci_read_config_word(dev, PCI_COMMAND, &cr);
		pci_write_config_word(dev, PCI_COMMAND, 0x0000);
		pci_write_config_word(dev, PCI_STATUS, 0xffff);

		child = pci_add_new_bus(bus, dev, ++max);
		buses = (buses & 0xff000000L)
		      | ((unsigned long)(child->primary))
		      | ((unsigned long)(child->secondary) * 256L)
		      | ((unsigned long)(child->subordinate) * 65536L);
		/*
		 * We need to blast all three values with a single write.
		 */
		pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses);
		if (!is_cardbus) 
		{
			/* Now we can scan all subordinate buses... */
			max = pci_do_scan_bus(child);
		} 
		else 
		{
			/*
			 * For CardBus bridges, we leave 4 bus numbers
			 * as cards with a PCI-to-PCI bridge can be
			 * inserted later.
			 */
			max += 3;
		}

		/*
		 * Set the subordinate bus number to its real value.
		 */
		child->subordinate = max;
		pci_write_config_byte(dev,PCI_SUBORDINATE_BUS,(u8)max);
		pci_write_config_word(dev,PCI_COMMAND,cr);
	}

	sprintf(child->name, (is_cardbus ? "PCI CardBus #%02x" : "PCI Bus #%02x"), 
		child->number);

	return max;
}

unsigned long pci_do_scan_bus(struct pci_bus far *bus)
{
	unsigned long devfn, max, pass;
	struct list_head *ln;
	struct pci_dev far * dev;
	struct pci_dev dev0;

	#ifdef DEBUG_VERSION
		safe_printf("Scanning bus %02x\n", bus->number);
	#endif

	max = bus->secondary;

	/* Create a device template */
	memset(&dev0, 0, sizeof(struct pci_dev));
	dev0.bus = bus;
	dev0.sysdata = bus->sysdata;

	/* Go find them, Rover! */
	for (devfn = 0; devfn < 0x100; devfn += 8) 
	{
		dev0.devfn = devfn;
		pci_scan_slot(&dev0);
	}

	/*
	 * After performing arch-dependent fixup of the bus, look behind
	 * all PCI-to-PCI bridges on this bus.
	 */
	#ifdef DEBUG_VERSION
		safe_printf("Fixups for bus %02x\n", bus->number);
	#endif

	pcibios_fixup_bus(bus);
	for (pass=0; pass < 2; pass++)
		for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) 
	{
			dev = pci_dev_b(ln);
			if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE 
				|| dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
				max = pci_scan_bridge(bus, dev, max, pass);
	}

	/*
	 * We've scanned the bus and so we know all about what's on
	 * the other side of any bridges that may be on this bus plus
	 * any devices.
	 *
	 * Return how far we've got finding sub-buses.
	 */
	#ifdef DEBUG_VERSION
		safe_printf("Bus scan for %02x returning with max=%02x\n", bus->number, max);
	#endif

	return max;
}

struct pci_bus far * pci_scan_bus(long bus, struct pci_ops *ops, void *sysdata)
{
	struct pci_bus far * b = pci_alloc_primary_bus(bus);
	if (b) 
	{
		b->sysdata = sysdata;
		b->ops = ops;
		b->subordinate = pci_do_scan_bus(b);
	}

	return b;
}

/**
 * pci_find_subsys - begin or continue searching for a PCI device by vendor/subvendor/device/subdevice 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 device ids
 * @ss_vendor: PCI subsystem vendor id to match, or %PCI_ANY_ID to match all vendor ids
 * @ss_device: PCI subsystem device id to match, or %PCI_ANY_ID to match all device 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, @device, @ss_vendor and @ss_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 next device on the global list.
 */
struct pci_dev far * pci_find_subsys(unsigned long vendor, unsigned long device,
		unsigned long ss_vendor, unsigned long ss_device,
		const struct pci_dev far * 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 device 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 next device on the global list.
 */
struct pci_dev far * pci_find_device(unsigned long vendor, unsigned long device, 
	const struct pci_dev far * from)
{
	return pci_find_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from);
}

/**
 * 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 * far pci_find_parent_resource(const struct pci_dev far * dev, 
	struct resource far * res)
{
	const struct pci_bus far * bus = dev->bus;
	int i;
	struct resource far * best = NULL;

	for(i=0; i<4; i++) 
	{
		struct resource far * 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;
}

long pci_claim_resource(struct pci_dev far * dev, long resource)
{
    struct resource far * res = &dev->resource[resource];
    struct resource far * root = pci_find_parent_resource(dev, res);
    long err;
	struct resource far * tmp;

    err = -EINVAL;
    if (root != NULL)
    {
	    tmp = request_resource(root,res);
	    if(!tmp)
	    {
			err = -EINVAL;

			#ifdef DEBUG_VERSION
				safe_printf("PCI: Address space collision on "
					"region %d of device %s [%lx:%lx]\n",
					(unsigned short)resource,dev->name,
					res->start,res->end);
			#endif
	    }
		else
		{
			err = 0L;
		}
	}
	else
	{
		#ifdef DEBUG_VERSION
			safe_printf("PCI: No parent found for region %d "
		       "of device %s\n", resource, dev->name);
		#endif
	}

	return err;
}

/**
 * pci_find_slot - locate PCI device from a given PCI slot
 * @bus: number of PCI bus on which desired PCI device resides
 * @devfn: encodes number of PCI slot in which the desired PCI 
 * device resides and the logical device number within that slot 
 * in case of multi-function devices.
 *
 * Given a PCI bus and slot/function 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 far * pci_find_slot(unsigned long bus, unsigned long devfn)
{
	struct pci_dev far * dev;

	pci_for_each_dev(dev)
	{
		if (dev->bus->number == bus && dev->devfn == devfn)
			return dev;
	}

	return NULL;
}

struct irq_routing_table far * pcibios_get_irq_routing_table(void)
{
	struct irq_routing_options opt;
	struct irq_routing_options far * popt;
	struct irq_routing_table far * rt = NULL;
	unsigned res, map;
	unsigned seg1;
	void far * page;

	if (!pci_bios_present)
		return NULL;

	page = (char far *)malloc((unsigned short)PAGE_SIZE);
	if (!page)
		return NULL;

	opt.table = (struct irq_info far *) page;
	opt.size = PAGE_SIZE;
	opt.segment = 0xf000;
	seg1 = opt.segment;
	popt = &(opt);

	#ifdef DEBUG_VERSION
		safe_printf("PCI: Fetching IRQ routing table... \n");
	#endif

	_asm push ds
	_asm push es
	_asm push di

	_asm mov ax,seg1
	_asm mov ds,ax
	_asm mov ah,PCI_FUNCTION_ID
	_asm mov al,GET_IRQ_ROUTING_OPTIONS
	_asm xor bx,bx
	_asm les di,popt
	_asm int 1ah

	_asm pop di
	_asm pop es
	_asm pop ds

	_asm mov res,ax
	_asm jc return_null
	_asm cmp ah,SUCCESSFUL
	_asm jnz return_null
	_asm mov map,bx
	_asm jmp get_ok

	return_null:

		#ifdef DEBUG_VERSION
			safe_printf("PCI: Error %02x when fetching IRQ routing table.\n", (res >> 8) & 0xff);
		#endif
		
		free(page);

		return NULL;

	get_ok:

		#ifdef DEBUG_VERSION
			safe_printf("OK  ret=%d, size=%d, map=%x\n", res, opt.size, map);
		#endif			

		rt = (struct irq_routing_table far * )malloc(
		      sizeof(struct irq_routing_table) + opt.size);
		if(rt)
		{
			memset(rt, 0, sizeof(struct irq_routing_table));
			rt->size = opt.size + sizeof(struct irq_routing_table);
			rt->exclusive_irqs = map;
			memcpy(rt->slots,page,opt.size);

			#ifdef DEBUG_VERSION
				safe_printf("PCI: Using BIOS Interrupt Routing Table\n");
			#endif
		}

		free(page);

		return rt;
}

/*
 * Discover remaining PCI buses in case there are peer host bridges.
 * We use the number of last PCI bus provided by the PCI BIOS.
 */
void pcibios_fixup_peer_bridges(void)
{
	long n;
	struct pci_bus bus;
	struct pci_dev dev;
	u16 l;

	if (pcibios_last_bus <= 0 || pcibios_last_bus >= 0xff)
		return;

	#ifdef DEBUG_VERSION
		safe_printf("PCI: Peer bridge fixup\n");
	#endif

	for (n=0; n <= pcibios_last_bus; n++) 
	{
		if (pci_bus_exists(&pci_root_buses, n))
			continue;
		bus.number = n;
		bus.ops = pci_root_ops;
		dev.bus = &bus;
		for(dev.devfn=0; dev.devfn<256; dev.devfn += 8)
			if (!pci_read_config_word(&dev, PCI_VENDOR_ID, &l) &&
			    l != 0x0000 && l != 0xffff) 
			{
				#ifdef DEBUG_VERSION
					safe_printf("Found device at %02x:%02x [%04x]\n", n, dev.devfn, l);
					safe_printf("PCI: Discovered peer bus %02x\n", n);
				#endif

				pci_scan_bus(n, pci_root_ops, NULL);
				break;
			}
	}
}

/* Return the conflict entry if you can't request it */
struct resource far * __request_resource(struct resource far * root, 
	struct resource far * new)
{
	unsigned long start = new->start;
	unsigned long end = new->end;
	struct resource far * tmp;
	struct resource far **p;

	if (end < start)
		return root;

	if (start < root->start)
		return root;

	if (end > root->end)
		return root;

	p = &root->child;
	for (;;) 
	{
		tmp = *p;
		if (!tmp || tmp->start > end) 
		{
			new->sibling = tmp;
			*p = new;

⌨️ 快捷键说明

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