?? transfer.c
字號:
/*++
Copyright (c) 1997-1998 Microsoft Corporation
Module Name:
transfer.c
Abstract:
Author:
Steve Dziok (SteveDz)
Environment:
Kernel mode
Revision History:
--*/
#include "pcidma.h"
VOID
PciDmaStartIo(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
Start the IRP on the device. This driver allows only one I/O to
be active on the adapter at any one time. If multiple I/Os are sent
to the driver, they will be queued and completed as they complete on
the adapter (one IRP per interrupt).
Arguments:
DeviceObject - Object representing a particular adapter.
Irp - I/O request to be started.
Return Value:
None
--*/
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
PTRANSFER_INFO transferInfo = deviceExtension->TransferInfo;
NTSTATUS status;
//
// Start the I/O operation on the physical device.
//
//
// Save information for this particular data transfer. If more than
// one transfer is allowed per interrupt, this structure could be
// extended.
//
transferInfo->Irp = Irp;
transferInfo->CurrentVA = MmGetMdlVirtualAddress(Irp->MdlAddress);
transferInfo->ByteCount = MmGetMdlByteCount(Irp->MdlAddress);
transferInfo->WriteToDevice = irpStack->MajorFunction == IRP_MJ_WRITE ? TRUE : FALSE;
//
// Calculate the number of map registers. The size of this I/O request
// should have already been checked to make sure it can be handled by
// this adapter.
//
transferInfo->NumberOfMapRegisters =
ADDRESS_AND_SIZE_TO_SPAN_PAGES(transferInfo->CurrentVA,
transferInfo->ByteCount,
);
//
// Flush the memory region described by the MDL from the caches of all
// processors. This should be done before beginning the DMA operation.
//
KeFlushIoBuffers(Irp->MdlAddress,
irpStack->MajorFunction == IRP_MJ_READ ? TRUE : FALSE,
TRUE
);
DebugPrint((2,
"Starting IRP %8x \n",
Irp
));
DebugPrint((3,
"Map registers required: %x \n",
transferInfo->NumberOfMapRegisters
));
//
// Allocate the adapter channel and start the transfer.
//
status = IoAllocateAdapterChannel(deviceExtension->AdapterObject,
DeviceObject,
transferInfo->NumberOfMapRegisters,
BuildScatterGatherList,
NULL
);
if (!NT_SUCCESS(status)) {
DebugPrint((2,
"Completing IRP %8x \n",
Irp
));
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = 0;
IoStartNextPacket(DeviceObject, FALSE);
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
} // PciDmaStartIo
IO_ALLOCATION_ACTION
BuildScatterGatherList(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID MapRegisterBase,
IN PVOID Context
)
/*++
Routine Description:
Arguments:
DeviceObject - Object representing a particular adapter.
Irp - I/O request to be started.
MapRegisterBase - Pointer to map register base provided by the
operating system.
Context - Driver determined context information passed in from the
call to IoAllocateAdapterChannel. For this driver, this
value is NULL.
Return Value:
DeallocateObjectKeepRegisters - Required return value for busmaster
devices.
--*/
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
PTRANSFER_INFO transferInfo = deviceExtension->TransferInfo;
PCCHAR virtualAddress;
PSG_ENTRY sgEntry;
ULONG totalLength;
ULONG dataTransferLength;
BOOLEAN writeToDevice;
//
// Given the current IRP, find the correct transfer info. Since this
// driver handles only one IRP, the transfer info is the only one in
// the device extension.
//
ASSERT(Irp == transferInfo->Irp);
//
// Since this sample only supports one I/O on the device at a time, the
// SG list is stored in the device extension. If multiple I/O's are to
// be supported, this architecture must change.
//
sgEntry = deviceExtension->SGList;
//
// Save the map register base for the DPC.
//
transferInfo->MapRegisterBase = MapRegisterBase;
//
// Get the virtual address of the user's data buffer for the call
// to IoMapTransfer.
//
virtualAddress = transferInfo->CurrentVA;
writeToDevice = transferInfo->WriteToDevice;
dataTransferLength = transferInfo->ByteCount;
//
// While the total buffer has not been mapped, find each contiguous
// buffer and build a scatter/gather entry.
//
totalLength = 0;
while (totalLength < dataTransferLength) {
//
// Set the length to the length remaining to be mapped. On return
// from IoMapTransfer, this length may be adjusted to the length of
// the contiguous buffer.
//
sgEntry->Length = dataTransferLength - totalLength;
//
// Get the logical address (i.e. the mapped physical address) of
// the contiguous buffer.
//
sgEntry->LogicalAddress = IoMapTransfer(deviceExtension->AdapterObject,
Irp->MdlAddress,
MapRegisterBase,
(PCCHAR)virtualAddress + totalLength,
&sgEntry->Length,
writeToDevice);
DebugPrint((3,
" SGList: PA %08x : %08x Length %08x \n",
sgEntry->LogicalAddress.HighPart,
sgEntry->LogicalAddress.LowPart,
sgEntry->Length
));
//
// Adjust the total length mapped so far.
//
totalLength += sgEntry->Length;
//
// Point to the next scatter/gather entry.
//
sgEntry++;
}
//
// Tell the hardware to start the I/O. This needs to be done at DIRQL
// so the device doesn't interrupt in the middle of programming.
//
KeSynchronizeExecution(deviceExtension->InterruptObject,
StartIoSynchronized,
deviceExtension
);
//
// Busmaster devices should return DeallocateObjectKeepRegisters.
//
return DeallocateObjectKeepRegisters;
} // BuildScatterGatherList
BOOLEAN
StartIoSynchronized(
IN PVOID Context
)
/*++
Routine Description:
SyncCriticalSection routine used to program the device to start
the IRP. Note that this routine is run at DIRQL so the routines
that can be called are limited.
Arguments:
Context - Driver determined context information. For this driver,
the context is a pointer to the device extension.
Return Value:
TRUE
--*/
{
///////////////////////////////////////////////////////////////
//
// VENDOR_UNIQUE -- Vendor unique code -- START
//
///////////////////////////////////////////////////////////////
#ifdef VENDORID_1000_DEVICEID_0004
PDEVICE_EXTENSION deviceExtension = Context;
//
// Do whatever is necessary to start the I/O on the device. This
// routine is run at DIRQL so as to not be preempted by the device
// interrupting. Please insure this routine runs as quickly as possible.
//
//
// For this sample, just set an internal timer in the device to generate
// the interrupt so the IRP can be completed.
//
//
// This value is between 0x01 and 0x0f.
//
WRITE_UCHAR(TIMER1, deviceExtension->TimerPeriod);
#endif
///////////////////////////////////////////////////////////////
//
// VENDOR_UNIQUE -- Vendor unique code -- END
//
///////////////////////////////////////////////////////////////
return TRUE;
} // StartIoSynchronized
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -