PCIe 장치 로밍 레지스터 읽기 편
1: 레지스터 쓰기
상위 응용 프로그램 쓰기 함수 코드:
/********************************************************************/
/* Write register 32bits */
/********************************************************************/
DLLEXP int CCONV ClLib_RegWrite32( HANDLE hHandle, unsigned char bar, unsigned long offset, unsigned long data )
{
PORT_ACCESS port;
DWORD dwBytes;
int status = RTN_OK;
if( (hHandle == NULL) || (hHandle == INVALID_HANDLE_VALUE) || (bar >= MAX_PCI_BAR) )
{
return (RTN_PRM_ERR);
}
memset(&port,0,sizeof(PORT_ACCESS));
port.bar = bar;
port.offs = offset;
port.u.ldata = data;
if(!DeviceIoControl(hHandle, IOCTL_WRITE_BASE_ULONG,
&port, sizeof(PORT_ACCESS),
NULL, 0,
&dwBytes, NULL))
{
status = RTN_ERR;
}
return (status);
}
함수 중 첫 번째 매개 변수 hHandle은 전편에서 장치를 통해 함수를 열어 얻은 장치 핸들입니다. 매개 변수 bar와offset은 각각 레지스터가 있는 BAR 공간 번호와 대응하는 편이 주소를 지정합니다.코드의 핵심은 DeviceIoControl 함수입니다.다음은 우리가 상세하게 토론할 것이다.
BOOL WINAPI DeviceIoControl(
__in HANDLE hDevice,
__in DWORD dwIoControlCode,
__in_opt LPVOID lpInBuffer,
__in DWORD nInBufferSize,
__out_opt LPVOID lpOutBuffer,
__in DWORD nOutBufferSize,
__out_opt LPDWORD lpBytesReturned,
__inout_opt LPOVERLAPPED lpOverlapped
);
HANDLE hDevice: 장치 핸들DWORD dwIoControlCode:제어 코드
LPVOID lpInBuffer:Buffer 입력
DWORD nInBufferSize: Buffer 크기 입력
LPVOID lpOutBuffer:출력 Buffer
DWORD nOutBufferSize: 출력 Buffer 크기
LPDWORD lpBytesReturned: 반환된 데이터 크기(출력 버퍼에 저장)
LPOVERLAPPED lpOverlapped: 비동기식 또는 동기식 입출력을 지정할 수 있습니다.
이 예에서 우리의 읽기와 쓰기 제어 코드(상기 함수의 두 번째 매개 변수)는 다음과 같이 정의되었다.
/* Used 32768-65535 */
#define FILE_DEVICE_DEMOPCI 530710
#define CODE_BASE 0x0A00
/* Control code definition */
#define IOCTL_WRITE_BASE_ULONG CTL_CODE(FILE_DEVICE_DEMOPCI, CODE_BASE+ 1 , METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_READ_BASE_ULONG CTL_CODE(FILE_DEVICE_DEMOPCI, CODE_BASE+ 2 , METHOD_BUFFERED, FILE_READ_ACCESS)
그리고저희가 또 하나의 PORT 를 정의했습니다.ACCESS 구조체는 입력 버퍼로 사용되며, 쓰기 작업은 데이터를 되찾는 문제와 관련이 없기 때문에, 출력 버퍼와 크기는 각각 NULL과 0을 생성하면 됩니다.다음은 PORTACCESS 구조체에 대한 자세한 정의:
/* For Single Access */
typedef struct _tagPortARG
{
unsigned char bar; /* Pci BaseAddress number */
unsigned long offs; /* offset */
union
{
unsigned long ldata; /* send/recv data buffer */
unsigned short sdata; /* send/recv data buffer */
unsigned char cdata; /* send/recv data buffer */
}u;
} PORT_ACCESS ,*PPORT_ACCESS;
이 구조체에서 우리는 조작할 레지스터에 대응하는 BAR 공간 번호와 편이 주소, 그리고 쓸 데이터를 이 구조에 기입한 다음DeviceIoControl 함수를 호출하여 I/O 관리자가 주 기능 번호를 IRP 로 만든다.MJ_DEVICE_CONTROL의 IRP 패키지는 기본 드라이버에 전달되며, 드라이버는 드라이버 엔트리 함수에 등록된 파견 함수인 DEMOPCi DevcieControl을 호출합니다.NTSTATUS DEMOPciDeviceControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP pIrp)
{
NTSTATUS status = STATUS_SUCCESS;
PTSTDPCI_DEVICE_EXT pDevExt;
PIO_STACK_LOCATION pIrpStack;
void * pBuffer;
ULONG Size;
LARGE_INTEGER StartTime, EndTime, Freq;
LONGLONG IntervelTime;
pDevExt = (PDEMOPCI_DEVICE_EXT)DeviceObject->DeviceExtension;
/* Flag setting when driver is being used */
DEMOPciRequestIncrement(pDevExt);
if (!pDevExt->Started)
{
status = STATUS_DEVICE_NOT_READY;
pIrp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
IoCompleteRequest( pIrp, IO_NO_INCREMENT );
}
pIrpStack = IoGetCurrentIrpStackLocation( pIrp );
switch (pIrpStack->MajorFunction)
{
case IRP_MJ_DEVICE_CONTROL:
switch (pIrpStack->Parameters.DeviceIoControl.IoControlCode)
{
case IOCTL_WRITE_BASE_ULONG:
status = DEMOPciWriteBaseUlong(pDevExt, pIrp);
break;
case IOCTL_READ_BASE_ULONG:
status = DEMOPciReadBaseUlong(pDevExt, pIrp);
break;
case IOCTL_CMN_BUFF_ALLOC:
status = DEMOPciCommonBufferAlloc(pDevExt, pIrp);
break;
case IOCTL_CMN_BUFF_FREE:
status = DEMOPciCommonBufferFree(pDevExt, pIrp);
break;
..............
..............
..............
case IOCTL_CREATE_EVENT:
status= DEMOPciCreateEvent(pDevExt, pIrp);
break;
case IOCTL_CLOSE_EVENT:
status= DEMOPciCloseEvent(pDevExt, pIrp);
break;
default:
status = STATUS_INVALID_PARAMETER;
break;
}
break;
default:
status = STATUS_NOT_IMPLEMENTED;
break;
}
break;
default:
status = STATUS_NOT_IMPLEMENTED;
break;
}
pIrp->IoStatus.Status = status;
if (status != STATUS_PENDING)
{
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
/* Flag release when driver is being used */
DEMOPciRequestDecrement(pDevExt);
}
return (status);
}
DEMOPCiDevcieControl 함수에서 서로 다른 장치 제어 코드에 따라 서로 다른 입출력 작업(예를 들어 DMA 버퍼 공간의 신청과 방출, 이벤트 생성과 닫기 등)을 수행하는 것을 보았습니다.이 예에서 우리는 레지스터 읽기 함수의 구체적인 실현만을 토론할 뿐이다.
NTSTATUS DEMOPciWriteBaseUlong( PDEMOPCI_DEVICE_EXT pDevExt, PIRP pIrp )
{
UCHAR bar;
NTSTATUS status = STATUS_SUCCESS;
PIO_STACK_LOCATION pIrpStack;
PORT_ACCESS *pBuffer;
ULONG ulInBufferSize, ulOutBufferSize;
PULONG pulIoAddr;
pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
ulInBufferSize = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;
pBuffer = (PORT_ACCESS *)pIrp->AssociatedIrp.SystemBuffer;
bar = pBuffer->bar;
if(bar < 6)
{
if( pDevExt->base[bar].WhichMapped == TYPE_MEM )
{
DebugPrint("TYPE_MEM
");
if( ( (pBuffer->offs) + sizeof(ULONG) ) > ( pDevExt->base[bar].MemorySize ) )
{
status=STATUS_INVALID_PARAMETER;
}
else
{
DebugPrint("base[%d].MemoryMappedAddress+(pBuffer->offs): %x
",bar, ((PUCHAR)pDevExt->base[bar].MemoryMappedAddress+(pBuffer->offs)));
DebugPrint("pBuffer->u.ldata: %x
",pBuffer->u.ldata);
WRITE_REGISTER_ULONG((PULONG)((PUCHAR)pDevExt->base[bar].MemoryMappedAddress+(pBuffer->offs)), pBuffer->u.ldata);
}
}
else if( pDevExt->base[bar].WhichMapped == TYPE_IO )
{
DebugPrint("TYPE_IO
");
if( ( (pBuffer->offs) + sizeof(ULONG) ) > ( pDevExt->base[bar].IoPortSize ) )
{
status=STATUS_INVALID_PARAMETER;
}
else
{
DebugPrint("base[%d].IoPortMappedAddress+(pBuffer->offs): %x
",bar, ((PUCHAR)pDevExt->base[bar].IoPortMappedAddress+(pBuffer->offs)));
DebugPrint("pBuffer->u.ldata: %x
",pBuffer->u.ldata);
WRITE_PORT_ULONG((PULONG)((PUCHAR)pDevExt->base[bar].IoPortMappedAddress+(pBuffer->offs)), pBuffer->u.ldata);
}
}
else
{
status=STATUS_UNSUCCESSFUL;
}
}
else
{
status=STATUS_INVALID_PARAMETER;
}
if(status == STATUS_SUCCESS)
{
pIrp->IoStatus.Information = 4;
}
else
{
pIrp->IoStatus.Information = 0;
}
return (status);
}
상기 코드에서 함수는 IRP 패키지의 정보를 분석하여 조작할 레지스터의bar 공간 번호, 편이 주소, 그리고 쓸 데이터 등의 정보를 얻어 시스템 함수 WRITE 를 호출한다.REGISTER_ULONG이 레지스터에 대한 쓰기 작업을 완료한 후 이 함수는 pIrp->IoStatus를 설정합니다.Information = 4는 이번 IRP 작업의 바이트 수를 표시하고 DEMOPCIDevcieControl 함수에 상태를 되돌려줍니다. DEMOPCIDevcieControl 함수에서 IoCompleteRequest 함수를 호출하여 이번 IRP 작업을 완성하고, 마지막으로 I/O 컨트롤러는 결과를 상부 함수에 되돌려줍니다. 이로써 레지스터의 쓰기 작업이 성공적으로 끝났습니다.
2: 레지스터 읽기
쓰기 조작의 절차를 알았으니 읽기 조작은 그대로 하는 것이 매우 간단하다.여기서 우리는 상세하게 서술하지 않겠다.코드가 최고의 선생님이야, 우리가 직접 보여줄게.
상위 레지스터 읽기 작업 함수는 다음과 같습니다.
/********************************************************************/
/* Read register 32bits */
/********************************************************************/
DLLEXP int CCONV ClLib_RegRead32( HANDLE hHandle, unsigned char bar, unsigned long offset, unsigned long *data )
{
PORT_ACCESS port;
DWORD dwBytes;
int status = RTN_OK;
if( (hHandle == NULL) || (hHandle == INVALID_HANDLE_VALUE) || (bar >= MAX_PCI_BAR) )
{
return (RTN_PRM_ERR);
}
memset(&port,0,sizeof(PORT_ACCESS));
port.bar = bar;
port.offs = offset;
if(!DeviceIoControl(hHandle, IOCTL_READ_BASE_ULONG,
&port, sizeof(PORT_ACCESS),
&port, sizeof(PORT_ACCESS),
&dwBytes, NULL))
{
status = RTN_ERR;
}
*data = port.u.ldata;
return (status);
}
제어 레이어 읽기 함수는 다음과 같습니다.
NTSTATUS DEMOPciReadBaseUlong( PDEMOPCI_DEVICE_EXT pDevExt, PIRP pIrp )
{
NTSTATUS status = STATUS_SUCCESS;
PIO_STACK_LOCATION pIrpStack;
PORT_ACCESS *pBuffer;
ULONG ulInBufferSize, ulOutBufferSize;
pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
ulInBufferSize = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;
ulOutBufferSize = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
pBuffer = (PORT_ACCESS *)pIrp->AssociatedIrp.SystemBuffer;
bar = pBuffer->bar;
if(bar < 6)
{
pBuffer->u.ldata=0;
if( pDevExt->base[bar].WhichMapped == TYPE_MEM )
{
DebugPrint("TYPE_MEM
");
if( ( (pBuffer->offs) + sizeof(ULONG) ) > ( pDevExt->base[bar].MemorySize ) )
{
status=STATUS_INVALID_PARAMETER;
}
else
{
DebugPrint("base[%d].MemoryMappedAddress+(pBuffer->offs): %x
",bar, ((PUCHAR)pDevExt->base[bar].MemoryMappedAddress+(pBuffer->offs)));
DebugPrint("pBuffer->u.ldata: %x
",pBuffer->u.ldata);
DebugPrint("pDevExt->base[bar].MemorySize = %lx
", pDevExt->base[bar].MemorySize);
pBuffer->u.ldata = READ_REGISTER_ULONG( (PULONG)((PUCHAR)pDevExt->base[bar].MemoryMappedAddress+(pBuffer->offs)) );
}
}
else if( pDevExt->base[bar].WhichMapped == TYPE_IO )
{
DebugPrint("TYPE_IO
");
if( ( (pBuffer->offs) + sizeof(ULONG) ) > ( pDevExt->base[bar].IoPortSize ) )
{
status=STATUS_INVALID_PARAMETER;
}
else
{
DebugPrint("base[%d].IoPortMappedAddress+(pBuffer->offs): %x
",bar, ((PUCHAR)pDevExt->base[bar].IoPortMappedAddress+(pBuffer->offs)));
DebugPrint("pBuffer->u.ldata: %x
",pBuffer->u.ldata);
pBuffer->u.ldata = READ_PORT_ULONG( (PULONG)((PUCHAR)pDevExt->base[bar].IoPortMappedAddress+(pBuffer->offs)) );
}
}
else
{
status=STATUS_UNSUCCESSFUL;
}
}
else
{
status=STATUS_INVALID_PARAMETER;
}
if(status == STATUS_SUCCESS)
pIrp->IoStatus.Information = sizeof(PORT_ACCESS);
else
pIrp->IoStatus.Information = 0;
return (status);
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.