📄 blockdmadevice.cpp
字号:
break;
default:
// Unrecognized IOCTL request
status = STATUS_INVALID_PARAMETER;
break;
}
// If the IRP was queued, or its IOCTL handler deferred processing using some
// driver specific scheme, the status variable is set to STATUS_PENDING.
// In this case we simply return that status, and the IRP will be completed
// later. Otherwise, complete the IRP using the status returned by the
// IOCTL handler.
if (status == STATUS_PENDING)
{
return status;
}
else
{
return I.PnpComplete(this, status);
}
}
////////////////////////////////////////////////////////////////////////
// BlockDMADevice::BlockDMA_IOCTL_800_Handler
//
// Routine Description:
// Handler for IO Control Code BlockDMA_IOCTL_800
//
// Parameters:
// I - IRP containing IOCTL request
//
// Return Value:
// NTSTATUS - Status code indicating success or failure
//
// Comments:
// This routine implements the BlockDMA_IOCTL_800 function.
// This routine runs at passive level.
//
NTSTATUS BlockDMADevice::BLOCKDMA_IOCTL_800_Handler(KIrp I)
{
NTSTATUS status = STATUS_SUCCESS;
t << "Entering BlockDMADevice::BlockDMA_IOCTL_800_Handler, " << I << EOL;
HANDLE hEvent=*(HANDLE*)I.IoctlBuffer();
if(m_pEventToSignal)
{
delete m_pEventToSignal;
m_pEventToSignal=NULL;
}
m_pEventToSignal=new(NonPagedPool)KEvent(hEvent,OBJECT_TYPE_ALL_ACCESS);
if(m_pEventToSignal==NULL)
{
status=STATUS_INSUFFICIENT_RESOURCES;
}
else
{
status=STATUS_SUCCESS;
// m_pEventToSignal->Initialize(SynchronizationEvent ,FALSE);
}
// TODO: Handle the the BlockDMA_IOCTL_800 request, or
// defer the processing of the IRP (i.e. by queuing) and set
// status to STATUS_PENDING.
// TODO: Assuming that the request was handled here. Set I.Information
// to indicate how much data to copy back to the user.
I.Information() = sizeof(ULONG);
return status;
}
////////////////////////////////////////////////////////////////////////
// BlockDMADevice::BlockDMA_IOCTL_801_Handler
//
// Routine Description:
// Handler for IO Control Code BlockDMA_IOCTL_801
//
// Parameters:
// I - IRP containing IOCTL request
//
// Return Value:
// NTSTATUS - Status code indicating success or failure
//
// Comments:
// This routine implements the BlockDMA_IOCTL_801 function.
// This routine runs at passive level.
//
NTSTATUS BlockDMADevice::BLOCKDMA_IOCTL_801_Handler(KIrp I)
{
// NTSTATUS status = STATUS_SUCCESS;
// t << "Entering BlockDMADevice::BlockDMA_IOCTL_801_Handler, " << I << EOL;
// TODO: Verify that the input parameters are correct
// If not, return STATUS_INVALID_PARAMETER
// TODO: Handle the the BlockDMA_IOCTL_801 request, or
// defer the processing of the IRP (i.e. by queuing) and set
// status to STATUS_PENDING.
// TODO: Assuming that the request was handled here. Set I.Information
// to indicate how much data to copy back to the user.
// I.Information() = 0;
/** NTSTATUS status = STATUS_SUCCESS;
//下面创建类实例m_CurrentTransfer,并初始化
// Create a new DMA transfer object for this IRP
m_CurrentTransfer = new(NonPagedPool) KDmaTransfer(this, &m_Dma);
if ( m_CurrentTransfer == NULL )
{
status = STATUS_INSUFFICIENT_RESOURCES;
DbgPrint("unable to allocate transfer object: %x\n", status);
I.Information() = 0;
// I.Status() = status;
// PnpNextIrp(I);
}
//下面采用应用程序的数据缓冲区作为DMA数据区
/* status = m_CurrentTransfer->Initiate(
I.Mdl(),
(I.MajorFunction() == IRP_MJ_READ) ? FromDeviceToMemory : FromMemoryToDevice,
LinkTo(OnDmaReady)
); //此操作将使系统调用OnDmaReady例程*/
// 下面采用公用缓冲区作为DMA数据区,这两种方法都可以
/** m_LocalAddress = *((PULONG)I.IoctlBuffer()); //读取应用程序中函数DeviceIoControl的输出缓冲区(应用程序传递给驱动的参数)数据
status = m_CurrentTransfer->Initiate(
this,
&m_Dma,
I.Mdl(),
FromDeviceToMemory ,//: FromMemoryToDevice,
LinkTo(OnDmaReady),
&m_Buffer
); //此操作将使系统调用OnDmaReady例程
// If the transfer cannot be initiated, complete it with an error status.
if ( ! NT_SUCCESS(status) )
{
DbgPrint("unable to initiate transfer: %x\n", status);
delete m_CurrentTransfer;
delete &m_LocalAddress;
m_CurrentTransfer = NULL;
I.Information() = 0;
// I.Status() = status;
// PnpNextIrp(I);
}
return status;
/* for(ULONG j=0;j<0xFFFFFF;j++)
{
m_IoPortRange2.outd(0xAA,0x0);
}
I.Information() = sizeof(ULONG);*/
/* KMemory Mem(I.Mdl());
ULONG reg;
ULONG *pBuf;
pBuf=(ULONG *)Mem.MapToSystemSpace();
// reg=m_IoPortRange1.ind(0x04);
reg=m_Bytes;
*pBuf=reg;
*/
/*初始化并启动DMA*/
ULONG Reg68 = 0;//Interrupt Control & Status Register
ULONG Reg80 = 0;//DMA Channel 0 Mode Register
ULONG Reg84 = 0;//DMA Channel 0 PCI Adress Register
ULONG Reg88 = 0;//DMA Channel 0 Local Adress Register
ULONG Reg8C = 0;//DMA Channel 0 Transfer Size(Bytes) Register
ULONG Reg90 = 0;//DMA Channel 0 Descriptor Pointer Register
UCHAR RegA8 = 0;//DMA Channel 0 Command/Status Register
Reg68 = 0x00040180;
m_IoPortRange1.outd(0x68,Reg68);//Enable Dma Channel0 INT
// m_IoPortRange1.outd(MBRAR,0x280000); //dma通道优先级设置
Reg80 = 0x000205C3; //BTERM=1,BURST=1
m_IoPortRange1.outd(0x80 , Reg80);
/*在不使用commonbuffer的情况下*/
// PTRANSFER_DESCRIPTOR ptd;
// while(m_CurrentTransfer->SequenceTransferDescriptors(&ptd))
// {
// }
// Reg84=(ULONG)ptd->td_PhysAddr.LowPart;
/*在不使用commonbuffer的情况下*/
// KMemory Mem(I.Mdl());
// ULONG ptd=(ULONG )Mem.MapToSystemSpace();
m_IoPortRange1.outd(0x84 , Reg84);
Reg88 = 0xed000000;
m_IoPortRange1.outd(0x88 , Reg88);
Reg8C = 0x400000;//16384 * 4;0x7FFFFF
m_IoPortRange1.outd(0x8c , Reg8C);// set dma count(bytes)
Reg90 = 0x8;
m_IoPortRange1.outd(0x90 , Reg90);
RegA8 = 0x03;
m_IoPortRange1.outb(0xA8 , RegA8);
// I.Information() = 0;
return STATUS_SUCCESS;
}
////////////////////////////////////////////////////////////////////////
// BlockDMADevice::BlockDMA_IOCTL_802_Handler
//
// Routine Description:
// Handler for IO Control Code BlockDMA_IOCTL_802
//
// Parameters:
// I - IRP containing IOCTL request
//
// Return Value:
// NTSTATUS - Status code indicating success or failure
//
// Comments:
// This routine implements the BlockDMA_IOCTL_802 function.
// This routine runs at passive level.
//
NTSTATUS BlockDMADevice::BLOCKDMA_IOCTL_802_Handler(KIrp I)
{
NTSTATUS status = STATUS_SUCCESS;
t << "Entering BlockDMADevice::BlockDMA_IOCTL_802_Handler, " << I << EOL;
ULONG *pp=(ULONG *)I.IoctlBuffer();
if(pp!=NULL)
{
ULONG index=*(ULONG *)pp;
ULONG Regvalue=m_IoPortRange3.ind(index);
KMemory Mem(I.Mdl());
ULONG *ret=(ULONG *)Mem.MapToSystemSpace();
*ret=Regvalue;
I.Information()=sizeof(ULONG);
status=STATUS_SUCCESS; //缓冲区方式
}
else
{
status=STATUS_UNSUCCESSFUL;
}
return status;
}
////////////////////////////////////////////////////////////////////////
// BlockDMADevice::BlockDMA_IOCTL_803_Handler
//
// Routine Description:
// Handler for IO Control Code BlockDMA_IOCTL_803
//
// Parameters:
// I - IRP containing IOCTL request
//
// Return Value:
// NTSTATUS - Status code indicating success or failure
//
// Comments:
// This routine implements the BlockDMA_IOCTL_803 function.
// This routine runs at passive level.
//
NTSTATUS BlockDMADevice::BLOCKDMA_IOCTL_803_Handler(KIrp I)
{
NTSTATUS status = STATUS_SUCCESS;
t << "Entering BlockDMADevice::BlockDMA_IOCTL_803_Handler, " << I << EOL;
// TODO: Verify that the input parameters are correct
// If not, return STATUS_INVALID_PARAMETER
// TODO: Handle the the BlockDMA_IOCTL_803 request, or
// defer the processing of the IRP (i.e. by queuing) and set
// status to STATUS_PENDING.
// TODO: Assuming that the request was handled here. Set I.Information
// to indicate how much data to copy back to the user.
// I.Information() = 0;
//测试是否可以复位9054
long m_reset;
m_reset=m_IoPortRange1.ind(0X6C);
t<<"输出当前CNTRL寄存器的值"<<m_reset<<EOL;
m_reset=0X4180F767; //复位9054
m_IoPortRange1.outd(0X6C,m_reset) ;
t<<"向CNTRL寄存器写入"<<m_reset<<EOL;
m_reset=m_IoPortRange1.ind(0X6C);
t<<"向CNTRL寄存器写入复位信息后再次读出的值是"<<m_reset<<EOL;
m_IoPortRange1.outd(0X6C,0X200F767E) ;
t<<"清除复位标志,重新加载EEPROM的信息到9054"<<m_reset<<EOL;
m_reset=m_IoPortRange1.ind(0X6C);
t<<"察看复位标志位是否被清除,以及EEPROM加载标志是否有效"<<m_reset<<EOL;
m_IoPortRange1.outd(0X6C,0X000F767E) ;
t<<"加载EEPROM结束"<<EOL;
I.Information()=sizeof(ULONG);
return status;
}
NTSTATUS BlockDMADevice::BLOCKDMA_IOCTL_804_Handler(KIrp I)
{
NTSTATUS status=STATUS_SUCCESS;
ULONG *pp=(ULONG *)I.IoctlBuffer();
if(pp!=NULL)
{
ULONG index=*(ULONG *)pp;
ULONG Regvalue=*(ULONG *)(pp+1);
m_IoPortRange3.outd(index,Regvalue);
t<<"Enter 804 address = "<<index<<" "<<Regvalue<<EOL;
I.Information()=sizeof(ULONG);
status=STATUS_SUCCESS; //缓冲区方式
}
else
{
status=STATUS_UNSUCCESSFUL;
}
return status;
}
////////////////////////////////////////////////////////////////////////
// BlockDMADevice::DpcFor_Irq
//
// Routine Description:
// Deferred Procedure Call (DPC) for Irq
//
// Parameters:
// Arg1 - User-defined context variable
// Arg2 - User-defined context variable
//
// Return Value:
// None
//
// Comments:
// This function is called for secondary processing of an interrupt.
// Most code that runs at elevated IRQL should run here rather than
// in the ISR, so that other interrupt handlers can continue to run.
//
VOID BlockDMADevice::DpcFor_Irq(PVOID Arg1, PVOID Arg2)
{
t<<"延时过程调用 "<<EOL;
m_CurrentTransfer->Continue(UseTransferSize);
}
////////////////////////////////////////////////////////////////////////
// BlockDMADevice::Isr_Irq
//
// Routine Description:
// Interrupt Service Routine (ISR) for IRQ Irq
//
// Parameters:
// None
//
// Return Value:
// BOOLEAN True if this is our interrupt
//
// Comments:
//
BOOLEAN BlockDMADevice::Isr_Irq(void)
{
//第3 步 DMA 传输结束 中断服务子程序
t<<"第3 步 DMA 传输结束 ,中断服务子程序 "<<EOL;
ULONG status;
status= m_IoPortRange1.ind(INTCSR);
if ((status & 0x200000)==0)
{
return FALSE;
}
//清除中断
m_IoPortRange1.outd(DMAMODE0,0x201C3);
m_IoPortRange1.outb(DMACSR0,0x18);
if(!m_DpcFor_Irq.Request(NULL,NULL)){}
return TRUE;
// m_pEventToSignal->Set();
//m_IoPortRange1.outd(0x84 , m_PAddr);
// m_IoPortRange1.outd(0x80 , 0x000205C3);
// m_IoPortRange1.outb(0xA8 , 0x03);
// m_Bytes=m_Bytes+0x100000;
}
VOID BlockDMADevice::StartDMA(ULONG PAddress,ULONG NBytes)
{
//Channel0 interrupt to the PCI Bus interrupt,Done Interrupt Enable,FIFO;
/*初始化并启动DMA*/
t<<"The StartDma function Called"<<EOL;
ULONG Reg68 = 0x00040180;
m_IoPortRange1.outd(0x68,Reg68);//Enable Dma Channel0 INT
ULONG Reg80 = 0x000205C3; //BTERM=1,BURST=1
m_IoPortRange1.outd(0x80 , Reg80);//DMA Channel 0 Mode
ULONG Reg84 = PAddress;
m_IoPortRange1.outd(0x84 , Reg84);//DMA Channel 0 PCI Adress Register
ULONG Reg88 = 0xed000000;
m_IoPortRange1.outd(0x88 , Reg88); //DMA Channel 0 Local Adress Register
ULONG Reg8C = NBytes;
m_IoPortRange1.outd(0x8c , Reg8C);// DMA Channel 0 set dma count(bytes)
ULONG Reg90 = 0x8;
if(m_ReadWrite==2) Reg90 = 0x0;
m_IoPortRange1.outd(0x90 , Reg90);//DMA Channel 0 Descriptor Pointer Register
UCHAR RegA8 = 0x03;
m_IoPortRange1.outb(0xA8 , RegA8);//DMA Channel 0 Command/Status Register
}
VOID BlockDMADevice::OnDmaReady(KDmaTransfer* pXfer, KIrp I)
{
// All KDmaTransfer callbacks must first check to see if there are any bytes
// left to transfer.
if(m_ReadWrite==1){
LONG Bytes=pXfer->BytesRemaining();
if (Bytes == 0)
{ //第四步,DMA结束,完成IRP
// If there are no bytes left to transfer, the callback must call
// Terminate(). Then it completes the IRP with STATUS_SUCCESS.
pXfer->Terminate();
t<<"第4步 DMA传输结束 ,完成IRP"<<EOL;
I.Information() = I.ReadSize(CURRENT);
I.Status() = STATUS_SUCCESS;
PnpNextIrp(I);
m_CurrentTransfer = NULL;
delete pXfer;
m_pEventToSignal->Set();
return;
}
// else if(Bytes==I.ReadSize(CURRENT))
//下面是第二步,获取要传输的物理内存的地址和字节数,调用StartDMA例程
PTRANSFER_DESCRIPTOR ptd;
while (pXfer->SequenceTransferDescriptors(&ptd)) {
// program the h/w using ppTD
t << " Physical address 0x" << ptd->td_PhysAddr.LowPart << ". Length is 0x"
<< ptd->td_Length << "." << EOL;
}
// If this is the first time through, then start the DMA going.
// We only want to do this ONCE for a given Read transfer. That
// way, our data will be collected smoothly, without interruptions
// or dropouts. ptd->td_Length
if ((ULONG) pXfer->BytesRemaining() == I.ReadSize()){
t<<"第2步 启动 StartDMA"<<EOL;
StartDMA(ptd->td_PhysAddr.LowPart,ptd->td_Length);
}
}else if(m_ReadWrite==2){
LONG Bytes=pXfer->BytesRemaining();
if (Bytes == 0)
{ //第四步,DMA结束,完成IRP
// If there are no bytes left to transfer, the callback must call
// Terminate(). Then it completes the IRP with STATUS_SUCCESS.
pXfer->Terminate();
t<<"第4步 DMA传输结束 ,完成IRP"<<EOL;
I.Information() = I.WriteSize(CURRENT);
I.Status() = STATUS_SUCCESS;
PnpNextIrp(I);
m_CurrentTransfer = NULL;
delete pXfer;
return;
}
//下面是第二步,获取要传输的物理内存的地址和字节数,调用StartDMA例程
PTRANSFER_DESCRIPTOR ptd;
while (pXfer->SequenceTransferDescriptors(&ptd)) {
// program the h/w using ppTD
t << " Physical address 0x" << ptd->td_PhysAddr.LowPart << ". Length is 0x"
<< ptd->td_Length << "." << EOL;
}
// If this is the first time through, then start the DMA going.
// We only want to do this ONCE for a given Read transfer. That
// way, our data will be collected smoothly, without interruptions
// or dropouts. ptd->td_Length
if ((ULONG) pXfer->BytesRemaining() == I.WriteSize()){
t<<"第2步 启动 StartDMA"<<EOL;
StartDMA(ptd->td_PhysAddr.LowPart,ptd->td_Length);
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -