📄 audioclass.c
字号:
else if ((newAltSetting == ALTSETTING_FOR_AUDIOSTREAMING_IDLE) && (gIsPlaybackActive))
{
Dprintf ("Stopping Playback!");
gIsPlaybackActive = false;
//Disarm the endpoint
DisarmEndpoint (EP1, EP_OUT);
UnprepareEP (EP1);
#if PROVIDE_FEEDBACK
DisarmEndpoint (EP2, EP_IN);
UnprepareEP (EP2);
#endif //PROVIDE_FEEDBACK
//ToDo: Cleanup the codec so that it stops playing
AC97_DisablePlayback();
}
}
}
else
{
if (gIsPlaybackActive)
{
gIsPlaybackActive = false;
//Disarm the endpoint
DisarmEndpoint (EP1, EP_OUT);
UnprepareEP (EP1);
#if PROVIDE_FEEDBACK
DisarmEndpoint (EP2, EP_IN);
UnprepareEP (EP2);
#endif //PROVIDE_FEEDBACK
//ToDo: Cleanup the codec so that it stops playing
AC97_DisablePlayback();
}
//We should disarm the endpoint(s) at this point!
}
return true;
}
/*------------------------------------------------------------
* OnInTransferComplete
*
* Parameters:
* endpointNumber - the endpoint on which the transfer was completed.
*
* Globals Used:
* none
*
* Description:
* This routine is called when a IN transfer is completed on one of the
* endpoints.
*
* Returns:
* Nothing
*
*------------------------------------------------------------*/
void OnInTransferComplete (UCHAR endpointNumber)
{
void *pFeedbackData;
#if PROVIDE_FEEDBACK
if ((endpointNumber == EP2) && (gIsPlaybackActive))
{
if (PrepareINEPForXFer (EP2, &pFeedbackData))
{
memcpy (pFeedbackData, &gFeedbackData, FEEDBACK_PACKET_SIZE);
//Arm the endpoint!
ArmEndpoint (EP2, EP_IN);
}
}
#endif //PROVIDE_FEEDBACK
}
/*------------------------------------------------------------
* OnOutTransferComplete
*
* Parameters:
* endpointNumber - the endpoint on which the transfer was completed.
* buffer - data buffer where the data was received
* numBytesReceived - number of bytes received
* wasPCAsserted - was the PC(packet complete) asserted when the TC interrup
* came in. If not, this could be a possible problem???
*
* Globals Used:
* gIsPlaybackActive
*
* Description:
* This routine is called when a transfer is completed on one of the
* out endpoints. In turn, this routine saves the received data in
* a cyclic buffer.
*
* Returns:
* true to tell the isr to recycle the dma buffer, and setup
* things for the next transfer, false to tell the isr to
* free up the dma buffer, and disarm the endpoint.
*
*------------------------------------------------------------*/
bool OnOutTransferComplete (UCHAR endpointNumber, void *buffer, UINT numBytesReceived, bool wasPCAsserted)
{
UINT inThisPass, currentTail, headTailDistance;
if (!gIsPlaybackActive)
return (false);
gTimeoutCount = 0;
//gDebugNumTransfers++;
//gDebugTotalTransferLength += numBytesReceived;
if ((gDataBufferHead + numBytesReceived) >= MAX_DATA_BUFFER_SIZE)
{
inThisPass = MAX_DATA_BUFFER_SIZE - gDataBufferHead;
memcpy (&gDataBuffer[gDataBufferHead], buffer, inThisPass);
memcpy (&gDataBuffer, (UCHAR *)buffer + inThisPass, numBytesReceived - inThisPass);
gDataBufferHead = numBytesReceived - inThisPass;
}
else
{
memcpy (&gDataBuffer[gDataBufferHead], buffer, numBytesReceived);
gDataBufferHead += numBytesReceived;
}
if (gEnablePlaybackCountdown != 0)
{
gEnablePlaybackCountdown--;
if (gEnablePlaybackCountdown == 0)
AC97_EnablePlayback ();
}
#if PROVIDE_FEEDBACK
else
{
//Check to see if we need to change the feedback Fs?
//Need to latch this value, as the SPORT0 interrupt
//might change it any time!
currentTail = gDataBufferTail;
if (gDataBufferHead >= currentTail)
headTailDistance = gDataBufferHead - currentTail;
else
headTailDistance = (MAX_DATA_BUFFER_SIZE - currentTail) + gDataBufferHead;
if (headTailDistance > ((PLAYBACK_DELAY + 1) * 4 * 48))
{
gFeedbackData = FEEDBACK_FREQUENCY_PLEASE_SLOWDOWN;
//Dprintf2 ("Slow: Head:%d, Tail: %d", gDataBufferHead, currentTail);
}
else if (headTailDistance < ((PLAYBACK_DELAY -1) * 4 * 48))
{
gFeedbackData = FEEDBACK_FREQUENCY_PLEASE_HURRY;
//Dprintf2 ("Hurry: Head:%d, Tail: %d", gDataBufferHead, currentTail);
}
else
gFeedbackData = FEEDBACK_FREQUENCY_NORMAL;
}
#endif //PROVIDE_FEEDBACK
return (true);
}
/*------------------------------------------------------------
* OnNAKSent
*
* Parameters:
* endpointNumber - endpoint where the NAK was sent.
*
* Globals Used:
* gPrepareReport
*
* Description:
* This routine is called when the device has sent a NAK in response
* to an IN or OUT request while the DMA buffer for that endpoint
* has been emptied. Please note that this will only be called in
* response to an "expected" direction request - IN request for
* endpoints setup as IN endpoints and OUT request for endpoints
* setup as OUT endpoints.
*
* Returns:
* Nothing
*
*------------------------------------------------------------*/
void OnNAKSent (UCHAR endpointNumber)
{
}
/*------------------------------------------------------------
* OnSuspend
*
* Parameters:
*
* Globals Used:
* gpOnSuspend
*
* Description:
* This routine will be called when USBDriver detects a
* suspend condition. Currently, it quites the AC97 and forwards
* the call to the client!
*
* Returns:
* Nothing.
*
*------------------------------------------------------------*/
void OnSuspend (void)
{
gIsPlaybackActive = false;
AC97_DisablePlayback ();
if (gpOnSuspend)
(gpOnSuspend)();
}
/*------------------------------------------------------------
* OnResume
*
* Parameters:
*
* Globals Used:
* gpOnResume
*
* Description:
* This routine will be called when the USBDriver detects that
* the bus is out of suspend. Currently, it simply forwards
* the call to the client!
*
* Returns:
* Nothing.
*
*------------------------------------------------------------*/
void OnResume (void)
{
if (gpOnResume)
(gpOnResume) ();
}
/*------------------------------------------------------------
* OnSOF
*
* Parameters: None.
*
* Globals Used:
* gIsPlaybackActive, gTimeoutCount, gDataBufferHead, gDataBufferTail
* gEnablePlaybackCountdown
*
* Description:
* This routine will be called when the USBDriver receives an SOF
* interrupt. It is mainly used to see if the transfers have timed out.
*
* Returns:
* Nothing.
*
*------------------------------------------------------------*/
void OnSOF (void)
{
if (!gIsPlaybackActive)
return;
if (gTimeoutCount > 3)
{
if (gEnablePlaybackCountdown == 0)
{
AC97_DisablePlayback ();
//init the pointers
gDataBufferHead = gDataBufferTail = 0;
gEnablePlaybackCountdown = PLAYBACK_DELAY;
}
}
else
gTimeoutCount++;
}
/*------------------------------------------------------------
* OnReset
*
* Parameters:
*
* Globals Used:
* gpOnReset
*
* Description:
* This routine will be called when the USBDriver detects reset
* signalling on the bus. Currently, it quiets the codec and forwards
* the call to the client!
*
* Returns:
* Nothing.
*
*------------------------------------------------------------*/
void OnReset (void)
{
gIsPlaybackActive = false;
AC97_DisablePlayback ();
if (gpOnReset)
(gpOnReset)();
}
/*----------------------------------------------------------------------------------
* $Log: AudioClass.c,v $
* Revision 1.8 2003/01/17 00:53:10 Devendra
* Commented out a few Dprintfs
*
* Revision 1.7 2003/01/17 00:52:03 Devendra
* - BugFix: Set Volume requests were not handled properly.
* - Changed the feedback speed up and slow down rates to be more aggressive.
*
* Revision 1.6 2003/01/16 19:10:05 Devendra
* - Added code to set AC97 registers for mute and volume controls based on Host requests..
* - Added code to detect "timeout" (no isoch. packets coming in) by implementing OnSOF callback.
* - Added support for AudioClass to perform non-ISR(foreground) tasks.
* - Exposed playback active state variable.
*
* Revision 1.5 2003/01/15 01:35:14 Devendra
* Added code to provide feedback to pace control the isoch. pipe.
*
* Revision 1.4 2003/01/13 19:56:18 Devendra
* Moved the data buffer to ac97.c
* Added code to enuser "distance" between buffer head and tail (latency).
* BugFix: buffer copy was not proper.
* Separated Descriptors to a separate header.
*
* Revision 1.2 2003/01/10 01:53:55 Devendra
* - Added support for receiving a playback stream on isoch. endpoint and storing the data in a cyclic buffer.
*
* Revision 1.1 2003/01/09 01:16:35 Devendra
* First Rev of AudioClass - have the device enumerated as audio device, and the volume control and mute are functional!
*
* Revision 1.1 2002/10/31 00:30:59 Devendra
* Moved all files in one folder to avoid IDE related problems.
*
* Revision 1.3 2002/10/30 02:36:40 Devendra
* - Added more abstraction to HIDCLASS. So that it's possible to build
* different devices without making any changes to the HIDCLASS module.
* - Added proper support for handling USB SUSPEND, RESUME, and RESET events.
*
* Revision 1.2 2002/10/22 17:50:54 Devendra
* - Changed Product ID to 0x0005
*
* Revision 1.1 2002/10/22 17:23:38 Devendra
* Rearranged file locations.
*
* Revision 1.6 2002/10/14 05:16:48 Devendra
* Updated version number.
*
* Revision 1.5 2002/10/14 05:16:04 Devendra
* - Custom Device now using Feature reports for I/O
* - Added compiler define/project configuration to switch between mouse and custom device.
*
* Revision 1.4 2002/10/14 01:33:15 Devendra
* Got "custom" device functional with buttons and lights!
*
* Revision 1.3 2002/10/09 17:09:32 Devendra
* - Added support for handling IN endpoints.
* - Added HID descriptors (HID and HID Report)
* - Modified the Interface descriptors to comply to HID Class Spec.
* - Added functionality to use the push-buttons on the Eagle-35 as a mouse (for buttons as well as for movement).
* - The device is now a fully functioning USB Mouse!
*
* Revision 1.2 2002/10/08 19:57:02 Devendra
* - Added specific callbacks for getting Device, Config, and String descriptors.
* - BugFix: Max. Packet Size was not being set correctly in ArmEndpoint.
* - Added internal buffer based logging to allow real-time "printfs".
* - Added String descriptors.
*
* Revision 1.1 2002/09/20 06:51:30 Devendra
* First Rev.
*
*
*---------------------------------------------------------------------------------*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -