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

📄 pciirq.c

📁 DOS_PCI_DRIVER,DOS环境下运行的PCI驱动程序,个人觉得比较好用.
💻 C
📖 第 1 页 / 共 2 页
字号:
#include <stdio.h>

#include "typedef.h"
#include "low.h"
#include "list.h"
#include "pci.h"

extern struct irq_routing_table far * pirq_table;

/*
 *  If we have a IRQ routing table, use it to search for peer host
 *  bridges.  It's a gross hack, but since there are no other known
 *  ways how to get a list of buses, we have to go this way.
 */

void pirq_peer_trick(void)
{
	struct irq_routing_table far * rt = pirq_table;
	u8 busmap[256];
	long i;
	struct irq_info far * e;

	memset(busmap, 0, sizeof(busmap));
	for(i=0; i < (rt->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info); i++) 
	{
		e = &rt->slots[i];

		{
			int j;

			#ifdef DEBUG_VERSION
				safe_printf("%02x:%02x slot=%02x", e->bus, e->devfn/8, e->slot);
				for(j=0; j<4; j++)
					safe_printf(" %d:%02x/%04x", j, e->irq[j].link, e->irq[j].bitmap);
				safe_printf("\n");
			#endif	
		}

		busmap[e->bus] = 1;
	}

	for(i=1; i<256; i++)
	{
		/*
		 *  It might be a secondary bus, but in this case its parent is already
		 *  known (ascending bus order) and therefore pci_scan_bus returns immediately.
		 */
		if (busmap[i] && pci_scan_bus(i, pci_root_bus->ops, NULL))
		{
			#ifdef DEBUG_VERSION
				safe_printf("PCI: Discovered primary peer bus %02x [IRQ]\n", i);
			#endif
		}
	}

	pcibios_last_bus = -1;
}

long pci_get_interrupt_pin(struct pci_dev far * dev, struct pci_dev far **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;
}

int pcibios_set_irq_routing(struct pci_dev far * dev, long pin, long irq)
{
	int res;
	unsigned temp_cx,temp_bx;

	temp_cx = (irq << 8) | (pin + 10);
	temp_bx = (dev->bus->number << 8) | dev->devfn;

	_asm mov ah, PCI_FUNCTION_ID
	_asm mov al, SET_PCI_IRQ
	_asm mov bx, temp_bx
	_asm mov cx, temp_cx
	_asm push ds
	_asm mov dx,0f000h
	_asm mov ds,dx
	_asm int 1ah
	_asm pop ds
	_asm mov res,ax
	_asm jc set_fail
	_asm jmp set_ret

	set_fail:
		return 0;
		
	set_ret:
		return !(res & 0xff00);
}

long pirq_bios_set(struct pci_dev far * router, struct pci_dev far * dev, long pirq, 
	long irq)
{
	struct pci_dev *bridge;

	int pin = pci_get_interrupt_pin(dev, &bridge);

	return pcibios_set_irq_routing(bridge, pin, irq);
}

/*
 * The Intel PIIX4 pirq rules are fairly simple: "pirq" is
 * just a pointer to the config space.
 */
long pirq_piix_get(struct pci_dev far * router, struct pci_dev far * dev, long pirq)
{
	u8 x;

	pci_read_config_byte(router, pirq, &x);
	return (x < 16) ? x : 0;
}

long pirq_piix_set(struct pci_dev far * router, struct pci_dev far * dev, long pirq, 
	long irq)
{
	pci_write_config_byte(router,pirq,(u8)irq);
	return 1;
}

/*
 * Common IRQ routing practice: nybbles in config space,
 * offset by some magic constant.
 */
unsigned long read_config_nybble(struct pci_dev far * router, unsigned long offset, 
	unsigned long nr)
{
	u8 x;
	unsigned long reg = offset + (nr >> 1);

	pci_read_config_byte(router, reg, &x);
	return (nr & 1) ? (x >> 4) : (x & 0xf);
}

void write_config_nybble(struct pci_dev far * router, unsigned long offset,
	unsigned long nr, unsigned long val)
{
	u8 x;
	unsigned long reg = offset + (nr >> 1);

	pci_read_config_byte(router, reg, &x);
	x = (nr & 1) ? ((x & 0x0f) | (val << 4)) : ((x & 0xf0) | val);
	pci_write_config_byte(router, reg, x);
}

/*
 * ALI pirq entries are damn ugly, and completely undocumented.
 * This has been figured out from pirq tables, and it's not a pretty
 * picture.
 */
long pirq_ali_get(struct pci_dev far * router, struct pci_dev far * dev, long pirq)
{
	unsigned char irqmap[16] = { 0, 9, 3, 10, 4, 5, 7, 6, 1, 11, 0, 12, 0, 14, 0, 15 };

	return irqmap[read_config_nybble(router, 0x48, pirq-1)];
}

long pirq_ali_set(struct pci_dev *router, struct pci_dev *dev, long pirq, long irq)
{
	unsigned char irqmap[16] = { 0, 8, 0, 2, 4, 5, 7, 6, 0, 1, 3, 9, 11, 0, 13, 15 };
	unsigned int val = irqmap[irq];
		
	if (val) 
	{
		write_config_nybble(router, 0x48, pirq-1, val);
		return 1;
	}

	return 0;
}

/*
 * The VIA pirq rules are nibble-based, like ALI,
 * but without the ugly irq number munging.
 */
long pirq_via_get(struct pci_dev far * router, struct pci_dev far * dev, long pirq)
{
	return read_config_nybble(router, 0x55, pirq);
}

long pirq_via_set(struct pci_dev far * router, struct pci_dev far * dev, long pirq, 
	long irq)
{
	write_config_nybble(router, 0x55, pirq, irq);
	return 1;
}

/*
 * OPTI: high four bits are nibble pointer..
 * I wonder what the low bits do?
 */
long pirq_opti_get(struct pci_dev far * router, struct pci_dev far * dev, long pirq)
{
	return read_config_nybble(router, 0xb8, pirq >> 4);
}

long pirq_opti_set(struct pci_dev far * router, struct pci_dev far * dev, long pirq, 
	long irq)
{
	write_config_nybble(router, 0xb8, pirq >> 4, irq);
	return 1;
}

/*
 * Cyrix: nibble offset 0x5C
 */
long pirq_cyrix_get(struct pci_dev far * router, struct pci_dev far * dev, long pirq)
{
	return read_config_nybble(router, 0x5C, pirq-1);
}

long pirq_cyrix_set(struct pci_dev far * router, struct pci_dev far * dev, long pirq, 
	long irq)
{
	write_config_nybble(router, 0x5C, pirq-1, irq);
	return 1;
}

/*
 *	PIRQ routing for SiS 85C503 router used in several SiS chipsets
 *	According to the SiS 5595 datasheet (preliminary V1.0, 12/24/1997)
 *	the related registers work as follows:
 *	
 *	general: one byte per re-routable IRQ,
 *		 bit 7      IRQ mapping enabled (0) or disabled (1)
 *		 bits [6:4] reserved
 *		 bits [3:0] IRQ to map to
 *		     allowed: 3-7, 9-12, 14-15
 *		     reserved: 0, 1, 2, 8, 13
 *
 *	individual registers in device config space:
 *
 *	0x41/0x42/0x43/0x44:	PCI INT A/B/C/D - bits as in general case
 *
 *	0x61:			IDEIRQ: bits as in general case - but:
 *				bits [6:5] must be written 01
 *				bit 4 channel-select primary (0), secondary (1)
 *
 *	0x62:			USBIRQ: bits as in general case - but:
 *				bit 4 OHCI function disabled (0), enabled (1)
 *	
 *	0x6a:			ACPI/SCI IRQ - bits as in general case
 *
 *	0x7e:			Data Acq. Module IRQ - bits as in general case
 *
 *	Apparently there are systems implementing PCI routing table using both
 *	link values 0x01-0x04 and 0x41-0x44 for PCI INTA..D, but register offsets
 *	like 0x62 as link values for USBIRQ e.g. So there is no simple
 *	"register = offset + pirq" relation.
 *	Currently we support PCI INTA..D and USBIRQ and try our best to handle
 *	both link mappings.
 *	IDE/ACPI/DAQ mapping is currently unsupported (left untouched as set by BIOS).
 */

long pirq_sis_get(struct pci_dev far * router, struct pci_dev far * dev, long pirq)
{
	u8 x;
	int reg = pirq;

	switch(pirq) {
		case 0x01:
		case 0x02:
		case 0x03:
		case 0x04:
			reg += 0x40;
		case 0x41:
		case 0x42:
		case 0x43:
		case 0x44:
		case 0x62:
			pci_read_config_byte(router, reg, &x);
			if (reg != 0x62)
				break;
			if (!(x & 0x40))
				return 0;
			break;
		case 0x61:
		case 0x6a:
		case 0x7e:

			#ifdef DEBUG_VERSION
				safe_printf("SiS pirq: advanced IDE/ACPI/DAQ mapping not yet implemented\n");
			#endif

			return 0;
		default:		
			
			#ifdef DEBUG_VERSION
				safe_printf("SiS router pirq escape (%d)\n", pirq);
			#endif

			return 0;
	}

	return (x & 0x80) ? 0 : (x & 0x0f);
}

long pirq_sis_set(struct pci_dev far * router, struct pci_dev far * dev, long pirq, 
	long irq)
{
	u8 x;
	int reg = pirq;

	switch(pirq) {
		case 0x01:
		case 0x02:
		case 0x03:
		case 0x04:
			reg += 0x40;
		case 0x41:
		case 0x42:
		case 0x43:
		case 0x44:
		case 0x62:
			x = (irq&0x0f) ? (irq&0x0f) : 0x80;
			if (reg != 0x62)
				break;
			/* always mark OHCI enabled, as nothing else knows about this */
			x |= 0x40;
			break;
		case 0x61:
		case 0x6a:
		case 0x7e:

			#ifdef DEBUG_VERSION
				safe_printf("advanced SiS pirq mapping not yet implemented\n");
			#endif

			return 0;
		default:
			
			#ifdef DEBUG_VERSION
				safe_printf("SiS router pirq escape (%d)\n", pirq);
			#endif

			return 0;
	}

	pci_write_config_byte(router, reg, x);

	return 1;
}

/*
 * VLSI: nibble offset 0x74 - educated guess due to routing table and
 *       config space of VLSI 82C534 PCI-bridge/router (1004:0102)
 *       Tested on HP OmniBook 800 covering PIRQ 1, 2, 4, 8 for onboard
 *       devices, PIRQ 3 for non-pci(!) soundchip and (untested) PIRQ 6
 *       for the busbridge to the docking station.
 */

long pirq_vlsi_get(struct pci_dev far * router, struct pci_dev far * dev, long pirq)
{
	if (pirq > 8) 
	{
		#ifdef DEBUG_VERSION
			safe_printf("VLSI router pirq escape (%d)\n", pirq);
		#endif
		return 0;
	}

	return read_config_nybble(router, 0x74, pirq-1);
}

long pirq_vlsi_set(struct pci_dev far * router, struct pci_dev far * dev, long pirq, 
	long irq)
{
	if (pirq > 8) 
	{
		#ifdef DEBUG_VERSION
			safe_printf("VLSI router pirq escape (%d)\n", pirq);
		#endif

		return 0;
	}

	write_config_nybble(router, 0x74, pirq-1, irq);
	return 1;
}

/*
 * ServerWorks: PCI interrupts mapped to system IRQ lines through Index
 * and Redirect I/O registers (0x0c00 and 0x0c01).  The Index register
 * format is (PCIIRQ## | 0x10), e.g.: PCIIRQ10=0x1a.  The Redirect
 * register is a straight binary coding of desired PIC IRQ (low nibble).
 *
 * The 'link' value in the PIRQ table is already in the correct format

⌨️ 快捷键说明

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