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

📄 s3c6400otgdevice.cpp

📁 Samsung公司S3C6400芯片的BSP源码包
💻 CPP
📖 第 1 页 / 共 5 页
字号:

	return bRet;
}

static
VOID
HandleEndpoint0Event(
	PCTRLR_PDD_CONTEXT  pContext
	)
{
	SETFNAME();
	FUNCTION_ENTER_MSG();

	ValidateContext(pContext);
	DEBUGCHK(pContext->fRunning);

	PEP_STATUS peps = GetEpStatus(pContext, 0);
	LOCK_ENDPOINT(peps);

	// Write 0 to SEND_STALL and SENT_STALL to clear them, so we need to
	// leave them unchanged by default.
	BYTE bEp0CsrToWrite = 0;
	BOOL fSendUdr = FALSE;
	BOOL fCompleted = FALSE;
	DWORD dwStatus;

	if (pContext->Ep0State == EP0_STATE_IDLE)
	{
		if (pContext->fSpeedReported == FALSE)
		{
			// After Every Reset Notify MDD of Speed setting.
			// This device can only support FULL Speed.
			// It will be process in HandleUSBBusIrq INT_SDE +chandolp
			DWORD wDSTS = ReadReg(pContext, DSTS);
			if (pContext->dwDetectedSpeed == USB_FULL)
			{
				pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_BUS_SPEED, BS_FULL_SPEED);
			}
			else if(pContext->dwDetectedSpeed == USB_HIGH)
			{
				pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_BUS_SPEED, BS_HIGH_SPEED);
			}
			else
			{
				RETAILMSG(1,(TEXT("SPEED Exeption LowSpeed \r\n")));
			}
			pContext->fSpeedReported = TRUE;
		}

		// New setup packet
		DWORD cbOutFifo = pContext->CntValue;
		pContext->CntValue = 0;
		PDWORD pbUdr = (PDWORD) &pContext->udr;
		volatile ULONG *pulFifoReg = _GetDataRegister(0);
		DWORD cbBytesRemaining = cbOutFifo;

		while (cbBytesRemaining>0)
		{
			*pbUdr++ = (DWORD) *pulFifoReg;
			cbBytesRemaining -= 4;
		}

		if (cbOutFifo != sizeof(pContext->udr))
		{
			DEBUGMSG(ZONE_ERROR, (_T("%s Setup packet was only %x bytes!\r\n"), pszFname, cbOutFifo));
			// Ideally this should not hapen. This is a recovery mechanism if
			// we get out of sync somehow.
			bEp0CsrToWrite |= (EP0_SEND_STALL | SERVICED_OUT_PKY_RDY | DATA_END);
		}
		else
		{
			// Parse the Setup Command this is necessary to Configure the
			// SW State Machine and to set bits to enable the HW to
			// ACK/NAK correctly.

			// Determine if this is a NO Data Packet
			if (pContext->udr.wLength > 0)
			{
				// Determine transfer Direction
				if (pContext->udr.bmRequestType & USB_ENDPOINT_DIRECTION_MASK)
				{
					// Start the SW OUT State Machine
					pContext->Ep0State = EP0_STATE_IN_DATA_PHASE;
				}
				else
				{
					// Start the SW OUT State Machine
					pContext->Ep0State = EP0_STATE_OUT_DATA_PHASE;
				}
				pContext->sendDataEnd = FALSE;
			}
			else
			{       // udr.wLength == 0
				// ClientDriver will issue a SendControlStatusHandshake to
				// complete the transaction.
				pContext->sendDataEnd = TRUE;
				// Nothing left to do... stay in IDLE.
				DEBUGCHK(pContext->Ep0State == EP0_STATE_IDLE);
			}
			fSendUdr = TRUE;
		}
	}

	else if (pContext->Ep0State == EP0_STATE_OUT_DATA_PHASE)
	{
		// Check For out packet read && receive fifo not empty -> out token event
		if (pContext->CntValue)
		{
                	DEBUGMSG(ZONE_RECEIVE, (_T("%s out token packet on endpoint 0 \r\n"), pszFname));
                	HandleRx(pContext, peps, &fCompleted, &dwStatus);
			pContext->sendDataEnd = TRUE;
            	}
            	// status stage of control transfer; zero-length packet received
            	else
		{
               	DEBUGMSG(ZONE_RECEIVE, (_T("%s status stage of control transfer on endpoint 0\r\n"), pszFname));
                	pContext->Ep0State = EP0_STATE_IDLE;
            	}
	}
	else
	{
		HandleTx(pContext, peps, 1);
	}

	// Clear any interrupts
	DEBUGMSG(ZONE_COMMENT, (_T("%s Writing 0x%02x to EP0_CSR\r\n"), pszFname, bEp0CsrToWrite));
	if (fCompleted)
	{
		CompleteTransfer(pContext, peps, dwStatus);
	}
	if (fSendUdr)
	{
		pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_SETUP_PACKET, (DWORD) &pContext->udr);
	}


	FUNCTION_LEAVE_MSG();
	UNLOCK_ENDPOINT(peps);
}


// Process an endpoint interrupt.  Call interrupt-specific handler.
static
VOID
HandleEndpointEvent(
                    PCTRLR_PDD_CONTEXT  pContext,
                    DWORD               dwEndpoint,
                    DWORD               epIrqStat
                    )
{
	SETFNAME();
	FUNCTION_ENTER_MSG();

	ValidateContext(pContext);
	DEBUGCHK(pContext->fRunning);
	DEBUGCHK(dwEndpoint != 0);

	DWORD dwPendingEvents = 0;
	EP_STATUS *peps = GetEpStatus(pContext, dwEndpoint);
	PREFAST_DEBUGCHK(peps);

	LOCK_ENDPOINT(peps);

	if (peps->dwDirectionAssigned == USB_IN_TRANSFER)
	{
		dwPendingEvents = IN_TRANSFER;
	}
	else
	{
		dwPendingEvents = OUT_TRANSFER;
	}


	BOOL fCompleted = FALSE;
	DWORD dwStatus;

	if (dwPendingEvents == IN_TRANSFER)
	{
		HandleTx(pContext, peps, 0);
	}
	else if (dwPendingEvents == OUT_TRANSFER)
	{
		HandleRx(pContext, peps, &fCompleted, &dwStatus);
	}

	if (fCompleted)
	{
		// Disable transfer interrupts until another transfer is issued.
		DisableEndpointInterrupt(pContext, peps->dwEndpointNumber, peps->dwDirectionAssigned);
	}

	if (fCompleted)
	{
		CompleteTransfer(pContext, peps, dwStatus);
	}

	FUNCTION_LEAVE_MSG();
	UNLOCK_ENDPOINT(peps);
}

static
VOID
SetEndpoint(
		PCTRLR_PDD_CONTEXT  pContext
		)
{
	// Unmask DAINT source
	WriteReg(pContext, DIEPINT0, 0xff);
	WriteReg(pContext, DOEPINT0, 0xff);
	WriteReg(pContext, DIEPINT1, 0xff);
	WriteReg(pContext, DOEPINT2, 0xff);

	// Init For Ep0
	WriteReg(pContext, DIEPTSIZ0, 1<<19|pContext->dwEp0MaxPktSize<<0);
	WriteReg(pContext, DOEPTSIZ0, 1<<29|1<<19|pContext->dwEp0MaxPktSize);
	WriteReg(pContext, DOEPCTL0, 0<<31|1<<26);		//ep0 enable, clear nak
}

static
VOID
SetMaxPktSizes(
                PCTRLR_PDD_CONTEXT  pContext,
                USB_SPEED eSpeed
                )
{
	if (eSpeed == USB_HIGH)
	{
		pContext->eSpeed = USB_HIGH;
		pContext->dwEp0MaxPktSize = 64;
	}
	else
	{
		pContext->eSpeed = USB_FULL;
		pContext->dwEp0MaxPktSize = 8;
	}
}

static
VOID
SetAllOutEpNak(
		PCTRLR_PDD_CONTEXT  pContext
		)
{
	volatile DWORD dwTemp;
	DWORD dwEndpoint;

	for(dwEndpoint=0; dwEndpoint<ENDPOINT_COUNT; dwEndpoint++)
	{
		dwTemp = ReadEPSpecificReg(pContext, dwEndpoint, DOEPCTL);
		dwTemp |= DEPCTL_SNAK;
		WriteEPSpecificReg(pContext, dwEndpoint, DOEPCTL, dwTemp);
	}
}

static
VOID
ClearAllOutEpNak(
		PCTRLR_PDD_CONTEXT  pContext
		)
{
	volatile DWORD dwTemp;
	DWORD dwEndpoint;

	for(dwEndpoint=0; dwEndpoint<ENDPOINT_COUNT; dwEndpoint++)
	{
		dwTemp = ReadEPSpecificReg(pContext, dwEndpoint, DOEPCTL);
		dwTemp |= DEPCTL_CNAK;
		WriteEPSpecificReg(pContext, dwEndpoint, DOEPCTL, dwTemp);
	}
}


// Process USB Bus interrupt
static
VOID
HandleUSBBusIrq(
		PCTRLR_PDD_CONTEXT  pContext,
		DWORD                bUSBBusIrqStat
		)
{
	SETFNAME();
	FUNCTION_ENTER_MSG();
    	SetAllOutEpNak(pContext);

	if (bUSBBusIrqStat & INT_RESET)
	{
		DWORD dwGOTGCTL = ReadReg(pContext, GOTGCTL);
		if (pContext->attachedState == UFN_DETACH)
		{
			if(dwGOTGCTL & (B_SESSION_VALID|A_SESSION_VALID))
			{
				if(USBClassInfo == USB_MSF)
				{
					Sleep(1000); //for MSF Class. on booting, to generate SD Detect INT and to to mount before storage detectetcion on BOT			
				}
					SoftResetCore(pContext);
					RETAILMSG(1,(TEXT("[UFNPDD] OTG Cable Attached\r\n")));

					InitDevice(pContext);

					pContext->fSpeedReported = FALSE;
					pContext->fSetUpPhaseDone = FALSE;
					pContext->Ep0State = EP0_STATE_IDLE;
					pContext->CntValue = 0;
					pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_BUS_EVENTS, UFN_ATTACH);
					pContext->attachedState = UFN_ATTACH;
			}
			else
			{
				RETAILMSG(1,(TEXT("[UFNPDD] RESET Exeption \r\n")));
				pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_BUS_EVENTS, UFN_DETACH);
				pContext->attachedState = UFN_DETACH;
			}
		}
		else
		{
			if(!(dwGOTGCTL & (B_SESSION_VALID|A_SESSION_VALID)))
			{
				RETAILMSG(0,(TEXT("[UFNPDD] OTG Cable Detached\r\n")));
				pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_BUS_EVENTS, UFN_DETACH);
				pContext->attachedState = UFN_DETACH;
			}
			else
			{
				if(USBClassInfo == USB_MSF)
				{
					SoftResetCore(pContext);
					InitDevice(pContext);

					pContext->fSpeedReported = FALSE;
					pContext->fSetUpPhaseDone = FALSE;
					pContext->Ep0State = EP0_STATE_IDLE;
					pContext->CntValue = 0;
					Sleep(100);
				}
				RETAILMSG(1,(TEXT("[UFNPDD] RESET Again \r\n")));
			}
		}

		WriteReg(pContext, GINTSTS, INT_RESET);
		DEBUGMSG(ZONE_USB_EVENTS, (_T("%s Reset\r\n"), pszFname));
		pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_BUS_EVENTS, UFN_RESET);
		ClearAllOutEpNak(pContext);
	}

	if (bUSBBusIrqStat & INT_SDE)
	{
		WriteReg(pContext, GINTSTS, INT_SDE);
		DWORD dwDSTS = ReadReg(pContext, DSTS);
		if (((dwDSTS & 0x6)>>1) == USB_HIGH)
		{
			pContext->dwDetectedSpeed = USB_HIGH;
			SetMaxPktSizes(pContext, USB_HIGH);
		}
		else if(((dwDSTS & 0x6) >> 1) == USB_FULL)
		{
			pContext->dwDetectedSpeed = USB_FULL;
			SetMaxPktSizes(pContext, USB_FULL);
		}
		else
		{
			RETAILMSG(1,(TEXT("[UFNPDD] INT_SDE_EXEPTION Occured! \r\n")));
		}
		SetEndpoint(pContext);
	}
	if (bUSBBusIrqStat & INT_RESUME)
	{
		if(USBClassInfo == USB_MSF)
		{
			Sleep(1000); //for MSF Class. on booting, to generate SD Detect INT and to to mount before storage detectetcion on BOT
		}
		WriteReg(pContext, GINTSTS, INT_RESUME);
              pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_BUS_EVENTS, UFN_RESUME);
	}
	if (bUSBBusIrqStat & INT_SUSPEND)
	{
		WriteReg(pContext, GINTSTS, INT_SUSPEND);
              pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_BUS_EVENTS, UFN_SUSPEND);
	}

	if (bUSBBusIrqStat & INT_OTG)
	{
		DWORD dwGotgint = ReadReg(pContext, GOTGINT);
		if (dwGotgint & SesEndDet)
		{
			RETAILMSG(1,(TEXT("[UFNPDD] OTG Cable Detached\r\n")));
			pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_BUS_EVENTS, UFN_DETACH);
			pContext->attachedState = UFN_DETACH;
		}
		else
		{
			RETAILMSG(1,(TEXT("[UFNPDD] OTG Interrupt Exeption %x\r\n"),dwGotgint));
		}
		WriteReg(pContext, GOTGINT, dwGotgint);
	}
	FUNCTION_LEAVE_MSG();
}


