⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hardwarebuffer.cpp

📁 WinCE 3.0 BSP, 包含Inter SA1110, Intel_815E, Advantech_PCM9574 等
💻 CPP
📖 第 1 页 / 共 2 页
字号:
	pSGDEntry->PhysicalAddr = m_SGDTable.GetPhysicalAddress();
	// and flag it with SGD_JMP
	pSGDEntry->CountAndFlag = SGD_JMP;
	
#ifdef DEBUG
	INFMSG("DsCaptureDriverBuffer::SetDMAChannelBuffer: SGD table is:");
	pSGDEntry = (PSGD_FORMAT)m_SGDTable.GetVirtualAddress();
	while(true)
	{
		INFMSG3("\tAddr: 0x%8.8x, size %d, %s", 
			pSGDEntry->PhysicalAddr, 
			pSGDEntry->CountAndFlag & ~(SGD_EOP | SGD_EOT |SGD_JMP),
			(pSGDEntry->CountAndFlag & SGD_EOP)?TEXT("SGD_EOP"):
		(pSGDEntry->CountAndFlag & SGD_JMP)?TEXT("SGD_JMP"):
		(pSGDEntry->CountAndFlag & SGD_EOT)?TEXT("SGD_EOT"):TEXT("no flag"));
		
		if (pSGDEntry->CountAndFlag & (SGD_EOT | SGD_JMP))
			break;
		pSGDEntry++;
	}
#endif
	FUNCMSG1("-CHardwareBuffer::SetDMABuffer() for %d", GetSize());

}

#if 0
// old (without MAX_ENTRY)
{
	UINT uCurrentChunk = 0;	// counter into the buffer chunk array
	USHORT uCurrentNotification = 0;	// counter into the notification array
	UINT uSGDCounter = 0;	// counter into the SGD table
	
	ULONG ulCurrentPhysicalOffset = 0;
	ULONG ulCurrentPhysicalAddress;
	ULONG ulNotificationAvailable;
	ULONG ulPhysicalAvailable;
	ULONG ulCurrentEntrySize = 0;
	
	if (!m_pDsPositionNotify || m_uNumberOfNotifications < 1)
	{
		ulNotificationAvailable = GetSize()+ 1;
	}
	else
	{
		ulNotificationAvailable = (m_pDsPositionNotify[0].dwOffset);
	}
	ulCurrentPhysicalAddress = GetChunkAddress(uCurrentChunk);
	ulPhysicalAvailable = GetChunkSize(uCurrentChunk);
	
	PSGD_FORMAT pSGDEntry = (PSGD_FORMAT)m_SGDTable.GetVirtualAddress();
	INFMSG1("CHardwareBuffer::SetDMABuffer: DMA table is at 0x%8.8x", pSGDEntry);
	
	ULONG ulMinAreaSize = m_wfxFormat.nAvgBytesPerSec * MIN_INTERRUPT_INTERVAL / 1000L;
	ULONG ulLastInterrupt = 0;
	INFMSG1("ulMinAreaSize is %d", ulMinAreaSize);
	while (true)
	{
		INFMSG2("ulNotificationAvailable = %d, ulPhysicalAvailable = %d", ulNotificationAvailable , ulPhysicalAvailable);
		
		// is the SGD table break determined by the next notification, or the next chunk boundary?
		if (ulNotificationAvailable >= ulPhysicalAvailable)
		{
			// the next chunk boundary; this is not of interest to DirectX, 
			// so we do not need to flag the SGD table entry
			INFMSG2("Writing 0x%8.8x + %d", GetChunkAddress(uCurrentChunk), ulCurrentPhysicalOffset);
			pSGDEntry->PhysicalAddr = GetChunkAddress(uCurrentChunk) + (ulCurrentPhysicalOffset);
			
			ulCurrentEntrySize = ulPhysicalAvailable;
			uCurrentChunk++;
			INFMSG2("Chunk boundary: chunk is %d, notif is %d", uCurrentChunk, uCurrentNotification);
			if (uCurrentChunk >= GetNumberOfChunks())
			{
				INFMSG1("No more chunks! Writing size %d", ulCurrentEntrySize);
				pSGDEntry->CountAndFlag = ulCurrentEntrySize | SGD_EOP;
				break;
			}
			ulCurrentPhysicalOffset = 0;
			ulNotificationAvailable -= ulCurrentEntrySize;
			ulPhysicalAvailable = GetChunkSize(uCurrentChunk);
			INFMSG1("Writing size %d", ulCurrentEntrySize );
			pSGDEntry->CountAndFlag = ulCurrentEntrySize;
			pSGDEntry++;
		}
		else
		{
			// notif boundary; is it acceptable?
			INFMSG2("Checking boundary: ulLastInterrupt = %d, m_pDsPositionNotify[uCurrentNotification].dwOffset = %d",
				ulLastInterrupt, m_pDsPositionNotify[uCurrentNotification].dwOffset);
			
			m_pDsPositionNotify[uCurrentNotification].dwOffset &= ~0x0F;	// ensure a 16 bit boundary (undocumented, but doesn't work otherwise)
			
			// first, it must be further than ulMinAreaSize from the last interrupt
			if ((m_pDsPositionNotify[uCurrentNotification].dwOffset- ulLastInterrupt) < ulMinAreaSize||
				// second, it must be further than ulMinAreaSize from the EOL interrupt (at the end of the buffer)
				(GetSize() - m_pDsPositionNotify[uCurrentNotification].dwOffset) < ulMinAreaSize )
			{
				//refuse interrupt
				INFMSG("Skipping notification");
				uCurrentNotification++;
				if (uCurrentNotification < m_uNumberOfNotifications)
				{
					ulNotificationAvailable  += (m_pDsPositionNotify[uCurrentNotification].dwOffset - m_pDsPositionNotify[uCurrentNotification-1].dwOffset);
				}
				else
				{
					ulNotificationAvailable  = GetSize()+ 1;
				}
			}
			else
			{
				INFMSG2("Writing 0x%8.8x + %d", GetChunkAddress(uCurrentChunk), ulCurrentPhysicalOffset);
				pSGDEntry->PhysicalAddr = GetChunkAddress(uCurrentChunk) + (ulCurrentPhysicalOffset);
				
				ulCurrentEntrySize = ulNotificationAvailable;
				ulCurrentPhysicalOffset += ulCurrentEntrySize;
				ulPhysicalAvailable -= ulCurrentEntrySize;
				uCurrentNotification++;
				INFMSG2("Notif boundary: chunk is %d, notif is %d", uCurrentChunk, uCurrentNotification);
				if (uCurrentNotification < m_uNumberOfNotifications)
				{
					ulNotificationAvailable  = m_pDsPositionNotify[uCurrentNotification].dwOffset - m_pDsPositionNotify[uCurrentNotification-1].dwOffset;
				}
				else
				{
					// the notifications vector ends before the end of the buffer; 
					// to ensure proper terminations set the next 
					// notification boundary to something guaranteed beyond the end of the last chunk
					INFMSG("Notifications done");
					ulNotificationAvailable  = GetSize()+ 1;
				}
				ulLastInterrupt += ulCurrentEntrySize;
				INFMSG1("Writing size %d", ulCurrentEntrySize );
				// the next notification: flag the entry with SGD_EOP
				pSGDEntry->CountAndFlag = ulCurrentEntrySize | SGD_EOP;
				pSGDEntry++;
			}
		}
	}
	
	// close the loop: add an entry that points back to the beginning of the table
	pSGDEntry++;
	pSGDEntry->PhysicalAddr = m_SGDTable.GetPhysicalAddress();
	// and flag it with SGD_JMP
	pSGDEntry->CountAndFlag = SGD_JMP;
	
#ifdef DEBUG
	INFMSG("DsCaptureDriverBuffer::SetDMAChannelBuffer: SGD table is:");
	pSGDEntry = (PSGD_FORMAT)m_SGDTable.GetVirtualAddress();
	while(true)
	{
		INFMSG3("\tAddr: 0x%8.8x, size %d, %s", 
			pSGDEntry->PhysicalAddr, 
			pSGDEntry->CountAndFlag & ~(SGD_EOP | SGD_EOT |SGD_JMP),
			(pSGDEntry->CountAndFlag & SGD_EOP)?TEXT("SGD_EOP"):
		(pSGDEntry->CountAndFlag & SGD_JMP)?TEXT("SGD_JMP"):
		(pSGDEntry->CountAndFlag & SGD_EOT)?TEXT("SGD_EOT"):TEXT("no flag"));
		
		if (pSGDEntry->CountAndFlag & (SGD_EOT | SGD_JMP))
			break;
		pSGDEntry++;
	}
#endif

}
#endif


bool CHardwareBuffer::Allocate(ULONG uSize)
{
	FUNCMSG1("CHardwareBuffer::Allocate(%lu)", uSize);

	ASSERT( ! m_pVirtualAddress );
	ASSERT( ! GetSize() );

	// the Hardware Secondary Buffer is limited to 64K
	// because the DMA channel can only address so much
	if(uSize > 0x10000)
	{
		ERRMSG1("CHardwareBuffer::Allocate: size too large (%d)", uSize);
		return false;
	}

	if(!ReservePhysicalMem(uSize))	
	{
		ERRMSG("CHardwareBuffer::Allocate: can't reserve phys mem");
		return false;
	}

	INFMSG3("CHardwareBuffer::Allocate: buf %d: size 0x%x locked; number of chunks: %d \r\n",
		m_uChannel, GetSize(), GetNumberOfChunks());
	return true;
}

void CHardwareBuffer::ProcessInterrupt(void)
{
	//FUNCMSG("CHardwareBuffer::ProcessInterrupt");
	DWORD dwAddr = m_pRegisters->regBusMasterPRD;
	// synchronize offsets; when we get an interrupt we know where the DMA is
	// what chunk are we in?
	// the device automatically advances the pointer, i.e., the register points to the *next* entry
	// note that we'll never actually get 0 as an entry, because the device spends very little time on the *last*
	// SGD table entry. The last entry is not a data one, but only a placeholder for a jump
	// flag, so the device reloads the beginning of the table and increments the 
	// sgd pointer immediately to point to entry numero uno.
	int nEntry = (dwAddr - m_SGDTable.GetPhysicalAddress())/sizeof(SGD_FORMAT) - 1;

	ULONG  ulCurrentOffset = 0;
	// the CX5530 doesn't allow us to read the DMA counter; in order to give a semblance 
	// of precision we use the DMA channel guesstimation procedure;
	// we save in the channel the position where we are now
	// When DirectSound calls GetDMAPosition the DMA channel will return this value
	// or compute an approximate one at a later date
	for (int i = 0; i < nEntry; i++)
	{
		ulCurrentOffset += (m_SGDTable.GetEntry(i)->CountAndFlag) & ~(SGD_EOT | SGD_EOP);
	}
	LOG('I', ulCurrentOffset, m_ulLastOffset);

	// deal with notifications

	if (m_uNumberOfNotifications > 0)
	{
		UINT i = 0;
		//INFMSG2("DsPlaybackDriverBuffer::ProcessInterrupt(%d): position is %d", intsrc, ulCurrentOffset);
		// the events might belong to another process, so set permissions long enough
		// to set the event (s).
		DWORD dwSavedPermissions = GetCurrentPermissions();
		SetProcPermissions( DWORD (-1) );

//		ulCurrentOffset += 64;
//		if (ulCurrentOffset >= GetSize())
//			ulCurrentOffset -= GetSize();


		//set off notification events
		if (m_ulLastOffset > ulCurrentOffset)	// wraparound;
		{
			for (i = 0; i < m_uNumberOfNotifications; i++)
			{
				
				if (m_pDsPositionNotify[i].dwOffset <= (ulCurrentOffset ) || m_pDsPositionNotify[i].dwOffset > m_ulLastOffset)
				{
					SetEvent(m_pDsPositionNotify[i].hEventNotify);
					LOG('W', ulCurrentOffset, m_pDsPositionNotify[i].dwOffset);
				}
			}
		}
		else
		{
			for (i = 0; i < m_uNumberOfNotifications; i++)
			{
				
				if (m_pDsPositionNotify[i].dwOffset <= (ulCurrentOffset) && m_pDsPositionNotify[i].dwOffset > m_ulLastOffset)
				{
					SetEvent(m_pDsPositionNotify[i].hEventNotify);
					LOG('N', ulCurrentOffset, m_pDsPositionNotify[i].dwOffset);
				}
			}
		}
		
		SetProcPermissions( dwSavedPermissions );
	}
	m_ulLastOffset = ulCurrentOffset;
}

void CHardwareBuffer::StartDMAChannel(bool bCapture)
{
	FUNCMSG1("+CHardwareBuffer::StartDMAChannel for %s", bCapture?TEXT("recording"):TEXT("playback"));
	BYTE byStatus = m_pRegisters->regBusMasterStatus;	// clear status
	INFMSG1("Trigger Master DMA: Status is 0x%2.2x", byStatus);
	m_dwLastAddr = m_pRegisters->regBusMasterPRD = m_SGDTable.GetPhysicalAddress();
	m_ulLastOffset = 0;
	m_pRegisters->regBusMasterCommand.byValue = 0x01 | (bCapture?CAPTURE_FLAG:0);	// enable play DMA
	m_bIsRunning = true;
}

void CHardwareBuffer::StopDMAChannel()
{
	FUNCMSG("+CHardwareBuffer::StopDMAChannel");
	
	// Terminate Master DMA.
	// put an EOT in the DMA table
	int nEntry = (m_pRegisters->regBusMasterPRD - m_SGDTable.GetPhysicalAddress())/sizeof(SGD_FORMAT);
	PSGD_FORMAT pTable = (PSGD_FORMAT )m_SGDTable.GetVirtualAddress();
	if (pTable[nEntry].CountAndFlag & SGD_JMP)
		nEntry = 0;
	pTable[nEntry].CountAndFlag = (pTable[nEntry].CountAndFlag & ~SGD_EOP)|SGD_EOT;
	INFMSG1("Stopping entry nEntry is %d", nEntry);
}

DWORD CHardwareBuffer::GetDMAPosition()
{
	//CriticalSectionAcquisition c(&m_csBuffer);
	LOG('P', m_ulLastOffset, 0);
	return m_ulLastOffset;
}

bool CHardwareBuffer::HasInterrupt()
{
	DWORD dwAddr = m_pRegisters->regBusMasterPRD;
	if (dwAddr != m_dwLastAddr)
	{
		// Ok, the PRD controller advanced; we assume we have an interrupt;
		m_dwLastAddr = dwAddr;
		return true;
	}
	return false;
}

bool CHardwareBuffer::IsStopInterrupt()
{
	return (m_pRegisters->regBusMasterStatus & BUSMASTER_ERROR) != 0;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -