📄 readwrite.cpp
字号:
PIRP junk, \
PVOID MapRegisterBase, \
PVOID Context)
{
KdPrint(("SIWDM - Entering SheldonWriteAdapterControl\n"));
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) Context;
PIRP Irp = GetCurrentIrp(&pdx->dqReadWrite);
PMDL Mdl = Irp->MdlAddress;
PULONG OP = pdx->base[AMCC_OPREGS];
ULONG intCSR;
pdx->WriteTransfer.BytesRequested = MmGetMdlByteCount(Mdl);
pdx->WriteTransfer.BytesRemaining = pdx->WriteTransfer.BytesRequested;
pdx->WriteTransfer.LogicalAddress = (UCHAR *) MmGetMdlVirtualAddress(Mdl);
pdx->WriteTransfer.MapRegisterBase = MapRegisterBase;
pdx->WriteTransfer.Mdl = Mdl;
// We now have the physical address and size of the first chunk to send
// Let's now set up the PCI hardware so that when we load MWTC and MWAR
// a transfer will occur
/////////////////
// IO and memory mapped
/////////////////
if( (ULONG)pdx->base[AMCC_OPREGS] & 0xffff0000 ) {
// Disable PCI FIFO to Add-on Bus Mastering by MCSR bit 14 set to 0
OP[AMCC_MCSR] &= ~AMCC_BUSMASTERED_WRITE_ENABLE_MASK;
intCSR = OP[AMCC_INTCSR] & AMCC_PRESERVE_INTCSR_MASK;
// Disable Ints from Transfer Count = 0 by INTCSR bits 14 15 both zeroed
OP[AMCC_INTCSR] = intCSR & ~AMCC_BUSMASTERED_WRITE_INT_ENABLE_MASK;
// Clear FIFO by MCSR bit 25 written with one
// Will clear fifo before every transfer if executed(implementation dependent)
// OP[AMCC_MCSR] |= AMCC_BUSMASTERED_WRITE_CLEAR_FIFO_MASK;
// Write zero into the MWTC
OP[AMCC_MRTC]=0x0000;
// Define FIFO Management Scheme as go-on-half-way (4 words) by MCSR bit 13 written as 1
OP[AMCC_MCSR] |= 0x00002000;
// Define Read-Write Priority as equal by bits 8 and 12 written as 1
OP[AMCC_MCSR] = (OP[AMCC_MCSR] | 0x00001000) & ~0x00000100;
// Set the transfer flag before allowing ints
pdx->WriteTransfer.TransferInProgress = TRUE;
// Ok, let's do the first call to the code which loads the registers and (re)starts
// the transfer. Later calls will be made by the DPC after each interrupt, until
// the transfer is complete.
DoBusMasteredWrite(pdx);
// Now re-enable the interrupts and set TIProgress
intCSR = OP[AMCC_INTCSR] & AMCC_PRESERVE_INTCSR_MASK;
// Enable Ints from Transfer Count = 0 by INTCSR bits 14 15 both zeroed
OP[AMCC_INTCSR] = intCSR | AMCC_BUSMASTERED_WRITE_INT_ENABLE_MASK;
// Enable Add-on to PCI FIFO Bus Mastering by MCSR bit 14 set 1
OP[AMCC_MCSR] |= AMCC_BUSMASTERED_WRITE_ENABLE_MASK;
}
else {
// Disable PCI FIFO to Add-on Bus Mastering by MCSR bit 14 set to 0
WRITE_PORT_ULONG(OP + AMCC_MCSR, READ_PORT_ULONG(OP + AMCC_MCSR) & ~AMCC_BUSMASTERED_WRITE_ENABLE_MASK );
intCSR = READ_PORT_ULONG(OP + AMCC_INTCSR) & AMCC_PRESERVE_INTCSR_MASK;
// Disable Ints from Transfer Count = 0 by INTCSR bits 14 15 both zeroed
WRITE_PORT_ULONG(OP + AMCC_INTCSR, intCSR & ~AMCC_BUSMASTERED_WRITE_INT_ENABLE_MASK);
// Clear FIFO by MCSR bit 25 written with one
// Will clear fifo before every transfer if executed(implementation dependent)
// OP[AMCC_MCSR] |= AMCC_BUSMASTERED_WRITE_CLEAR_FIFO_MASK;
// Write zero into the MWTC
WRITE_PORT_ULONG(OP + AMCC_MRTC, 0x0000);
// Define FIFO Management Scheme as go-on-half-way (4 words) by MCSR bit 13 written as 1
WRITE_PORT_ULONG(OP + AMCC_MCSR, READ_PORT_ULONG(OP + AMCC_MCSR) | 0x00002000);
// Define Read-Write Priority as equal by bits 8 and 12 written as 1
WRITE_PORT_ULONG(OP + AMCC_MCSR, (READ_PORT_ULONG(OP + AMCC_MCSR) | 0x00001000) & ~0x00000100);
// Set the transfer flag before allowing ints
pdx->WriteTransfer.TransferInProgress = TRUE;
// Ok, let's do the first call to the code which loads the registers and (re)starts
// the transfer. Later calls will be made by the DPC after each interrupt, until
// the transfer is complete.
DoBusMasteredWrite(pdx);
// Now re-enable the interrupts and set TIProgress
intCSR = READ_PORT_ULONG(OP + AMCC_INTCSR) & AMCC_PRESERVE_INTCSR_MASK;
// Enable Ints from Transfer Count = 0 by INTCSR bits 14 15 both zeroed
WRITE_PORT_ULONG(OP + AMCC_INTCSR, intCSR | AMCC_BUSMASTERED_WRITE_INT_ENABLE_MASK);
// Enable Add-on to PCI FIFO Bus Mastering by MCSR bit 14 set 1
WRITE_PORT_ULONG(OP + AMCC_MCSR, READ_PORT_ULONG(OP + AMCC_MCSR) | AMCC_BUSMASTERED_WRITE_ENABLE_MASK);
}
KdPrint(("SIWDM - Exiting SheldonWriteAdapterControl\n"));
return DeallocateObjectKeepRegisters;
}
/*
Function Name:
DoBusMasteredRead
Routine Description:
Perform a BusMastered Read.
Arguments:
pdx - pointer to a device extension
Return Value:
TRUE
*/
BOOLEAN DoBusMasteredRead(IN PDEVICE_EXTENSION pdx)
{
PULONG OP = pdx->base[AMCC_OPREGS];
PHYSICAL_ADDRESS PhysicalAddress;
LARGE_INTEGER When = {-1,-5000000};
KdPrint(("SIWDM - Entering DoBusMasteredRead\n"));
// LogicalAddress and BytesRemaining must be set before calling this
// function
pdx->ReadTransfer.CurrentTransferSize = pdx->ReadTransfer.BytesRemaining;
PhysicalAddress =
pdx->ReadTransfer.Adapter->DmaOperations->MapTransfer
(
pdx->ReadTransfer.Adapter,
pdx->ReadTransfer.Mdl,
pdx->ReadTransfer.MapRegisterBase,
pdx->ReadTransfer.LogicalAddress,
&pdx->ReadTransfer.CurrentTransferSize,
FALSE
);
// if current transfer size is 0, then cannot get physical addr.
if ( pdx->ReadTransfer.CurrentTransferSize == 0 )
{
KdPrint
((
"%s%s",
"SIWDM - DoBusMasteredRead: ERROR - ",
"pdx->ReadTransfer.CurrentTransferSize == 0\n"
));
When.QuadPart = 1;
KeSetTimer
(
&pdx->ReadTransfer.Timer, When, &pdx->ReadTransfer.TimerDPC
);
return FALSE;
}
// convert to microseconds & relative
When.QuadPart = (ULONGLONG) pdx->Timeout_ms * (LONGLONG) -10000L;
if(pdx->Timeout_ms != 0)
KeSetTimer(&pdx->ReadTransfer.Timer, When, &pdx->ReadTransfer.TimerDPC);
// Load MWAR and MWTC for this chunk
/////////////////
// IO and memory mapped
/////////////////
if( (ULONG)pdx->base[AMCC_OPREGS] & 0xffff0000 ) {
// Write the address into the MWAR
OP[AMCC_MWAR] = PhysicalAddress.LowPart;
// Write the count (BYTES) into the MWTC
OP[AMCC_MWTC] = pdx->ReadTransfer.CurrentTransferSize;
}
else {
// Write the address into the MWAR
WRITE_PORT_ULONG(OP + AMCC_MWAR, PhysicalAddress.LowPart );
// Write the count (BYTES) into the MWTC
WRITE_PORT_ULONG(OP + AMCC_MWTC, pdx->ReadTransfer.CurrentTransferSize );
}
// The transfer (re)starts now and will interrupt when this chunk is done
// but if it doesn't, the timer will let us know.
KdPrint(("SIWDM - Exiting DoBusMasteredRead\n"));
return TRUE;
}
/*
Function Name:
DoBusMasteredWrite
Routine Description:
Perform a BusMastered Write.
Arguments:
pdx - pointer to a device extension
Return Value:
TRUE
*/
BOOLEAN DoBusMasteredWrite(IN PDEVICE_EXTENSION pdx)
{
PULONG OP = pdx->base[AMCC_OPREGS];
PHYSICAL_ADDRESS PhysicalAddress;
LARGE_INTEGER When;
KdPrint(("SIWDM - Entering DoBusMasteredWrite\n"));
// LogicalAddress and BytesRemaining must be set before calling this
// function
pdx->WriteTransfer.CurrentTransferSize = pdx->WriteTransfer.BytesRemaining;
PhysicalAddress =
pdx->WriteTransfer.Adapter->DmaOperations->MapTransfer
(
pdx->WriteTransfer.Adapter,
pdx->WriteTransfer.Mdl,
pdx->WriteTransfer.MapRegisterBase,
pdx->WriteTransfer.LogicalAddress,
&pdx->WriteTransfer.CurrentTransferSize,
TRUE
);
// if current transfer size is 0, then cannot get physical addr.
if ( pdx->WriteTransfer.CurrentTransferSize == 0 )
{
KdPrint
((
"%s%s",
"SIWDM - DoBusMasteredWrite: ERROR - ",
"pdx->WriteTransfer.CurrentTransferSize == 0\n"
));
When.QuadPart = 1;
KeSetTimer
(
&pdx->ReadTransfer.Timer, When, &pdx->ReadTransfer.TimerDPC
);
return FALSE;
}
// convert to microseconds & relative
When.QuadPart = (ULONGLONG) pdx->Timeout_ms * (LONGLONG) -10000L;
KdPrint
((
"SIWDM - DoBusMasteredWrite: Timer = 0x%x\n",
&pdx->WriteTransfer.Timer
));
KdPrint
((
"SIWDM - DoBusMasteredWrite: TimerDPC = 0x%x\n",
&pdx->WriteTransfer.TimerDPC
));
if(pdx->Timeout_ms != 0)
KeSetTimer(&pdx->WriteTransfer.Timer, When, &pdx->WriteTransfer.TimerDPC);
// Load MRAR and MRTC for this chunk
/////////////////
// IO and memory mapped
/////////////////
if( (ULONG)pdx->base[AMCC_OPREGS] & 0xffff0000 ) {
// Write the address into the MRAR, before the count
OP[AMCC_MRAR]=PhysicalAddress.LowPart;
// Write the count (in BYTES) into the MRTC
OP[AMCC_MRTC]=pdx->WriteTransfer.CurrentTransferSize;
}
else {
// Write the address into the MRAR, before the count
WRITE_PORT_ULONG(OP + AMCC_MRAR, PhysicalAddress.LowPart);
// Write the count (in BYTES) into the MRTC
WRITE_PORT_ULONG(OP + AMCC_MRTC, pdx->WriteTransfer.CurrentTransferSize);
}
// The transfer begins now and will interrupt when done
// but if it doesn't, the timer will let us know.
KdPrint(("SIWDM - Exiting DoBusMasteredWrite\n"));
return TRUE;
}
/*
Function Name:
SheldonTimerRoutine
Routine Description:
Performs the Timeout for BusMastered Transfers.
Retires the IRP and resets the hardware.
Arguments:
Dpc - pointer to a dpc object
Context - pointer to a device extension
junk1 - invalid parameter, for custom timer DPC's
junk2 - invalid parameter
Return Value:
*/
VOID SheldonTimerRoutine(PKDPC Dpc, PVOID Context, PVOID junk1, PVOID junk2)
{
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) Context;
ULONG mcsr, intCSR;
PIRP Irp;
KdPrint(("SIWDM - Entering SheldonTimerRoutine\n"));
// figure out what kind of a transfer was in progress
// a read went wrong
if(Dpc == &(pdx->ReadTransfer.TimerDPC) && pdx->ReadTransfer.TransferInProgress)
{
// turn off the transfer
/////////////////
// IO and memory mapped
/////////////////
if( (ULONG)pdx->base[AMCC_OPREGS] & 0xffff0000 ) {
mcsr = READ_REGISTER_ULONG(pdx->base[AMCC_OPREGS] + AMCC_MCSR);
// shut off go signal for reads
mcsr &= ~AMCC_BUSMASTERED_READ_ENABLE_MASK;
WRITE_REGISTER_ULONG(pdx->base[AMCC_OPREGS] + AMCC_MCSR, mcsr);
// shut off and clear the interrupt
intCSR = READ_REGISTER_ULONG(pdx->base[AMCC_OPREGS] + AMCC_INTCSR);
// clear the "write 1 clear" bits to avoid problems
intCSR &= AMCC_PRESERVE_INTCSR_MASK;
// shut off ints for reads
intCSR &= ~AMCC_BUSMASTERED_READ_INT_ENABLE_MASK;
// clear the read's int bit
intCSR |= AMCC_BUSMASTERED_READ_INT_OCCURRED_MASK;
WRITE_REGISTER_ULONG(pdx->base[AMCC_OPREGS] + AMCC_INTCSR, intCSR);
// update the status
pdx->ReadTransfer.TransferInProgress = FALSE;
// Conclude the previous "DMA" Transfer
pdx->ReadTransfer.Adapter->DmaOperations->FlushAdapterBuffers(
pdx->ReadTransfer.Adapter,
pdx->ReadTransfer.Mdl,
pdx->ReadTransfer.MapRegisterBase,
pdx->ReadTransfer.LogicalAddress,
pdx->ReadTransfer.CurrentTransferSize,
FALSE);
pdx->ReadTransfer.Adapter->DmaOperations->FreeMapRegisters(
pdx->ReadTransfer.Adapter,
pdx->ReadTransfer.MapRegisterBase,
pdx->ReadTransfer.NumberOfMapRegisters);
// Close out this IRP
Irp = pdx->ReadTransfer.pIrp;
Irp->IoStatus.Information =
pdx->ReadTransfer.BytesRequested - pdx->ReadTransfer.BytesRemaining
+ pdx->ReadTransfer.CurrentTransferSize
- READ_REGISTER_ULONG(pdx->base[AMCC_OPREGS] + AMCC_MWTC);
Irp->IoStatus.Status = STATUS_IO_TIMEOUT;
// This one's done. Begin working on the next
StartNextPacket(&pdx->dqReadWrite, pdx->DeviceObject);
UnlockDevice(pdx);
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
else {
mcsr = READ_PORT_ULONG(pdx->base[AMCC_OPREGS] + AMCC_MCSR);
// shut off go signal for reads
mcsr &= ~AMCC_BUSMASTERED_READ_ENABLE_MASK;
WRITE_PORT_ULONG(pdx->base[AMCC_OPREGS] + AMCC_MCSR, mcsr);
// shut off and clear the interrupt
intCSR = READ_PORT_ULONG(pdx->base[AMCC_OPREGS] + AMCC_INTCSR);
// clear the "write 1 clear" bits to avoid problems
intCSR &= AMCC_PRESERVE_INTCSR_MASK;
// shut off ints for reads
intCSR &= ~AMCC_BUSMASTERED_READ_INT_ENABLE_MASK;
// clear the read's int bit
intCSR |= AMCC_BUSMASTERED_READ_INT_OCCURRED_MASK;
WRITE_PORT_ULONG(pdx->base[AMCC_OPREGS] + AMCC_INTCSR, intCSR);
// update the status
pdx->ReadTransfer.TransferInProgress = FALSE;
// Conclude the previous "DMA" Transfer
pdx->ReadTransfer.Adapter->DmaOperations->FlushAdapterBuffers(
pdx->ReadTransfer.Adapter,
pdx->ReadTransfer.Mdl,
pdx->ReadTransfer.MapRegisterBase,
pdx->ReadTransfer.LogicalAddress,
pdx->ReadTransfer.CurrentTransferSize,
FALSE);
pdx->ReadTransfer.Adapter->DmaOperations->FreeMapRegisters(
pdx->ReadTransfer.Adapter,
pdx->ReadTransfer.MapRegisterBase,
pdx->ReadTransfer.NumberOfMapRegisters);
// Close out this IRP
Irp = pdx->ReadTransfer.pIrp;
Irp->IoStatus.Information =
pdx->ReadTransfer.BytesRequested - pdx->ReadTransfer.BytesRemaining
+ pdx->ReadTransfer.CurrentTransferSize
- READ_PORT_ULONG(pdx->base[AMCC_OPREGS] + AMCC_MWTC);
Irp->IoStatus.Status = STATUS_IO_TIMEOUT;
// This one's done. Begin working on the next
StartNextPacket(&pdx->dqReadWrite, pdx->DeviceObject);
UnlockDevice(pdx);
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
}
// a write went wrong
else if(Dpc == &(pdx->WriteTransfer.TimerDPC) && pdx->WriteTransfer.TransferInProgress)
{
// stop the transfer and clear the FIFO
/////////////////
// IO and memory mapped
/////////////////
if( (ULONG)pdx->base[AMCC_OPREGS] & 0xffff0000 ) {
mcsr = READ_REGISTER_ULONG(pdx->base[AMCC_OPREGS] + AMCC_MCSR);
// shut off go signal for writes
mcsr &= ~AMCC_BUSMASTERED_WRITE_ENABLE_MASK;
WRITE_REGISTER_ULONG(pdx->base[AMCC_OPREGS] + AMCC_MCSR, mcsr);
// shut off the hardware ints
intCSR = READ_REGISTER_ULONG(pdx->base[AMCC_OPREGS] + AMCC_INTCSR);
// clear the "write 1 clear" bits to avoid problems
intCSR &= AMCC_PRESERVE_INTCSR_MASK;
// shut off ints for writes
intCSR &= ~AMCC_BUSMASTERED_WRITE_INT_ENABLE_MASK;
// clear the write int bit
intCSR |= AMCC_BUSMASTERED_WRITE_INT_OCCURRED_MASK;
WRITE_REGISTER_ULONG(pdx->base[AMCC_OPREGS] + AMCC_INTCSR, intCSR);
// set the internal state to inactive
pdx->WriteTransfer.TransferInProgress = FALSE;
// Conclude the previous "DMA" Transfer
pdx->WriteTransfer.Adapter->DmaOperations->FlushAdapterBuffers(
pdx->WriteTransfer.Adapter,
pdx->WriteTransfer.Mdl,
pdx->WriteTransfer.MapRegisterBase,
pdx->WriteTransfer.LogicalAddress,
pdx->WriteTransfer.CurrentTransferSize,
TRUE);
pdx->WriteTransfer.Adapter->DmaOperations->FreeMapRegisters(
pdx->WriteTransfer.Adapter,
pdx->WriteTransfer.MapRegisterBase,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -