📄 d9054device.cpp
字号:
// TODO: If the write can be satisfied immediately, set the Information
// and Status fields now, then call NextIrp to complete this IRP
// and start processing the next IRP in the queue.
// TODO: If the device cannot accept all of the data yet, initiate a
// request to the physical device here, and defer the Information,
// Status, and NextIrp handling until the hardware indicates that
// the write is complete. Typically, this might be handled in a
// DPC that is called after the hardware finishes transferring
// the data.
// TODO: To satisfy the write now, transfer data to the device
// from caller's buffer at "pBuffer". Then, indicate how much
// data was transferred:
I.Information() = 0;
I.Status() = status;
// PnpNextIrp completes this IRP and starts
// processing for the next IRP in the queue.
PnpNextIrp(I);
}
////////////////////////////////////////////////////////////////////////
// D9054Device::Write
//
// Routine Description:
// Handler for IRP_MJ_WRITE
//
// Parameters:
// I - Current IRP
//
// Return Value:
// NTSTATUS - Result code
//
// Comments:
// This routine handles write requests.
// The requests are queued to the StartIo
// queue. This enforces serialization so that
// multiple requests are not processed
// simultaneously.
//
// The KPnpDevice class handles restricting IRP flow
// if the device is stopping or being removed.
//
NTSTATUS D9054Device::Write(KIrp I)
{
t << "Entering D9054Device::Write, " << I << EOL;
// TODO: Check the incoming request. Replace "FALSE" in the following
// line with a check that returns TRUE if the request is not valid.
if (FALSE)
{
// Invalid parameter in the Write request
I.Information() = 0;
return I.PnpComplete(this, STATUS_INVALID_PARAMETER);
}
// Always ok to write 0 elements.
if (I.WriteSize() == 0)
{
I.Information() = 0;
return I.PnpComplete(this, STATUS_SUCCESS);
}
// Queue the IRP for processing in StartIO
// The write function is performed in SerialWrite
return QueueIrp(I, LinkTo(CancelQueuedIrp));
}
////////////////////////////////////////////////////////////////////////
// D9054Device::DeviceControl
//
// Routine Description:
// Handler for IRP_MJ_DEVICE_CONTROL
//
// Parameters:
// I - Current IRP
//
// Return Value:
// None
//
// Comments:
// This routine is the first handler for Device Control requests.
// Some function codes may be handled immediately,
// while others may be serialized through the StartIo routine.
//
// The KPnpDevice class handles restricting IRP flow
// if the device is stopping or being removed.
//
NTSTATUS D9054Device::DeviceControl(KIrp I)
{
NTSTATUS status;
t << " Entering DeviceControl "<< I.IoctlCode();
switch (I.IoctlCode())
{
case EVENT_SET:
{
t<<" \nEVENT_SET\n\n";
t<<"INTCSR ="<<m_IoPortRange0.ind(INTCSR)<<"\n";
m_IoPortRange0.outd(INTCSR,0x40100);
HANDLE hEvent = *(HANDLE*)I.IoctlBuffer();
if (m_pEvent)
{
delete m_pEvent;
m_pEvent = NULL;
}
m_pEvent = new (NonPagedPool) KEvent(hEvent);
status = ( m_pEvent != NULL ) ? STATUS_SUCCESS:STATUS_INSUFFICIENT_RESOURCES ;
bRec = TRUE ;
m_pEvent->Set();
return I.Complete(status);
}
break;
case READ_RGS:
{
t<<"\n\nREAD_RGS bRec="<<bRec<<"\n\n";
bRec = FALSE ;
return STATUS_SUCCESS;
}
case EVENT_CANCEL:
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);
}
}
////////////////////////////////////////////////////////////////////////
// D9054Device::EVENT_SET_Handler
//
// Routine Description:
// Handler for IO Control Code EVENT_SET
//
// Parameters:
// I - IRP containing IOCTL request
//
// Return Value:
// NTSTATUS - Status code indicating success or failure
//
// Comments:
// This routine implements the EVENT_SET function.
// This routine runs at passive level.
//
NTSTATUS D9054Device::EVENT_SET_Handler(KIrp I)
{
NTSTATUS status = STATUS_SUCCESS;
// t << "Entering D9054Device::EVENT_SET_Handler, " << I << EOL;
I.Information() = 0;
return status;
}
////////////////////////////////////////////////////////////////////////
// D9054Device::EVENT_CANCEL_Handler
//
// Routine Description:
// Handler for IO Control Code EVENT_CANCEL
//
// Parameters:
// I - IRP containing IOCTL request
//
// Return Value:
// NTSTATUS - Status code indicating success or failure
//
// Comments:
// This routine implements the EVENT_CANCEL function.
// This routine runs at passive level.
//
NTSTATUS D9054Device::EVENT_CANCEL_Handler(KIrp I)
{
NTSTATUS status = STATUS_SUCCESS;
// t << "Entering D9054Device::EVENT_CANCEL_Handler, " << I << EOL;
/////// 事件取消 //////////
///////事件取消//////////
I.Information() = 0;
return status;
}
////////////////////////////////////////////////////////////////////////
// D9054Device::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 D9054Device::DpcFor_Irq(PVOID Arg1, PVOID Arg2)
{
// TODO: Typically, the interrupt signals the end of a data transfer
// operation for a READ or WRITE operation. The following code
// assumes the driver will handle the completion of the IRP
// associated with this operation here. It further assumes that the
// IRP to be completed is the current IRP on the device queue. Modify
// or replace the code here to handle the function of your DPC.
t<<"\n Enter DPC !!!!!!! \n";
m_CurrentTransfer->Continue(UseTransferSize);
UNREFERENCED_PARAMETER(Arg1);
UNREFERENCED_PARAMETER(Arg2);
}
////////////////////////////////////////////////////////////////////////
// D9054Device::Isr_Irq
//
// Routine Description:
// Interrupt Service Routine (ISR) for IRQ Irq
//
// Parameters:
// None
//
// Return Value:
// BOOLEAN True if this is our interrupt
//
// Comments:
//
BOOLEAN D9054Device::Isr_Irq(void)
{
// TODO: Verify that the interrupt was caused by our device.
// Replace "TRUE" in next line with actual test.
t<<" Enter ISR_IRQ() !!! "<<bRec<<"\n";
ULONG status;
status= m_IoPortRange0.ind(INTCSR); // 读中断状态寄存器
if( status & 0x8000 ) // pci
{
t<<"PCI int "<<bRec<<"\n";
m_IoPortRange0.outd(INTCSR,0x40100);
if( m_pEvent )
{
m_pEvent->Set();
}
else
{
t<<"end of rec \n";
}
return TRUE;
}
else if ((status & 0x200000)==0) // dma
{
return FALSE;
}
else if(status & 0x200000)
{
t<<"DMA int "<<bRec<<"\n";
if( m_pEvent )
{
m_pEvent->Clear();
}
m_IoPortRange0.outd(DMAMODE0,0x20800); // 禁止中断
m_IoPortRange0.outb(DMACSR0,0x10);// 0x18 ?????? Clear Interrupt
m_IoPortRange0.outd(INTCSR,0x40900);
if (!m_DpcFor_Irq.Request(NULL, NULL))
{
}
}
// Return TRUE to indicate that our device caused the interrupt
return TRUE;
}
VOID D9054Device::StartDMA(ULONG PAddress,ULONG NBytes)
{
t<<" Enter StartDMA !!!\n";
/* t<<"\nINSTCR-> "<<m_IoPortRange0.ind(INTCSR);
t<<"\nDMAMODE0-> "<<m_IoPortRange0.ind(DMAMODE0);
t<<"\nDMAPADR0-> "<<m_IoPortRange0.ind(DMAPADR0);
t<<"\nDMALADR0-> "<<m_IoPortRange0.ind(DMALADR0);
t<<"\nDMASIZ0-> "<<m_IoPortRange0.ind(DMASIZ0);
t<<"\nDMADPR0-> "<<m_IoPortRange0.ind(DMADPR0);
t<<"\nDMACSR0-> "<<m_IoPortRange0.inb(DMACSR0);
*/
//下面几条语句设置DMA通道0寄存器,启动块传输方式,从FIFO读数据
//Channel0 interrupt to the PCI Bus interrupt,Done Interrupt Enable,FIFO
m_IoPortRange0.outd(DMAMODE0,0x20DC3); //
//DMA Channel0 PCI Address
m_IoPortRange0.outd(DMAPADR0,PAddress);
//DMA Channel0 Local Address,自己设计的FIFO地址
m_IoPortRange0.outd(DMALADR0,0x8);
//DMA Channel0 Transfer Size(Bytes)
m_IoPortRange0.outd(DMASIZ0,NBytes);
//from the Local Bus to the PCI Bus
m_IoPortRange0.outd(DMADPR0,0x8);
//Channel0 Enable,Start p284
m_IoPortRange0.outb(DMACSR0,0x3);
/* t<<"\nINSTCR-> "<<m_IoPortRange0.ind(INTCSR);
t<<"\nDMAMODE0-> "<<m_IoPortRange0.ind(DMAMODE0);
t<<"\nDMAPADR0-> "<<m_IoPortRange0.ind(DMAPADR0);
t<<"\nDMALADR0-> "<<m_IoPortRange0.ind(DMALADR0);
t<<"\nDMASIZ0-> "<<m_IoPortRange0.ind(DMASIZ0);
t<<"\nDMADPR0-> "<<m_IoPortRange0.ind(DMADPR0);
t<<"\nDMACSR0-> "<<m_IoPortRange0.inb(DMACSR0);
*/
}
VOID D9054Device::OnDmaReady(KDmaTransfer* pXfer, KIrp I)
{
// All KDmaTransfer callbacks must first check to see if there are any bytes
// left to transfer.
t<<"Enter OnDmaReady\n";
if (pXfer->BytesRemaining() == 0)
{
// If there are no bytes left to transfer, the callback must call
// Terminate(). Then it completes the IRP with STATUS_SUCCESS.
if( !bRec )
{
t<<"\nbRec = FALSE\n";
}
pXfer->Terminate();
I.Information() = I.ReadSize(CURRENT);
I.Status() = STATUS_SUCCESS;
PnpNextIrp(I);
m_CurrentTransfer = NULL;
delete pXfer;
return;
}
// We must get the descriptor for the physical memory location for
// the DMA transfer.
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.
if ((ULONG) pXfer->BytesRemaining() == I.ReadSize())
StartDMA(ptd->td_PhysAddr.LowPart,ptd->td_Length);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -