📄 dispatch.cpp
字号:
dcd.DACChainLoad = 0;//
dcd.DemandMode = 0;
dcd.DmaChannelPriority = Channel0Highest;
//DMA threshold
dcd.LocalToPciAlmostEmpty = 0;
dcd.LocalToPciAlmostFull = 0;
dcd.PciToLocalAlmostEmpty = 0;
dcd.PciToLocalAlmostFull = 0;
rc = DmaOpenBlockChannel(pdx, 0, &dcd);
if (rc != RC_SUCCESS)
{
KdPrint((DBG_NAME "Can't DmaOpenBlockChannel.\n"));
lReturnedValue = 0;
UnlockDevice(pdx);
return CompleteRequestInfo(pIrp, status, lReturnedValue);
}
break;
case IOCTL_PDC4000_READ_REG_DATA:
unsigned long lNumReg, lBufferReg;
lPdcAddress = (ULONG)pdx->LocalRegisterMemBase;
//KdPrint((DBG_NAME "The LocalRegisterMemBase is %x.\n", lPdcAddress));
RtlCopyMemory(&lNumReg, pIrp->AssociatedIrp.SystemBuffer, sizeof(ULONG));
KdPrint((DBG_NAME "Input Value is %x.\n", lNumReg));
lBufferReg = READ_REGISTER_ULONG((unsigned long *)(lPdcAddress + lNumReg));
KdPrint((DBG_NAME "Read Reg Data Value is %x.\n", lBufferReg));
RtlCopyMemory( pIrp->AssociatedIrp.SystemBuffer, &lBufferReg, sizeof(ULONG));
lReturnedValue = sizeof(ULONG);
break;
case IOCTL_PDC4000_WRITE_REG_DATA:
unsigned long lWriteBufferReg[2];
lPdcAddress = (ULONG)pdx->LocalRegisterMemBase;
RtlCopyMemory(lWriteBufferReg, pIrp->AssociatedIrp.SystemBuffer, sizeof(ULONG) * 2);
WRITE_REGISTER_ULONG((unsigned long *)(lPdcAddress + lWriteBufferReg[0]), lWriteBufferReg[1]);
KdPrint((DBG_NAME "Write Reg Data Value is %x.\n", lWriteBufferReg[1]));
lReturnedValue = 0;
break;
case IOCTL_PDC4000_BURST_READ_DATA:
unsigned char cNumBurst, cBufferBurst[16];
lPdcAddress = (ULONG)pdx->PdcMemBase0;
RtlCopyMemory(&cNumBurst, pIrp->AssociatedIrp.SystemBuffer, 1);
KdPrint((DBG_NAME "Input Value is %x.\n", cNumBurst));
READ_REGISTER_BUFFER_UCHAR((unsigned char *)(lPdcAddress + cNumBurst), cBufferBurst, 16);
KdPrint((DBG_NAME "Read Data Value is: \n"));
for (i = 0; i < 16; i ++)
{
KdPrint((DBG_NAME "[%d]: %X.\n", i, cBufferBurst[i]));
}
RtlCopyMemory( pIrp->AssociatedIrp.SystemBuffer, cBufferBurst, 16);
lReturnedValue = 16;
break;
case IOCTL_PDC4000_BURST_WRITE_DATA:
unsigned char cWriteBufferBurst[17];
lPdcAddress = (ULONG)pdx->PdcMemBase0;
//KdPrint((DBG_NAME "The PdcMemBase0 is %x.\n", lPdcAddress));
RtlCopyMemory(cWriteBufferBurst, pIrp->AssociatedIrp.SystemBuffer, 17);
WRITE_REGISTER_BUFFER_UCHAR((unsigned char *)(lPdcAddress + cWriteBufferBurst[0]), &cWriteBufferBurst[1], 16);
KdPrint((DBG_NAME "Write Data Value is %x.\n", cWriteBufferBurst[1]));
lReturnedValue = 0;
break;
case IOCTL_PDC4000_RTLCPY_VABUFFER:
ULONG lDMALocalToPciTransferSize2;
lDMALocalToPciTransferSize2 = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
RtlCopyMemory(pIrp->AssociatedIrp.SystemBuffer, pdx->DmaInfo[0].vaCommonBuffer, lDMALocalToPciTransferSize2);
lReturnedValue = lDMALocalToPciTransferSize2;
break;
default:
break;
}
UnlockDevice(pdx);
KdPrint((DBG_NAME "DeviceIoControl End.\n"));
if (status == STATUS_PENDING)
return STATUS_PENDING;
return CompleteRequestInfo(pIrp, status, lReturnedValue);
} //DispatchIoControl
/******************************************************************************
*
* Function : StartIo
*
* Description: The StartIo Service Routine for PDC4000.
*
******************************************************************************/
VOID StartIo(IN PDEVICE_OBJECT fdo,
IN PIRP pIrp)
{ //StartIo
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)fdo->DeviceExtension;
PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
KdPrint((DBG_NAME "StartIo Start.\n"));
NTSTATUS status = STATUS_SUCCESS;
PMDL pMdl;
/* if (!LockDevice(pdx))
{
CompleteRequest(pIrp, STATUS_DELETE_PENDING);
}
*/
//Open Dma Channl0
DMA_CHANNEL_DESCRIPTION dcd;
dcd.BTERMInputEnable = 0;
dcd.DACChainLoad = 0;
dcd.DemandMode = 0;
dcd.DmaChannelPriority = Rotational;
dcd.DmaEOTPinEnable = 0;
dcd.DoneInterrputEnable = 1;
dcd.EnableTransferCountClear = 0; //For sgl DMA
dcd.FastSlowTerminateModeSelect = 0;
dcd.InternalWaitStates = 0;
dcd.InterrputSelect = 1;
dcd.LocalAddressingMode = 0;
dcd.LocalBurstEnable = 1;
dcd.LocalBusWidth = 3;
dcd.MemoryWriteAndInvalidateMode = 0;
dcd.ReadyInputEnable = 1;
dcd.ScatterGatherMODE = 0;
//DMA threshold
dcd.LocalToPciAlmostEmpty = 0;
dcd.LocalToPciAlmostFull = 0;
dcd.PciToLocalAlmostEmpty = 0;
dcd.PciToLocalAlmostFull = 0;
BOOLEAN bResult;
RETURN_CODE rc = DmaOpenSglChannel(pdx, 0, &dcd);
if (rc != RC_SUCCESS)
{
CompleteRequestInfo(pIrp, status, 0);
IoStartNextPacket(fdo, TRUE);
KdPrint((DBG_NAME "Can't DmaOpenBlockChannel.\n"));
}
// Switch on the IRP major function code
switch(pIrpStack->MajorFunction)
{
case IRP_MJ_WRITE:
//DMA Transfer Data
pdx->DmaInfo[0].bWriteToLocal = TRUE;
pMdl = pIrp->MdlAddress;
KeFlushIoBuffers(pMdl, FALSE, TRUE); //For Dma Transfer
status = (*pdx->DmaInfo[0].pDmaAdapterObject->DmaOperations->AllocateAdapterChannel)(
pdx->DmaInfo[0].pDmaAdapterObject,
fdo,
pdx->DmaInfo[0].lNumberOfMapRegisters,
(PDRIVER_CONTROL) AdapterControl, //ExecutionRoutine
pdx); //Context
if (!NT_SUCCESS(status))
{
CompleteRequestInfo(pIrp, status, 0);
IoStartNextPacket(fdo, TRUE);
}
return; //退出StartIo;
break;
case IRP_MJ_READ:
//DMA Transfer Data
pdx->DmaInfo[0].bWriteToLocal = FALSE;
pMdl = pIrp->MdlAddress;
KeFlushIoBuffers(pMdl, FALSE, TRUE); //For Dma Transfer
status = (*pdx->DmaInfo[0].pDmaAdapterObject->DmaOperations->AllocateAdapterChannel)(
pdx->DmaInfo[0].pDmaAdapterObject,
fdo,
pdx->DmaInfo[0].lNumberOfMapRegisters,
(PDRIVER_CONTROL) AdapterControl, //ExecutionRoutine
pdx); //Context
if (!NT_SUCCESS(status))
{
CompleteRequestInfo(pIrp, status, 0);
IoStartNextPacket(fdo, TRUE);
}
return;
break;
default:
status = STATUS_NOT_SUPPORTED;
break;
}
// Complete this IRP
if(pIrp->Cancel)
status = STATUS_CANCELLED;
// Remove cancel routine
KIRQL OldIrql;
IoAcquireCancelSpinLock( &OldIrql);
IoSetCancelRoutine(pIrp, NULL);
IoReleaseCancelSpinLock(OldIrql);
// Unlock device, complete IRP and start next
// UnlockDevice(pdx);
KdPrint((DBG_NAME "StartIo End.\n"));
CompleteRequestInfo(pIrp, STATUS_SUCCESS, 0);
IoStartNextPacket(fdo, TRUE);
} //StartIo
/******************************************************************************
*
* Function : CancelIrp
*
* Description: The CancelIrp Service Routine for PDC4000.
*
******************************************************************************/
VOID CancelIrp(IN PDEVICE_OBJECT fdo,
IN PIRP pIrp)
{ //CancelIrp
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)fdo->DeviceExtension;
KdPrint((DBG_NAME "WdmIoCancelIrp: Cancelling %x %I", pIrp, pIrp));
if (pIrp == fdo->CurrentIrp)
{
KdPrint((DBG_NAME "CancelIrp: IRP running in StartIo\n"));
// IRP is being processed by IoStartIo.
// Irp->Cancel flag already set.
// IoStartIo will detect Cancel flag and cancel IRP in due course
IoReleaseCancelSpinLock(pIrp->CancelIrql);
}
else
{
KdPrint((DBG_NAME "CancelIrp: IRP in StartIo queue.\n"));
// IRP is still in StartIo device queue.
// Just dequeue and cancel it. No need to start next IRP.
BOOLEAN dequeued = KeRemoveEntryDeviceQueue(
&fdo->DeviceQueue,
&pIrp->Tail.Overlay.DeviceQueueEntry);
IoReleaseCancelSpinLock(pIrp->CancelIrql);
if (dequeued)
{
UnlockDevice(pdx);
CompleteRequest(pIrp, STATUS_CANCELLED);
}
}
} //CancelIrp
/******************************************************************************
*
* Function : OnInterrupt //中断处理函数
*
* Description: The Interrupt Service Routine for the PLX device.
*
* Note : 中断处理函数工作在很高地级别,需要慎重处理
******************************************************************************/
BOOLEAN OnInterrupt(IN PKINTERRUPT pInterrupt,
IN PDEVICE_EXTENSION pdx)//IN PVOID pdx)
{ //OnInterrupt
ULONG lRegisterValue;
ULONG lAddress;
UCHAR cInterrupt;
UCHAR cCommand;
lAddress = (ULONG)((PDEVICE_EXTENSION)pdx)->LocalRegisterMemBase;
// Read interrupt status register.
lRegisterValue = READ_REGISTER_ULONG((ULONG *)(lAddress + PCI9054_INT_CTRL_STAT));
// Check for master PCI interrupt enable.
if ((lRegisterValue & 0x100) == 0) //Interupt Control/Status Register: 8
{
return FALSE; //如果不是该设备的中断,必须返回FALSE,否则系统会出问题。
}
KdPrint((DBG_NAME "On Interrupt!!!\n"));
KdPrint((DBG_NAME "ICS Register is 0x%X.\n", lRegisterValue));
// Check to see if an interrupt is active.
if ((lRegisterValue & 0x00200000)==0x00200000)//有DMA中断就通知应用程序
{
lRegisterValue &= (~0x100);//禁止所有的pci的中断
WRITE_REGISTER_ULONG((ULONG *)(lAddress + PCI9054_INT_CTRL_STAT), lRegisterValue);
KdPrint((DBG_NAME "Operate the Interrupt.\n"));
if (pdx->pWaitEvent != NULL)
KeSetEvent(pdx->pWaitEvent, 0, FALSE); //通知应用程序,中断的到来
if (pdx->DmaInfo[0].State == DMA_STATE_BLOCK)
{
KdPrint((DBG_NAME "Block DMA Interrupt!!!\n"));
WRITE_REGISTER_ULONG((ULONG *)(lAddress + PCI9054_DMA_COMMAND_STAT), 0x9);//把DMA通道0的中断标志清0
DmaCloseBlockChannel(pdx, 0, FALSE);
}
//打开中断
lRegisterValue |= 0x100;
WRITE_REGISTER_ULONG((ULONG *)(lAddress + PCI9054_INT_CTRL_STAT), lRegisterValue);
KdPrint((DBG_NAME "open the Interrupt.\n"));
return TRUE; //如果是该设备的中断,必须返回TRUE。
}
return FALSE;
} //OnInterrupt
/******************************************************************************
*
* Function : DpcForIsr
*
* Description: This routine will be triggered by the ISR to service an interrupt.
*
* Note : The 9052 supports Edge-triggerable interrupts as well as level
* triggered interrupts. The 9050 only supports level triggered
* interrupts. The interrupt masking code below handles both cases.
* If the chip is a 9050, the same code is used but should work
* ok since edge triggerable interrupts will always be disabled.
*
******************************************************************************/
VOID DpcForIsr(IN PKDPC pDpc,
IN PDEVICE_OBJECT fdo,
IN PIRP pIrp,
IN PDEVICE_EXTENSION pdx)
{ //OnInterrupt DpcForIsr
KdPrint((DBG_NAME "DpcForIsr Start.\n"));
if (pIrp->Cancel)
pdx->TransmitIrpStatus = STATUS_CANCELLED;
KIRQL OldIrql;
//Remove Cancel Routine.
IoAcquireCancelSpinLock(&OldIrql);
IoSetCancelRoutine(pIrp,NULL);
IoReleaseCancelSpinLock(OldIrql);
if (!LockDevice(pdx))
{
CompleteRequest(pIrp, STATUS_DELETE_PENDING);
}
KIRQL OriginalIrqL;
KeAcquireSpinLock(&(pdx->HardwareAccessLock), &OriginalIrqL);
ULONG lRegAddress = (ULONG)pdx->LocalRegisterMemBase;
// Read interrupt status register
ULONG lRegValue = READ_REGISTER_ULONG((ULONG *)(lRegAddress + PCI9054_INT_CTRL_STAT));
REG_DATA RegData;
ULONG lValue;
// Local Interrupt
if (lRegValue & (1 << 15))
{
// Setup to synchronize access to Interrupt Control/Status Register
RegData.lRegAddress = lRegAddress + PCI9054_INT_CTRL_STAT;
RegData.lBitsToSet = 0;
RegData.lBitsToClear = (1 << 11);
// Mask Local Interrupt 1
KeSynchronizeExecution(pdx->pInterruptObject,
(PKSYNCHRONIZE_ROUTINE)SynchronizedModifyRegister,
(VOID *)&RegData);
// if (pdx->pWaitEvent != NULL)
// KeSetEvent(pdx->pWaitEvent, 0, FALSE);
}
KeReleaseSpinLock(&(pdx->HardwareAccessLock), OriginalIrqL);
// Re-enable PCI interrupts
KeSynchronizeExecution(pdx->pInterruptObject,
(PKSYNCHRONIZE_ROUTINE)EnablePciInterrupt,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -