阅读:1422回复:0
请问OnDmaReady究竟何时被调用?
对于NT下DriverWorks开发驱动程序,我对LinkTo()始终很模糊,不知道被LINK的函数究竟被谁调用,何时调用。如写一个执行DMA的驱动,常要创建一个KDmaAdapter、KDmaTransfer派生的类。然后执行以下操作:
void DMASampleDevice::SerialRead(KIrp I) { NTSTATUS status = STATUS_SUCCESS; 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); } status = m_CurrentTransfer->Initiate( this, &m_Dma, I.Mdl(), (I.MajorFunction() == IRP_MJ_READ) ? FromDeviceToMemory : FromMemoryToDevice, LinkTo(OnDmaReady), &m_Buffer ); // 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; m_CurrentTransfer = NULL; I.Information() = 0; I.Status() = status; PnpNextIrp(I); } } VOID DMASampleDevice::OnDmaReady(KDmaTransfer* pXfer, KIrp I) { t << "Entering OnDmaReady\n"; // All KDmaTransfer callbacks must first check to see if there are any bytes // left to transfer. 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. t << "terminating transfer\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); } 对于上述代码,OnDmaReady究竟在什么情况下被调用?如果硬件支持分散/集中DMA,而且只有当所有的数据(可能不止一个数据块)传输完毕时才产生中断,传完一个数据块也不需驱动去设置硬件的地址或长度寄存器(硬件自己会执行此操作),还会调用它么? |
|