pci.c

来自「一个类似windows」· C语言 代码 · 共 813 行 · 第 1/2 页

C
813
字号
/* $Id: pci.c 21261 2006-03-08 23:26:25Z audit $
 *
 * COPYRIGHT:       See COPYING in the top level directory
 * PROJECT:         ReactOS kernel
 * FILE:            ntoskrnl/hal/x86/pci.c
 * PURPOSE:         Interfaces to the PCI bus
 * PROGRAMMER:      David Welch (welch@mcmail.com)
 *                  Eric Kohl (ekohl@rz-online.de)
 * UPDATE HISTORY:
 *                  05/06/1998: Created
 *                  17/08/2000: Added preliminary pci bus scanner
 *                  13/06/2001: Implemented access to pci configuration space
 */

/*
 * NOTES: Sections copied from the Linux pci support
 */

/* INCLUDES *****************************************************************/

#include <hal.h>
#define NDEBUG
#include <debug.h>


/* MACROS ******************************************************************/

/* FIXME These are also defined in drivers/bus/pci/pcidef.h.
   Maybe put PCI definitions in a central include file??? */

/* access type 1 macros */
#define CONFIG_CMD(bus, dev_fn, where) \
	(0x80000000 | (((ULONG)(bus)) << 16) | (((dev_fn) & 0x1F) << 11) | (((dev_fn) & 0xE0) << 3) | ((where) & ~3))

/* access type 2 macros */
#define IOADDR(dev_fn, where) \
	(0xC000 | (((dev_fn) & 0x1F) << 8) | (where))
#define FUNC(dev_fn) \
	((((dev_fn) & 0xE0) >> 4) | 0xf0)

#define  PCI_BASE_ADDRESS_SPACE	0x01	/* 0 = memory, 1 = I/O */
#define  PCI_BASE_ADDRESS_SPACE_IO 0x01
#define  PCI_BASE_ADDRESS_SPACE_MEMORY 0x00
#define  PCI_BASE_ADDRESS_MEM_TYPE_MASK 0x06
#define  PCI_BASE_ADDRESS_MEM_TYPE_32	0x00	/* 32 bit address */
#define  PCI_BASE_ADDRESS_MEM_TYPE_1M	0x02	/* Below 1M [obsolete] */
#define  PCI_BASE_ADDRESS_MEM_TYPE_64	0x04	/* 64 bit address */
#define  PCI_BASE_ADDRESS_MEM_PREFETCH	0x08	/* prefetchable? */
#define  PCI_BASE_ADDRESS_MEM_MASK	(~0x0fUL)
#define  PCI_BASE_ADDRESS_IO_MASK	(~0x03UL)
/* bit 1 is reserved if address_space = 1 */


/* GLOBALS ******************************************************************/

#define TAG_PCI  TAG('P', 'C', 'I', 'H')

static ULONG BusConfigType = 0;  /* undetermined config type */
static KSPIN_LOCK PciLock;

/* FUNCTIONS ****************************************************************/

static NTSTATUS
ReadPciConfigUchar(UCHAR Bus,
		   UCHAR Slot,
		   UCHAR Offset,
		   PUCHAR Value)
{
   KIRQL oldIrql;

   switch (BusConfigType)
     {
     case 1:
        KeAcquireSpinLock(&PciLock, &oldIrql);
	WRITE_PORT_ULONG((PULONG)0xCF8, CONFIG_CMD(Bus, Slot, Offset));
	*Value = READ_PORT_UCHAR((PUCHAR)0xCFC + (Offset & 3));
	KeReleaseSpinLock(&PciLock, oldIrql);
	return STATUS_SUCCESS;

     case 2:
        KeAcquireSpinLock(&PciLock, &oldIrql);
	WRITE_PORT_UCHAR((PUCHAR)0xCF8, (UCHAR)FUNC(Slot));
	WRITE_PORT_UCHAR((PUCHAR)0xCFA, Bus);
	*Value = READ_PORT_UCHAR((PUCHAR)(IOADDR(Slot, Offset)));
	WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0);
	KeReleaseSpinLock(&PciLock, oldIrql);
	return STATUS_SUCCESS;
     }
   return STATUS_UNSUCCESSFUL;
}


static NTSTATUS
ReadPciConfigUshort(UCHAR Bus,
		    UCHAR Slot,
		    UCHAR Offset,
		    PUSHORT Value)
{
   KIRQL oldIrql;

   if ((Offset & 1) != 0)
     {
	return STATUS_INVALID_PARAMETER;
     }

   switch (BusConfigType)
     {
     case 1:
        KeAcquireSpinLock(&PciLock, &oldIrql);
	WRITE_PORT_ULONG((PULONG)0xCF8, CONFIG_CMD(Bus, Slot, Offset));
	*Value = READ_PORT_USHORT((PUSHORT)0xCFC + (Offset & 2));
	KeReleaseSpinLock(&PciLock, oldIrql);
	return STATUS_SUCCESS;

     case 2:
        KeAcquireSpinLock(&PciLock, &oldIrql);
	WRITE_PORT_UCHAR((PUCHAR)0xCF8, (UCHAR)FUNC(Slot));
	WRITE_PORT_UCHAR((PUCHAR)0xCFA, Bus);
	*Value = READ_PORT_USHORT((PUSHORT)(IOADDR(Slot, Offset)));
	WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0);
	KeReleaseSpinLock(&PciLock, oldIrql);
	return STATUS_SUCCESS;
     }
   return STATUS_UNSUCCESSFUL;
}


static NTSTATUS
ReadPciConfigUlong(UCHAR Bus,
		   UCHAR Slot,
		   UCHAR Offset,
		   PULONG Value)
{
   KIRQL oldIrql;

   if ((Offset & 3) != 0)
     {
	return STATUS_INVALID_PARAMETER;
     }

   switch (BusConfigType)
     {
     case 1:
        KeAcquireSpinLock(&PciLock, &oldIrql);
	WRITE_PORT_ULONG((PULONG)0xCF8, CONFIG_CMD(Bus, Slot, Offset));
	*Value = READ_PORT_ULONG((PULONG)0xCFC);
	KeReleaseSpinLock(&PciLock, oldIrql);
	return STATUS_SUCCESS;

     case 2:
        KeAcquireSpinLock(&PciLock, &oldIrql);
	WRITE_PORT_UCHAR((PUCHAR)0xCF8, (UCHAR)FUNC(Slot));
	WRITE_PORT_UCHAR((PUCHAR)0xCFA, Bus);
	*Value = READ_PORT_ULONG((PULONG)(IOADDR(Slot, Offset)));
	WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0);
	KeReleaseSpinLock(&PciLock, oldIrql);
	return STATUS_SUCCESS;
     }
   return STATUS_UNSUCCESSFUL;
}


static NTSTATUS
WritePciConfigUchar(UCHAR Bus,
		    UCHAR Slot,
		    UCHAR Offset,
		    UCHAR Value)
{
   KIRQL oldIrql;

   switch (BusConfigType)
     {
     case 1:
        KeAcquireSpinLock(&PciLock, &oldIrql);
	WRITE_PORT_ULONG((PULONG)0xCF8, CONFIG_CMD(Bus, Slot, Offset));
	WRITE_PORT_UCHAR((PUCHAR)0xCFC + (Offset&3), Value);
	KeReleaseSpinLock(&PciLock, oldIrql);
	return STATUS_SUCCESS;

     case 2:
        KeAcquireSpinLock(&PciLock, &oldIrql);
	WRITE_PORT_UCHAR((PUCHAR)0xCF8, (UCHAR)FUNC(Slot));
	WRITE_PORT_UCHAR((PUCHAR)0xCFA, Bus);
	WRITE_PORT_UCHAR((PUCHAR)(IOADDR(Slot,Offset)), Value);
	WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0);
	KeReleaseSpinLock(&PciLock, oldIrql);
	return STATUS_SUCCESS;
     }
   return STATUS_UNSUCCESSFUL;
}


static NTSTATUS
WritePciConfigUshort(UCHAR Bus,
		     UCHAR Slot,
		     UCHAR Offset,
		     USHORT Value)
{
   KIRQL oldIrql;

   if ((Offset & 1) != 0)
     {
	return  STATUS_INVALID_PARAMETER;
     }

   switch (BusConfigType)
     {
     case 1:
        KeAcquireSpinLock(&PciLock, &oldIrql);
	WRITE_PORT_ULONG((PULONG)0xCF8, CONFIG_CMD(Bus, Slot, Offset));
	WRITE_PORT_USHORT((PUSHORT)0xCFC + (Offset & 2), Value);
	KeReleaseSpinLock(&PciLock, oldIrql);
	return STATUS_SUCCESS;

     case 2:
        KeAcquireSpinLock(&PciLock, &oldIrql);
	WRITE_PORT_UCHAR((PUCHAR)0xCF8, (UCHAR)FUNC(Slot));
	WRITE_PORT_UCHAR((PUCHAR)0xCFA, Bus);
	WRITE_PORT_USHORT((PUSHORT)(IOADDR(Slot, Offset)), Value);
	WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0);
	KeReleaseSpinLock(&PciLock, oldIrql);
	return STATUS_SUCCESS;
     }
   return STATUS_UNSUCCESSFUL;
}


static NTSTATUS
WritePciConfigUlong(UCHAR Bus,
		    UCHAR Slot,
		    UCHAR Offset,
		    ULONG Value)
{
   KIRQL oldIrql;

   if ((Offset & 3) != 0)
     {
	return  STATUS_INVALID_PARAMETER;
     }

   switch (BusConfigType)
     {
     case 1:
        KeAcquireSpinLock(&PciLock, &oldIrql);
	WRITE_PORT_ULONG((PULONG)0xCF8, CONFIG_CMD(Bus, Slot, Offset));
	WRITE_PORT_ULONG((PULONG)0xCFC, Value);
	KeReleaseSpinLock(&PciLock, oldIrql);
	return STATUS_SUCCESS;

     case 2:
        KeAcquireSpinLock(&PciLock, &oldIrql);
	WRITE_PORT_UCHAR((PUCHAR)0xCF8, (UCHAR)FUNC(Slot));
	WRITE_PORT_UCHAR((PUCHAR)0xCFA, Bus);
	WRITE_PORT_ULONG((PULONG)(IOADDR(Slot, Offset)), Value);
	WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0);
	KeReleaseSpinLock(&PciLock, oldIrql);
	return STATUS_SUCCESS;
     }
   return STATUS_UNSUCCESSFUL;
}


