天天看點

35、PCI裝置驅動簡介

PCI(Peripheral Component Interconnect)總線标準是一種将系統外部裝置連接配接起來的總線标準,速度可以達到133MB/s,它是PC中最重要的總線,其他總路線如ISA總線,USB總線等,都挂載在PCI總線上(通過橋接電路)。由Intel推出的一種局部總線,為32位資料位址總線,可以擴充為64位,支援突發讀寫,及多組外圍裝置。

在PCI系統中,Host/PCI稱為北橋,連接配接主處理器總線到基礎PCI局部總線;PCI-ISA橋稱為南橋,連接配接基礎PCI總線到ISA總線。其中南橋通常還含有中斷控制器,IDE控制器,USB控制器和DMA控制器等裝置。

35、PCI裝置驅動簡介

圖示 P412

PCI有三個互相獨立的實體位址空間:裝置存儲器位址空間,I/O位址空間和配置空間。由于PCI支援裝置即插即用,是以PCI裝置不占用固定的記憶體位址空間或I/O位址空間,而是可以由作業系統決定其映射的基址。

PCI總線規範定義的配置Hha總長度為256個位元組,配置資訊按一定的順序和大小依次存放。根據讀取PCI配置空間,可以得到PCI裝置的所有資源。[1]中講述了多種讀取PCI配置空間的方法,包括通過最基本的I/O端口操作進行讀取,通過DDK提供的函數HalGetBusData,HalSetBusData在NT式驅動中進行讀取,在WDM驅動中的讀取方法,等。

一般程式所看到的記憶體指針都是虛拟記憶體,如果想操作實體記憶體,必須使用DDK提供的核心函數WRITE_REGISTER_XX,READ_REGISTER_XX系列函數。

MmAllocateContiguousMemory配置設定連續的實體位址,MmGetPhysicalAddress得到連續的實體記憶體位址。

35、PCI裝置驅動簡介
35、PCI裝置驅動簡介

代碼

#pragma PAGEDCODE

NTSTATUS InitMyPCI(IN PDEVICE_EXTENSION pdx,IN PCM_PARTIAL_RESOURCE_LIST list)

{

PDEVICE_OBJECT fdo = pdx->fdo;

ULONG vector;

KIRQL irql;

KINTERRUPT_MODE mode;

KAFFINITY affinity;

BOOLEAN irqshare;

BOOLEAN gotinterrupt = FALSE;

PHYSICAL_ADDRESS portbase;

BOOLEAN gotport = FALSE;

PCM_PARTIAL_RESOURCE_DESCRIPTOR resource = &list->PartialDescriptors[0];

ULONG nres = list->Count;

BOOLEAN IsMem0 = TRUE;

for (ULONG i = 0; i < nres; ++i, ++resource)

{ // for each resource

switch (resource->Type)

{ // switch on resource type

case CmResourceTypePort:

portbase = resource->u.Port.Start;

pdx->nports = resource->u.Port.Length;

pdx->mappedport = (resource->Flags & CM_RESOURCE_PORT_IO) == 0;

gotport = TRUE;

break;

case CmResourceTypeMemory:

if (IsMem0)

pdx->MemBar0 = (PUCHAR)MmMapIoSpace(resource->u.Memory.Start,

resource->u.Memory.Length,

MmNonCached);

pdx->nMem0 = resource->u.Memory.Length;

IsMem0 = FALSE;

}else

pdx->MemBar1 = (PUCHAR)MmMapIoSpace(resource->u.Memory.Start,

pdx->nMem1 = resource->u.Memory.Length;

}

case CmResourceTypeInterrupt:

irql = (KIRQL) resource->u.Interrupt.Level;

vector = resource->u.Interrupt.Vector;

affinity = resource->u.Interrupt.Affinity;

mode = (resource->Flags == CM_RESOURCE_INTERRUPT_LATCHED)

? Latched : LevelSensitive;

irqshare = resource->ShareDisposition == CmResourceShareShared;

gotinterrupt = TRUE;

default:

KdPrint(("Unexpected I/O resource type %d\n", resource->Type));

} // switch on resource type

} // for each resource

if (!(TRUE&& gotport&& gotinterrupt ))

KdPrint((" Didn't get expected I/O resources\n"));

return STATUS_DEVICE_CONFIGURATION_ERROR;

if (pdx->mappedport)

{ // map port address for RISC platform

pdx->portbase = (PUCHAR) MmMapIoSpace(portbase, pdx->nports, MmNonCached);

if (!pdx->mappedport)

KdPrint(("Unable to map port range %I64X, length %X\n", portbase, pdx->nports));

return STATUS_INSUFFICIENT_RESOURCES;

} // map port address for RISC platform

else

pdx->portbase = (PUCHAR) portbase.QuadPart;

NTSTATUS status = IoConnectInterrupt(&pdx->InterruptObject, (PKSERVICE_ROUTINE) OnInterrupt,

(PVOID) pdx, NULL, vector, irql, irql, LevelSensitive, TRUE, affinity, FALSE);

if (!NT_SUCCESS(status))

KdPrint(("IoConnectInterrupt failed - %X\n", status));

if (pdx->portbase && pdx->mappedport)

MmUnmapIoSpace(pdx->portbase, pdx->nports);

pdx->portbase = NULL;

return status;

#define IMAGE_LENGTH (640*480)

//申請一段連續實體位址來讀取圖像

PHYSICAL_ADDRESS maxAddress;

maxAddress.u.LowPart = 0xFFFFFFFF;

maxAddress.u.HighPart = 0;

pdx->MemForImage = MmAllocateContiguousMemory(IMAGE_LENGTH,maxAddress);

PHYSICAL_ADDRESS pycialAddressForImage = MmGetPhysicalAddress(pdx->MemForImage);

WRITE_REGISTER_BUFFER_UCHAR((PUCHAR)pdx->MemBar0+0x10000,

(PUCHAR)&pycialAddressForImage.u.LowPart,4);

return STATUS_SUCCESS;

示例代碼 P428

參考

[1] Windows 驅動開發技術詳解,張帆