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

📄 pciirq.c

📁 PCI总线在DOS操作系统下的驱动程序源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
 * for the Index register.  There are some special index values:
 * 0x00 for ACPI (SCI), 0x01 for USB, 0x02 for IDE0, 0x04 for IDE1,
 * and 0x03 for SMBus.
 */
long pirq_serverworks_get(struct pci_dev far * router,struct pci_dev far * dev,long pirq)
{
	outb((u8)pirq,0xc00);
	return inb(0xc01) & 0xf;
}

long pirq_serverworks_set(struct pci_dev far * router, struct pci_dev far * dev, 
	long pirq, long irq)
{
	outb((u8)pirq, 0xc00);
	outb((u8)irq, 0xc01);

	return 1;
}

/* Support for AMD756 PCI IRQ Routing
 * Jhon H. Caicedo <jhcaiced@osso.org.co>
 * Jun/21/2001 0.2.0 Release, fixed to use "nybble" functions... (jhcaiced)
 * Jun/19/2001 Alpha Release 0.1.0 (jhcaiced)
 * The AMD756 pirq rules are nibble-based
 * offset 0x56 0-3 PIRQA  4-7  PIRQB
 * offset 0x57 0-3 PIRQC  4-7  PIRQD
 */
long pirq_amd756_get(struct pci_dev far * router, struct pci_dev far * dev, long pirq)
{
	u8 irq;
	irq = 0;
	if (pirq <= 4)
	{
		irq = read_config_nybble(router, 0x56, pirq - 1);
	}

	#ifdef DEBUG_VERSION
		safe_printf("AMD756: dev %04x:%04x, router pirq : %d get irq : %2d\n",
			dev->vendor, dev->device, pirq, irq);
	#endif

	return irq;
}

long pirq_amd756_set(struct pci_dev far * router, struct pci_dev far * dev, long pirq, 
	long irq)
{
	#ifdef DEBUG_VERSION
		safe_printf("AMD756: dev %04x:%04x, router pirq : %d SET irq : %2d\n", 
			dev->vendor, dev->device, pirq, irq);
	#endif

	if (pirq <= 4)
	{
		write_config_nybble(router, 0x56, pirq - 1, irq);
	}

	return 1;
}


extern struct irq_router pirq_bios_router;

extern struct irq_router pirq_routers[];

extern unsigned short total_pirq_routers;

extern long pirq_penalty[16];

extern unsigned long pcibios_irq_mask;

extern struct pci_dev *pirq_router_dev;

extern struct irq_router *pirq_router;

void pirq_find_router(void)
{
	struct irq_routing_table far * rt = pirq_table;
	struct irq_router far * r;

	if (!rt->signature) 
	{
		#ifdef DEBUG_VERSION
			safe_printf("PCI: Using BIOS for IRQ routing\n");
		#endif

		pirq_router = &pirq_bios_router;
		return;
	}

	#ifdef DEBUG_VERSION
		safe_printf("PCI: Attempting to find IRQ router for %04x:%04x\n",
			rt->rtr_vendor, rt->rtr_device);
	#endif

	/* fall back to default router if nothing else found */
	pirq_router = &pirq_routers[total_pirq_routers - 1];

	pirq_router_dev = pci_find_slot(rt->rtr_bus, rt->rtr_devfn);
	if (!pirq_router_dev) 
	{
		#ifdef DEBUG_VERSION
			safe_printf("PCI: Interrupt router not found at %02x:%02x\n", 
				rt->rtr_bus, rt->rtr_devfn);
		#endif
		return;
	}

	for(r= pirq_routers; r->vendor; r++) 
	{
		/* Exact match against router table entry? Use it! */
		if (r->vendor == rt->rtr_vendor && r->device == rt->rtr_device) 
		{
			pirq_router = r;
			break;
		}
		/* Match against router device entry? Use it as a fallback */
		if (r->vendor == pirq_router_dev->vendor && r->device == pirq_router_dev->device) {
			pirq_router = r;
		}
	}

	#ifdef DEBUG_VERSION
		safe_printf("PCI: Using IRQ router %s [%04x/%04x] at %s\n",
			pirq_router->name,
			pirq_router_dev->vendor,
			pirq_router_dev->device,
			pirq_router_dev->slot_name);
	#endif
}

void pcibios_irq_init(void)
{
	#ifdef DEBUG_VERSION
		safe_printf("PCI: IRQ init\n");
	#endif

	/*pirq_table = pirq_find_routing_table();*/

	if (!pirq_table && (pci_probe & PCI_BIOS_IRQ_SCAN))
		pirq_table = pcibios_get_irq_routing_table();

	if (pirq_table) 
	{
		pirq_peer_trick();
		pirq_find_router();
		if (pirq_table->exclusive_irqs) 
		{
			int i;
			for (i=0; i<16; i++)
				if (!(pirq_table->exclusive_irqs & (1 << i)))
					pirq_penalty[i] += 100;
		}
	}
}

struct irq_info far * pirq_get_info(struct pci_dev far * dev)
{
	struct irq_routing_table far * rt = pirq_table;

	int entries = (rt->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info);
	struct irq_info far * info;

	for (info = rt->slots; entries--; info++)
	{
		if (info->bus == dev->bus->number && PCI_SLOT(info->devfn) == PCI_SLOT(dev->devfn))
			return info;
	}

	return NULL;
}

/*
 *  Code for querying and setting of IRQ routes on various interrupt routers.
 */

void eisa_set_level_irq(unsigned long irq)
{
	unsigned char mask = 1 << (irq & 7);
	unsigned short port = 0x4d0 + (irq >> 3);
	unsigned char val = inb(port);

	if (!(val & mask)) 
	{
		#ifdef DEBUG_VERSION
			safe_printf(" -> edge");
		#endif
		outb((u8)(val|mask), port);
	}
}

long pcibios_lookup_irq(struct pci_dev far * dev, long assign)
{
	u8 pin;
	struct irq_info far * info;
	long i, pirq, newirq;
	long irq = 0;
	u32 mask;
	struct irq_router far * r = pirq_router;
	struct pci_dev *dev2;
	char *msg = NULL;

	if (!pirq_table)
		return 0;

	/* Find IRQ routing entry */
	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
	if (!pin) 
	{
		#ifdef DEBUG_VERSION
			safe_printf(" -> no interrupt pin\n");
		#endif
		return 0;
	}

	pin = pin - 1;

	#ifdef DEBUG_VERSION
		safe_printf("IRQ for %s:%d", dev->slot_name, pin);
	#endif

	info = pirq_get_info(dev);
	if (!info) 
	{
		#ifdef DEBUG_VERSION
			safe_printf(" -> not found in routing table\n");
		#endif
		return 0;
	}

	pirq = info->irq[pin].link;
	mask = info->irq[pin].bitmap;
	if (!pirq) 
	{
		#ifdef DEBUG_VERSION
			safe_printf(" -> not routed\n");
		#endif
		return 0;
	}

	#ifdef DEBUG_VERSION
		safe_printf(" -> PIRQ %02x, mask %04x, excl %04x", pirq, mask, 
			pirq_table->exclusive_irqs);
	#endif
	mask &= pcibios_irq_mask;

	/*
	 * Find the best IRQ to assign: use the one
	 * reported by the device if possible.
	 */
	newirq = dev->irq;
	if (!newirq && assign) 
	{
		for (i = 0; i < 16; i++) 
		{
			if (!(mask & (1 << i)))
				continue;

			if (pirq_penalty[i] < pirq_penalty[newirq]) 
			{
				newirq = i;
			}
		}
	}

	#ifdef DEBUG_VERSION
		safe_printf(" -> newirq = %d\n", newirq);
	#endif

	/* Check if it is hardcoded */
	if ((pirq & 0xf0) == 0xf0) 
	{
		irq = pirq & 0xf;

		#ifdef DEBUG_VERSION
			safe_printf(" -> hardcoded IRQ %d\n",irq);
		#endif

		msg = "Hardcoded";
	} 
	else if (r->get && (irq = r->get(pirq_router_dev, dev, pirq))) 
	{
		#ifdef DEBUG_VERSION
			safe_printf(" -> got IRQ %d\n", irq);
		#endif
		msg = "Found";
	} 
	else if (newirq && r->set && (dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) 
	{
		#ifdef DEBUG_VERSION
			safe_printf(" -> assigning IRQ %d\n", newirq);
		#endif

		if (r->set(pirq_router_dev, dev, pirq, newirq)) 
		{
			eisa_set_level_irq(newirq);

			#ifdef DEBUG_VERSION
				safe_printf(" ... OK\n");
			#endif
			msg = "Assigned";
			irq = newirq;
		}
	}

	if (!irq) 
	{
		#ifdef DEBUG_VERSION
			safe_printf(" ... failed\n");
		#endif
		if (newirq && mask == (1 << newirq)) 
		{
			msg = "Guessed";
			irq = newirq;
		} 
		else
			return 0;
	}

	#ifdef DEBUG_VERSION
		safe_printf("PCI: %s IRQ %d for device %s\n", msg, irq, dev->slot_name);
	#endif

	/* Update IRQ for all devices with the same pirq value */
	pci_for_each_dev(dev2) 
	{
		pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin);
		if (!pin)
			continue;
		pin--;
		info = pirq_get_info(dev2);
		if (!info)
			continue;
		if (info->irq[pin].link == pirq) 
		{
			/* We refuse to override the dev->irq information. Give a warning! */
		    	if (dev2->irq && dev2->irq != irq) 
				{
					#ifdef DEBUG_VERSION
		    			safe_printf("IRQ routing conflict for %s, have irq %d, want irq %d\n",
							dev2->slot_name,dev2->irq,irq);
					#endif

		    		continue;
		    	}

			dev2->irq = irq;
			pirq_penalty[irq]++;
			if (dev != dev2)
			{
				#ifdef DEBUG_VERSION
					safe_printf("PCI: Sharing IRQ %d with %s\n", irq, dev2->slot_name);
				#endif
			}
		}
	}

	return 1;
}

void pcibios_fixup_irqs(void)
{
	struct pci_dev far * dev;
	u8 pin;

	safe_printf("PCI: IRQ fixup\n");
	pci_for_each_dev(dev) 
	{
		/*
		 * If the BIOS has set an out of range IRQ number, just ignore it.
		 * Also keep track of which IRQ's are already in use.
		 */
		if (dev->irq >= 16) 
		{
			#ifdef DEBUG_VERSION
				safe_printf("%s: ignoring bogus IRQ %d\n", dev->slot_name, dev->irq);
			#endif

			dev->irq = 0;
		}

		/* If the IRQ is already assigned to a PCI device, ignore its ISA use penalty */
		if (pirq_penalty[dev->irq] >= 100 && pirq_penalty[dev->irq] < 100000)
			pirq_penalty[dev->irq] = 0;
		pirq_penalty[dev->irq]++;
	}

	pci_for_each_dev(dev) 
	{
		pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);

		/*
		 * Still no IRQ? Try to lookup one...
		 */
		if (pin && !dev->irq)
			pcibios_lookup_irq(dev, 0);
	}
}

⌨️ 快捷键说明

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