static ULONG STDCALL
HalpGetPciData(PBUS_HANDLER BusHandler,
	       ULONG BusNumber,
	       ULONG SlotNumber,
	       PVOID Buffer,
	       ULONG Offset,
	       ULONG Length)
{
   PVOID Ptr = Buffer;
   ULONG Address = Offset;
   ULONG Len = Length;
   ULONG Vendor;
   UCHAR HeaderType;

   DPRINT("HalpGetPciData() called.\n");
   DPRINT("  BusNumber %lu\n", BusNumber);
   DPRINT("  SlotNumber %lu\n", SlotNumber);
   DPRINT("  Offset 0x%lx\n", Offset);
   DPRINT("  Length 0x%lx\n", Length);

   if ((Length == 0) || (BusConfigType == 0))
     return 0;

   ReadPciConfigUlong((UCHAR)BusNumber,
		      (UCHAR)(SlotNumber & 0x1F),
		      0x00,
		      &Vendor);
   /* some broken boards return 0 if a slot is empty: */
   if (Vendor == 0xFFFFFFFF || Vendor == 0)
   {
     if (BusNumber == 0 && Offset == 0 && Length >= 2)
     {
	*(PUSHORT)Buffer = PCI_INVALID_VENDORID;
	return 2;
     }
     return 0;
   }

   /* 0E=PCI_HEADER_TYPE */
   ReadPciConfigUchar((UCHAR)BusNumber,
		      (UCHAR)(SlotNumber & 0x1F),
		      0x0E,
		      &HeaderType);
   if (((HeaderType & PCI_MULTIFUNCTION) == 0) && ((SlotNumber & 0xE0) != 0))
   {
     if (Offset == 0 && Length >= 2)
     {
	*(PUSHORT)Buffer = PCI_INVALID_VENDORID;
	return 2;
     }
     return 0;
   }
   ReadPciConfigUlong((UCHAR)BusNumber,
		      (UCHAR)SlotNumber,
		      0x00,
		      &Vendor);
   /* some broken boards return 0 if a slot is empty: */
   if (Vendor == 0xFFFFFFFF || Vendor == 0)
   {
     if (BusNumber == 0 && Offset == 0 && Length >= 2)
     {
	*(PUSHORT)Buffer = PCI_INVALID_VENDORID;
	return 2;
     }
     return 0;
   }

   if ((Address & 1) && (Len >= 1))
     {
	ReadPciConfigUchar((UCHAR)BusNumber,
			   (UCHAR)SlotNumber,
			   (UCHAR)Address,
			   Ptr);
	Ptr = (char*)Ptr + 1;
	Address++;
	Len--;
     }

   if ((Address & 2) && (Len >= 2))
     {
	ReadPciConfigUshort((UCHAR)BusNumber,
			    (UCHAR)SlotNumber,
			    (UCHAR)Address,
			    Ptr);
	Ptr = (char*)Ptr + 2;
	Address += 2;
	Len -= 2;
     }

   while (Len >= 4)
     {
	ReadPciConfigUlong((UCHAR)BusNumber,
			   (UCHAR)SlotNumber,
			   (UCHAR)Address,
			   Ptr);
	Ptr = (char*)Ptr + 4;
	Address += 4;
	Len -= 4;
     }

   if (Len >= 2)
     {
	ReadPciConfigUshort((UCHAR)BusNumber,
			    (UCHAR)SlotNumber,
			    (UCHAR)Address,
			    Ptr);
	Ptr = (char*)Ptr + 2;
	Address += 2;
	Len -= 2;
     }

   if (Len >= 1)
     {
	ReadPciConfigUchar((UCHAR)BusNumber,
			   (UCHAR)SlotNumber,
			   (UCHAR)Address,
			   Ptr);
	Ptr = (char*)Ptr + 1;
	Address++;
	Len--;
     }

   return Length - Len;
}


static ULONG STDCALL
HalpSetPciData(PBUS_HANDLER BusHandler,
	       ULONG BusNumber,
	       ULONG SlotNumber,
	       PVOID Buffer,
	       ULONG Offset,
	       ULONG Length)
{
   PVOID Ptr = Buffer;
   ULONG Address = Offset;
   ULONG Len = Length;
   ULONG Vendor;
   UCHAR HeaderType;

   DPRINT("HalpSetPciData() called.\n");
   DPRINT("  BusNumber %lu\n", BusNumber);
   DPRINT("  SlotNumber %lu\n", SlotNumber);
   DPRINT("  Offset 0x%lx\n", Offset);
   DPRINT("  Length 0x%lx\n", Length);

⌨️ 快捷键说明

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