static
VOID
HandleUSBEvent(
               PCTRLR_PDD_CONTEXT pContext
               )
{
	SETFNAME();
	FUNCTION_ENTER_MSG();
	ValidateContext(pContext);

	DWORD dwGintsts = ReadReg(pContext, GINTSTS);
	DWORD dwDaint = ReadReg(pContext, DAINT);

	if (dwGintsts & (INT_RESUME | INT_SDE | INT_RESET | INT_SUSPEND | INT_OTG))
	{
		HandleUSBBusIrq(pContext, dwGintsts);
	}

	if (dwGintsts & (INT_OUT_EP | INT_IN_EP | INT_RX_FIFO_NOT_EMPTY))
	{
	       // Interrupt is not occured by Out EP interrupt. it is disabled.
	       // But if DMA mode is used, Out EP interrupt should be need. so i'm not blocking the code.
		if (dwGintsts & INT_OUT_EP)
		{
			if (dwDaint & EP0_OUT_INT)
			{
				volatile DWORD dwDoepint0 = ReadReg(pContext, DOEPINT0);
				if (dwDoepint0 & SETUPPHASEDONE)
				{
					pContext->fSetUpPhaseDone = TRUE;
				}
				WriteReg(pContext, DOEPINT0, dwDoepint0);
			}
			for(DWORD dwEndpoint = 1; dwEndpoint < ENDPOINT_COUNT; ++ dwEndpoint)
			{
				DWORD dwEpBit = EpToIrqStatBit(dwEndpoint) << ENDPOINT_COUNT;
				if (dwDaint & dwEpBit)
				{
					volatile DWORD dwDoepint2 = ReadReg(pContext, DOEPINT2);
					// Not Call HandleEndpointEvent function
					// because in USB CPU mode, you should check the INT_RX_FIFO_NOT_EMPTY
					WriteReg(pContext, DOEPINT2, dwDoepint2);
				}
			}
		}

		if (dwGintsts & INT_IN_EP)
		{
			if (dwDaint & EP0_IN_INT)
			{
				volatile DWORD dwDiepint0 = ReadReg(pContext, DIEPINT0);
				if (dwDiepint0 & IN_TKN_RECEIVED)
				{
					HandleEndpoint0Event(pContext);
				}
				if (dwDiepint0 & TIMEOUT_CONDITION)
				{
					RETAILMSG(1,(TEXT("Time Out EP0\r\n")));
					WriteReg(pContext, DCTL, CLEAR_GNPINNAK);
				}
				WriteReg(pContext, DIEPINT0, dwDiepint0);
			}
			for(DWORD dwEndpoint = 1; dwEndpoint < ENDPOINT_COUNT; ++ dwEndpoint)
			{
				DWORD dwEpBit = EpToIrqStatBit(dwEndpoint);
				if (dwDaint & dwEpBit)
				{
					volatile DWORD dwDiepint = ReadEPSpecificReg(pContext, dwEndpoint, DIEPINT);
					if (dwDiepint & IN_TKN_RECEIVED)
					{
						HandleEndpointEvent(pContext, dwEndpoint, dwDaint);
					}
					if (dwDiepint & TIMEOUT_CONDITION)
					{
						RETAILMSG(1,(TEXT("Time Out EP%x\r\n"),dwEndpoint));
						WriteReg(pContext, DCTL, CLEAR_GNPINNAK);
					}
					WriteEPSpecificReg(pContext, dwEndpoint, DIEPINT, dwDiepint);
				}
			}
		}

		if (dwGintsts & INT_RX_FIFO_NOT_EMPTY)
		{
			volatile DWORD dwGINTMSK = ReadReg(pContext, GINTMSK);
			// Mask INT_RX_FIFO_NOT_EMPTY interrupt
			dwGINTMSK = dwGINTMSK & (~INT_RX_FIFO_NOT_EMPTY);
			WriteReg(pContext, GINTMSK, dwGINTMSK);

			DWORD dwGrxstsp = ReadReg(pContext, GRXSTSP);
			DWORD dwEpnum = dwGrxstsp & 0xf;

			if (dwEpnum == 0)
			{
				if ((dwGrxstsp & PKTSTS) == SETUP_PKT_RECEIVED)
				{
					pContext->CntValue = (dwGrxstsp & 0x7ff0) >> 4;
					HandleEndpoint0Event(pContext);
					WriteReg(pContext, DOEPTSIZ0, 1<<29|1<<19|pContext->dwEp0MaxPktSize);
					WriteReg(pContext, DOEPCTL0, (1<<31)| (1<<26));
				}
				else if((dwGrxstsp & PKTSTS) == OUT_PKT_RECEIVED)
				{
					pContext->CntValue = (dwGrxstsp & 0x7ff0) >> 4;
					HandleEndpoint0Event(pContext);
				}
			}
			else if ((dwGrxstsp & PKTSTS) == OUT_PKT_RECEIVED)
			{
				DWORD dwDaintmsk = ReadReg(pContext, DAINTMSK);
				pContext->CntValue = (dwGrxstsp & 0x7ff0) >> 4;
				if (dwDaintmsk & ((0x1<<dwEpnum)<<ENDPOINT_COUNT))
				{
	                    		HandleEndpointEvent(pContext, dwEpnum, dwDaint);
				}
			}

⌨️ 快捷键说明

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