?? atapipci.cpp
字號:
DWORD iPage = 0, iPFN, iBuffer;
BOOL fUnalign = FALSE;
DMA_ADAPTER_OBJECT Adapter;
Adapter.ObjectSize = sizeof(DMA_ADAPTER_OBJECT);
Adapter.InterfaceType = (INTERFACE_TYPE)m_pPort->m_pController->m_dwi.dwInterfaceType;
Adapter.BusNumber = m_pPort->m_pController->m_dwi.dwBusNumber;
DEBUGMSG(ZONE_DMA, (_T(
"Atapi!CPCIDisk::SetupDMA> Request(%s), SgCount(%d)\r\n"
), fRead ? (_T("Read")) : (_T("Write")), dwSgCount));
// disable bus master
WriteBMCommand(0);
if (!m_pPRD) {
m_pPRD = (PDMATable)HalAllocateCommonBuffer(&Adapter,
UserKInfo[KINX_PAGESIZE], (PPHYSICAL_ADDRESS)&m_pPRDPhys, FALSE);
if (!m_pPRD) {
goto ExitFailure;
}
}
// m_pPhysList tracks pages used for DMA buffers when the scatter/gather
// buffer is unaligned
if (!m_pPhysList) {
m_pPhysList = (PPhysTable)VirtualAlloc(m_pStartMemory, UserKInfo[KINX_PAGESIZE], MEM_COMMIT, PAGE_READWRITE);
if (!m_pPhysList) {
goto ExitFailure;
}
// allocate the minimum number of fixed pages
for (DWORD i = 0; i < MIN_PHYS_PAGES; i++) {
PHYSICAL_ADDRESS PhysicalAddress = {0};
m_pPhysList[i].pVirtualAddress = (LPBYTE)HalAllocateCommonBuffer(&Adapter,
UserKInfo[KINX_PAGESIZE], &PhysicalAddress, FALSE);
m_pPhysList[i].pPhysicalAddress = (LPBYTE)PhysicalAddress.QuadPart;
if (!m_pPhysList[i].pVirtualAddress) {
goto ExitFailure;
}
}
}
m_dwPhysCount = 0;
// m_pSGCopy tracks the mapping between scatter/gather buffers and DMA
// buffers when the scatter/gather buffer is unaligned and we are reading,
// so we can copy the read data back to the scatter/gather buffer; when the
// scatter/gather buffer is aligned, m_pSGCopy tracks the scatter/gather
// buffers of a particular DMA transfer, so we can unlock the buffers at
// completion
if (!m_pSGCopy) {
m_pSGCopy = (PSGCopyTable)VirtualAlloc(
m_pStartMemory + UserKInfo[KINX_PAGESIZE],
UserKInfo[KINX_PAGESIZE],
MEM_COMMIT,
PAGE_READWRITE);
if (!m_pSGCopy) {
goto ExitFailure;
}
}
m_dwSGCount = 0;
if (!m_pPFNs) {
m_pPFNs = (PDWORD)VirtualAlloc(
m_pStartMemory + 2*UserKInfo[KINX_PAGESIZE],
UserKInfo[KINX_PAGESIZE],
MEM_COMMIT,
PAGE_READWRITE);
if (!m_pPFNs) {
goto ExitFailure;
}
}
// determine whether the a buffer or the buffer length is unaligned
for (iBuffer = 0; iBuffer < dwSgCount; iBuffer++) {
if (
((DWORD)pSgBuf[iBuffer].sb_buf & dwAlignMask) ||
((DWORD)pSgBuf[iBuffer].sb_len & dwAlignMask)
) {
fUnalign = TRUE;
break;
}
}
if (fUnalign) {
DWORD dwCurPageOffset = 0;
for (iBuffer = 0; iBuffer < dwSgCount; iBuffer++) {
// Map address and check for security violation
LPBYTE pBuffer = (LPBYTE)MapCallerPtr((LPVOID)pSgBuf[iBuffer].sb_buf, pSgBuf[iBuffer].sb_len);
if (pSgBuf[iBuffer].sb_buf != NULL && pBuffer == NULL) {
// security violation
DEBUGMSG(ZONE_ERROR, (TEXT(
"Atapi!CPCIDisk::SetupDMA> Failed to map pointer to caller\r\n"
)));
goto ExitFailure;
}
DWORD dwBufferLeft = pSgBuf[iBuffer].sb_len;
while (dwBufferLeft) {
DWORD dwBytesInCurPage = UserKInfo[KINX_PAGESIZE] - dwCurPageOffset;
DWORD dwBytesToTransfer = (dwBufferLeft > dwBytesInCurPage) ? dwBytesInCurPage : dwBufferLeft;
// allocate a new page, if necessary
if ((dwCurPageOffset == 0) && (m_dwPhysCount >= MIN_PHYS_PAGES)) {
PHYSICAL_ADDRESS PhysicalAddress = {0};
m_pPhysList[m_dwPhysCount].pVirtualAddress = (LPBYTE)HalAllocateCommonBuffer(
&Adapter, UserKInfo[KINX_PAGESIZE], &PhysicalAddress, FALSE);
m_pPhysList[m_dwPhysCount].pPhysicalAddress = (LPBYTE)PhysicalAddress.QuadPart;
if (!m_pPhysList[m_dwPhysCount].pVirtualAddress) {
goto ExitFailure;
}
}
if (fRead) {
// prepare a scatter/gather copy entry on read, so we can
// copy data from the DMA buffer to the scatter/gather
// buffer after this DMA transfer is complete
m_pSGCopy[m_dwSGCount].pSrcAddress = m_pPhysList[m_dwPhysCount].pVirtualAddress + dwCurPageOffset;
m_pSGCopy[m_dwSGCount].pDstAddress = pBuffer;
m_pSGCopy[m_dwSGCount].dwSize = dwBytesToTransfer;
m_dwSGCount++;
}
else {
memcpy(m_pPhysList[m_dwPhysCount].pVirtualAddress + dwCurPageOffset, pBuffer, dwBytesToTransfer);
}
// if this buffer is larger than the space remaining on the page,
// then finish processing this page by setting @dwCurPageOffset<-0
if (dwBufferLeft >= dwBytesInCurPage) {
dwCurPageOffset = 0;
}
else {
dwCurPageOffset += dwBytesToTransfer;
}
// have we finished a page? (i.e., offset was reset or this is the last buffer)
if ((dwCurPageOffset == 0) || (iBuffer == (dwSgCount - 1))) {
// add this to the PRD table
m_pPRD[m_dwPhysCount].physAddr = (DWORD)m_pPhysList[m_dwPhysCount].pPhysicalAddress;
m_pPRD[m_dwPhysCount].size = dwCurPageOffset ? (USHORT)dwCurPageOffset : (USHORT)UserKInfo[KINX_PAGESIZE];
m_pPRD[m_dwPhysCount].EOTpad = 0;
m_dwPhysCount++;
}
// update transfer
dwBufferLeft -= dwBytesToTransfer;
pBuffer += dwBytesToTransfer;
}
}
m_pPRD[m_dwPhysCount - 1].EOTpad = 0x8000;
}
else {
DWORD dwTotalBytes = 0;
for (iBuffer = 0; iBuffer < dwSgCount; iBuffer++) {
// Map address and check for security violation
LPBYTE pBuffer = (LPBYTE)MapCallerPtr((LPVOID)pSgBuf[iBuffer].sb_buf, pSgBuf[iBuffer].sb_len);
if (pSgBuf[iBuffer].sb_buf != NULL && pBuffer == NULL) {
// security violation
DEBUGMSG(ZONE_ERROR, (TEXT(
"Atapi!CPCIDisk::SetupDMA> Failed to map pointer to caller\r\n"
)));
goto ExitFailure;
}
// determine the number of bytes remaining to be placed in PRD
dwTotalBytes = pSgBuf[iBuffer].sb_len;
if (!LockPages (
pBuffer,
dwTotalBytes,
m_pPFNs,
fRead ? LOCKFLAG_WRITE : LOCKFLAG_READ)
) {
goto ExitFailure;
}
// add a scatter/gather copy entry for the area we lock, so that
// we can unlock it when we are finished
m_pSGCopy[m_dwSGCount].pSrcAddress = pBuffer;
m_pSGCopy[m_dwSGCount].pDstAddress = 0;
m_pSGCopy[m_dwSGCount].dwSize = dwTotalBytes;
m_dwSGCount++;
iPFN = 0;
while (dwTotalBytes) {
DWORD dwBytesToTransfer = UserKInfo[KINX_PAGESIZE];
if ((DWORD)pBuffer & dwPageMask) {
// the buffer is not page aligned; use up the next page
// boundary
dwBytesToTransfer = UserKInfo[KINX_PAGESIZE] - ((DWORD)pBuffer & dwPageMask);
}
if (dwTotalBytes < dwBytesToTransfer) {
// use what remains
dwBytesToTransfer = dwTotalBytes;
}
m_pPRD[iPage].physAddr = (m_pPFNs[iPFN] << UserKInfo[KINX_PFN_SHIFT]) + ((DWORD)pBuffer & dwPageMask);
if (!TranslateAddress(&m_pPRD[iPage].physAddr)) {
goto ExitFailure;
}
m_pPRD[iPage].size = (USHORT)dwBytesToTransfer;
m_pPRD[iPage].EOTpad = 0;
iPage++;
iPFN++;
// update transfer
pBuffer += dwBytesToTransfer;
dwTotalBytes -= dwBytesToTransfer;
}
}
m_dwPhysCount = 0;
m_pPRD[iPage-1].EOTpad = 0x8000;
}
return TRUE;
ExitFailure:
DEBUGCHK(0);
// clean up
// FreeDMABuffers();
return FALSE;
}
// ----------------------------------------------------------------------------
// Function: BeginDMA
// Begin DMA transfer
//
// Parameters:
// fRead -
// ----------------------------------------------------------------------------
BOOL
CPCIDisk::BeginDMA(
BOOL fRead
)
{
BYTE bStatus, bCommand;
CacheSync(CACHE_SYNC_DISCARD);
WriteBMCommand(0);
WriteBMTable(m_pPRDPhys);
bStatus = ReadBMStatus();
bStatus |= 0x06;
// bStatus |= 0x66;
WriteBMStatus(bStatus);
if (fRead) {
bCommand = 0x08 | 0x01;
}
else {
bCommand = 0x00 | 0x01;
}
WriteBMCommand(bCommand);
bStatus = ReadBMStatus();
return TRUE;
}
// ----------------------------------------------------------------------------
// Function: EndDMA
// End DMA transfer
//
// Parameters:
// None
// ----------------------------------------------------------------------------
BOOL
CPCIDisk::EndDMA(
)
{
BYTE bStatus = ReadBMStatus();
if ((bStatus & BM_STATUS_INTR) && (bStatus & BM_STATUS_ACTIVE)) {
DEBUGMSG(ZONE_DMA, (_T(
"Atapi!CPCIDisk::EndDMA> Status: active; status(0x%x)\r\n"
), bStatus));
}
else if ((bStatus & BM_STATUS_INTR) && !(bStatus & BM_STATUS_ACTIVE)) {
DEBUGMSG(ZONE_DMA, (_T(
"Atapi!CPCIDisk::EndDMA> Status: inactive; status(0x%x)\r\n"
), bStatus));
}
else if (!(bStatus & BM_STATUS_INTR)&& (bStatus & BM_STATUS_ACTIVE)) {
DEBUGMSG(ZONE_ERROR|ZONE_DMA, (_T(
"Atapi!CPCIDisk::EndDMA> Interrupt delayed; status(0x%x)\r\n"
), bStatus));
BOOL bCount = 0;
while (TRUE) {
StallExecution(100);
bCount++;
bStatus = ReadBMStatus();
if ((bStatus & BM_STATUS_INTR) && !(bStatus & BM_STATUS_ACTIVE)) {
DEBUGMSG(ZONE_DMA, (_T(
"Atapi!CPCIDisk::EndDMA> DMA complete after delay; status(0x%x)\r\n"
), bStatus));
break;
}
else {
DEBUGMSG(ZONE_ERROR|ZONE_DMA, (_T(
"Atapi!CPCIDisk::EndDMA> Interrupt still delayed; status(0x%x)\r\n"
), bStatus));
if (bCount > 10) {
WriteBMCommand(0);
return FALSE;
}
}
}
}
else {
if (bStatus & BM_STATUS_ERROR) {
DEBUGMSG(ZONE_ERROR|ZONE_DMA, (_T(
"Atapi!CPCIDisk::EndDMA> Error; (0x%x)\r\n"
), bStatus));
DEBUGCHK(0);
return FALSE;
}
}
WriteBMCommand(0);
return TRUE;
}
// ----------------------------------------------------------------------------
// Function: AbortDMA
// Abort DMA transfer
//
// Parameters:
// None
// ----------------------------------------------------------------------------
BOOL
CPCIDisk::AbortDMA(
)
{
DWORD i;
WriteBMCommand(0);
for (i = 0; i < m_dwSGCount; i++) {
if (!m_pSGCopy[i].pDstAddress) {
UnlockPages(m_pSGCopy[i].pSrcAddress, m_pSGCopy[i].dwSize);
}
}
// free all but the first @MIN_PHYS_PAGES pages; these are fixed
for (i = MIN_PHYS_PAGES; i < m_dwPhysCount; i++) {
FreePhysMem(m_pPhysList[i].pVirtualAddress);
}
return FALSE;
}
// ----------------------------------------------------------------------------
// Function: CompleteDMA
// Complete DMA transfer
//
// Parameters:
// pSgBuf -
// dwSgCount -
// fRead -
// ----------------------------------------------------------------------------
BOOL
CPCIDisk::CompleteDMA(
PSG_BUF pSgBuf,
DWORD dwSgCount,
BOOL fRead
)
{
DWORD i;
for (i = 0; i < m_dwSGCount; i++) {
if (m_pSGCopy[i].pDstAddress) {
// this corresponds to an unaligned region; copy it back to the
// scatter/gather buffer
memcpy(m_pSGCopy[i].pDstAddress, m_pSGCopy[i].pSrcAddress, m_pSGCopy[i].dwSize);
}
else {
// this memory region needs to be unlocked
UnlockPages(m_pSGCopy[i].pSrcAddress, m_pSGCopy[i].dwSize);
}
}
// free all but the first @MIN_PHYS_PAGES pages; the first @MIN_PHYS_PAGES
// pages are fixed
for (i = MIN_PHYS_PAGES; i < m_dwPhysCount; i++) {
FreePhysMem(m_pPhysList[i].pVirtualAddress);
}
return TRUE;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -