/*---------------------------------------------------------------------------* Project: TwlSDK - libraries - snd - common File: snd_command.c Copyright 2004-2008 Nintendo. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Date:: 2008-09-18#$ $Rev: 8573 $ $Author: okubata_ryoma $ *---------------------------------------------------------------------------*/ #include #include #include #include #include #include #include #include #include #include #include #include /****************************************************************************** Macro definitions ******************************************************************************/ #define SND_COMMAND_NUM 256 #define SND_PXI_FIFO_MESSAGE_BUFSIZE 8 #define SND_MSG_REQUEST_COMMAND_PROC 0 #define UNPACK_COMMAND( arg, shift, bit ) ( ( (arg) >> (shift) ) & ( ( 1 << (bit) ) - 1 ) ) /****************************************************************************** Static variable ******************************************************************************/ #ifdef SDK_ARM9 static SNDCommand sCommandArray[SND_COMMAND_NUM] ATTRIBUTE_ALIGN(32); /* Command array */ static SNDCommand *sFreeList; /* Free command list */ static SNDCommand *sFreeListEnd; /* End of free command list */ static SNDCommand *sReserveList; /* Reserved command list */ static SNDCommand *sReserveListEnd; /* End of reserved command list */ static SNDCommand *sWaitingCommandListQueue[SND_PXI_FIFO_MESSAGE_BUFSIZE + 1]; static int sWaitingCommandListQueueRead; static int sWaitingCommandListQueueWrite; static int sWaitingCommandListCount; /* Issued command list count */ static u32 sCurrentTag; /* Current tag */ static u32 sFinishedTag; /* Completed tag */ static SNDSharedWork sSharedWork ATTRIBUTE_ALIGN(32); #else /* SDK_ARM7 */ static OSMessage sCommandMesgBuffer[SND_PXI_FIFO_MESSAGE_BUFSIZE]; static OSMessageQueue sCommandMesgQueue; #endif /* SDK_ARM9 */ /****************************************************************************** Static function declarations ******************************************************************************/ static void PxiFifoCallback(PXIFifoTag tag, u32 data, BOOL err); static void InitPXI(void); #ifdef SDK_ARM9 static void RequestCommandProc(void); static SNDCommand *AllocCommand(void); static BOOL IsCommandAvailable(void); #else static void SetChannelTimer(u32 chBitMask, int timer); static void SetChannelVolume(u32 chBitMask, int volume, SNDChannelDataShift shift); static void SetChannelPan(u32 chBitMask, int pan); static void StartTimer(u32 chBitMask, u32 capBitMask, u32 alarmBitMask, u32 flags); static void StopTimer(u32 chBitMask, u32 capBitMask, u32 alarmBitMask, u32 flags); static void ReadDriverInfo(SNDDriverInfo * info); #endif /****************************************************************************** Public functions ******************************************************************************/ /*---------------------------------------------------------------------------* Name: SND_CommandInit Description: Initializes the command library. Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ void SND_CommandInit(void) { #ifdef SDK_ARM9 SNDCommand *command; int i; #endif /* SDK_ARM9 */ #ifdef SDK_ARM7 OS_InitMessageQueue(&sCommandMesgQueue, sCommandMesgBuffer, SND_PXI_FIFO_MESSAGE_BUFSIZE); #endif InitPXI(); #ifdef SDK_ARM9 /* Create free list */ sFreeList = &sCommandArray[0]; for (i = 0; i < SND_COMMAND_NUM - 1; i++) { sCommandArray[i].next = &sCommandArray[i + 1]; } sCommandArray[SND_COMMAND_NUM - 1].next = NULL; sFreeListEnd = &sCommandArray[SND_COMMAND_NUM - 1]; /* Initialize reserve list */ sReserveList = NULL; sReserveListEnd = NULL; /* Initialize other variables */ sWaitingCommandListCount = 0; sWaitingCommandListQueueRead = 0; sWaitingCommandListQueueWrite = 0; sCurrentTag = 1; sFinishedTag = 0; /* Initialize shared work */ SNDi_SharedWork = &sSharedWork; SNDi_InitSharedWork(SNDi_SharedWork); command = SND_AllocCommand(SND_COMMAND_BLOCK); if (command != NULL) { command->id = SND_COMMAND_SHARED_WORK; command->arg[0] = (u32)SNDi_SharedWork; SND_PushCommand(command); (void)SND_FlushCommand(SND_COMMAND_BLOCK); } #else /* SDK_ARM7 */ SNDi_SharedWork = NULL; #endif /* SDK_ARM9 */ } #ifdef SDK_ARM9 /*---------------------------------------------------------------------------* Name: SND_RecvCommandReply Description: Receives reply (ThreadSafe). Arguments: flags - BLOCK or NOBLOCK Returns: Processed command list, or NULL. *---------------------------------------------------------------------------*/ const SNDCommand *SND_RecvCommandReply(u32 flags) { OSIntrMode bak_psr = OS_DisableInterrupts(); SNDCommand *commandList; SNDCommand *commandListEnd; if (flags & SND_COMMAND_BLOCK) { while (sFinishedTag == SNDi_GetFinishedCommandTag()) { // Retry (void)OS_RestoreInterrupts(bak_psr); OS_SpinWait(100); bak_psr = OS_DisableInterrupts(); } } else { if (sFinishedTag == SNDi_GetFinishedCommandTag()) { (void)OS_RestoreInterrupts(bak_psr); return NULL; } } /* POP from the waiting command list */ commandList = sWaitingCommandListQueue[sWaitingCommandListQueueRead]; sWaitingCommandListQueueRead++; if (sWaitingCommandListQueueRead > SND_PXI_FIFO_MESSAGE_BUFSIZE) sWaitingCommandListQueueRead = 0; /* Get the end of the command list */ commandListEnd = commandList; while (commandListEnd->next != NULL) { commandListEnd = commandListEnd->next; } /* Join to the end of the free list */ if (sFreeListEnd != NULL) { sFreeListEnd->next = commandList; } else { sFreeList = commandList; } sFreeListEnd = commandListEnd; /* Update counter */ sWaitingCommandListCount--; sFinishedTag++; (void)OS_RestoreInterrupts(bak_psr); return commandList; } /*---------------------------------------------------------------------------* Name: SND_AllocCommand Description: Allocates command (ThreadSafe). Arguments: flags - BLOCK or NOBLOCK Returns: Commands. *---------------------------------------------------------------------------*/ SNDCommand *SND_AllocCommand(u32 flags) { SNDCommand *command; if (!IsCommandAvailable()) return NULL; command = AllocCommand(); if (command != NULL) return command; if ((flags & SND_COMMAND_BLOCK) == 0) return NULL; if (SND_CountWaitingCommand() > 0) { /* There are commands waiting to be processed */ /* Try receiving the completed command list */ while (SND_RecvCommandReply(SND_COMMAND_NOBLOCK) != NULL) { } /* Is there a free command? */ command = AllocCommand(); if (command != NULL) return command; } else { /* There are no commands waiting to be processed */ /* Issue the current command list */ (void)SND_FlushCommand(SND_COMMAND_BLOCK); } /* Request immediate processing */ RequestCommandProc(); /* Wait for command processing to complete */ do { (void)SND_RecvCommandReply(SND_COMMAND_BLOCK); command = AllocCommand(); } while (command == NULL); return command; } /*---------------------------------------------------------------------------* Name: SND_PushCommand Description: Adds a command to the command list (ThreadSafe). Arguments: Command to add Returns: None. *---------------------------------------------------------------------------*/ void SND_PushCommand(struct SNDCommand *command) { OSIntrMode bak_psr; SDK_NULL_ASSERT(command); bak_psr = OS_DisableInterrupts(); // Add to end of sReserveList if (sReserveListEnd == NULL) { sReserveList = command; sReserveListEnd = command; } else { sReserveListEnd->next = command; sReserveListEnd = command; } command->next = NULL; (void)OS_RestoreInterrupts(bak_psr); } /*---------------------------------------------------------------------------* Name: SND_FlushCommand Description: Sends the command list (ThreadSafe). Arguments: flags - BLOCK or NOBLOCK Returns: Whether it was successful. *---------------------------------------------------------------------------*/ BOOL SND_FlushCommand(u32 flags) { OSIntrMode bak_psr = OS_DisableInterrupts(); if (sReserveList == NULL) { /* There are no reserved commands, so do nothing */ (void)OS_RestoreInterrupts(bak_psr); return TRUE; } if (sWaitingCommandListCount >= SND_PXI_FIFO_MESSAGE_BUFSIZE) { /* A backlog of command processing on ARM7 has built up */ if ((flags & SND_COMMAND_BLOCK) == 0) { (void)OS_RestoreInterrupts(bak_psr); return FALSE; } do { (void)SND_RecvCommandReply(SND_COMMAND_BLOCK); } while (sWaitingCommandListCount >= SND_PXI_FIFO_MESSAGE_BUFSIZE); /* Verified again in SND_RecvCommandReply because of the occurrence of interrupt processing */ if (sReserveList == NULL) { /* There are no reserved commands, so do nothing */ (void)OS_RestoreInterrupts(bak_psr); return TRUE; } } /* Issue command list */ DC_FlushRange(sCommandArray, sizeof(sCommandArray)); if (PXI_SendWordByFifo(PXI_FIFO_TAG_SOUND, (u32)sReserveList, FALSE) < 0) { if ((flags & SND_COMMAND_BLOCK) == 0) { (void)OS_RestoreInterrupts(bak_psr); return FALSE; } while (sWaitingCommandListCount >= SND_PXI_FIFO_MESSAGE_BUFSIZE || PXI_SendWordByFifo(PXI_FIFO_TAG_SOUND, (u32)sReserveList, FALSE) < 0) { /* Wait until successful */ (void)OS_RestoreInterrupts(bak_psr); (void)SND_RecvCommandReply(SND_COMMAND_NOBLOCK); bak_psr = OS_DisableInterrupts(); DC_FlushRange(sCommandArray, sizeof(sCommandArray)); /* Verified again because of the occurrence of interrupt processing */ if (sReserveList == NULL) { /* There are no reserved commands, so do nothing */ (void)OS_RestoreInterrupts(bak_psr); return TRUE; } } } /* PUSH into the command wait queue */ sWaitingCommandListQueue[sWaitingCommandListQueueWrite] = sReserveList; sWaitingCommandListQueueWrite++; if (sWaitingCommandListQueueWrite > SND_PXI_FIFO_MESSAGE_BUFSIZE) sWaitingCommandListQueueWrite = 0; /* Update variables */ sReserveList = NULL; sReserveListEnd = NULL; sWaitingCommandListCount++; sCurrentTag++; (void)OS_RestoreInterrupts(bak_psr); if (flags & SND_COMMAND_IMMEDIATE) { /* Request immediate command processing */ RequestCommandProc(); } return TRUE; } /*---------------------------------------------------------------------------* Name: SND_WaitForCommandProc Description: Synchronizes the completion of command processing (ThreadSafe). Arguments: tag - Command tag Returns: None. *---------------------------------------------------------------------------*/ void SND_WaitForCommandProc(u32 tag) { if (SND_IsFinishedCommandTag(tag)) { /* Already completed */ return; } /* Try receiving the completed command list */ while (SND_RecvCommandReply(SND_COMMAND_NOBLOCK) != NULL) { } if (SND_IsFinishedCommandTag(tag)) { /* It has completed */ return; } /* Request immediate command processing */ RequestCommandProc(); /* Wait for finish */ while (!SND_IsFinishedCommandTag(tag)) { (void)SND_RecvCommandReply(SND_COMMAND_BLOCK); } } /*---------------------------------------------------------------------------* Name: SND_WaitForFreeCommand Description: Waits for free commands (ThreadSafe). Arguments: count - Required number of free commands Returns: None. *---------------------------------------------------------------------------*/ void SND_WaitForFreeCommand(int count) { int freeCount = SND_CountFreeCommand(); SDK_MAX_ASSERT(count, SND_COMMAND_NUM); if (freeCount >= count) return; if (freeCount + SND_CountWaitingCommand() >= count) { /* OK if we wait for the completion of a command waiting to be processed */ /* Try receiving the completed command list */ while (SND_RecvCommandReply(SND_COMMAND_NOBLOCK) != NULL) { } /* Is there a free command? */ if (SND_CountFreeCommand() >= count) return; } else { /* It is necessary to process reserved commands */ /* Issue the current command list */ (void)SND_FlushCommand(SND_COMMAND_BLOCK); } /* Request immediate processing */ RequestCommandProc(); /* Wait for command processing to complete */ do { (void)SND_RecvCommandReply(SND_COMMAND_BLOCK); } while (SND_CountFreeCommand() < count); } /*---------------------------------------------------------------------------* Name: SND_GetCurrentCommandTag Description: Gets command tag (ThreadSafe). Arguments: None. Returns: Command tag. *---------------------------------------------------------------------------*/ u32 SND_GetCurrentCommandTag(void) { OSIntrMode bak_psr = OS_DisableInterrupts(); u32 tag; if (sReserveList == NULL) { tag = sFinishedTag; } else { tag = sCurrentTag; } (void)OS_RestoreInterrupts(bak_psr); return tag; } /*---------------------------------------------------------------------------* Name: SND_IsFinishedCommandTag Description: Checks whether or not a command tag has already been processed (ThreadSafe). Arguments: tag - Command tag Returns: Whether it was processed or not. *---------------------------------------------------------------------------*/ BOOL SND_IsFinishedCommandTag(u32 tag) { OSIntrMode bak_psr = OS_DisableInterrupts(); BOOL result; if (tag > sFinishedTag) { if (tag - sFinishedTag < 0x80000000) { result = FALSE; } else { result = TRUE; } } else { if (sFinishedTag - tag < 0x80000000) { result = TRUE; } else { result = FALSE; } } (void)OS_RestoreInterrupts(bak_psr); return result; } /*---------------------------------------------------------------------------* Name: SND_CountFreeCommand Description: Gets the number of free commands (ThreadSafe). Arguments: None. Returns: Number of free commands. *---------------------------------------------------------------------------*/ int SND_CountFreeCommand(void) { OSIntrMode bak_psr = OS_DisableInterrupts(); SNDCommand *command; int count = 0; command = sFreeList; while (command != NULL) { ++count; command = command->next; } (void)OS_RestoreInterrupts(bak_psr); return count; } /*---------------------------------------------------------------------------* Name: SND_CountReservedCommand Description: Gets the number of reserved commands (ThreadSafe). Arguments: None. Returns: Number of reserved commands. *---------------------------------------------------------------------------*/ int SND_CountReservedCommand(void) { OSIntrMode bak_psr = OS_DisableInterrupts(); SNDCommand *command; int count = 0; command = sReserveList; while (command != NULL) { ++count; command = command->next; } (void)OS_RestoreInterrupts(bak_psr); return count; } /*---------------------------------------------------------------------------* Name: SND_CountWaitingCommand Description: Gets the number of commands waiting to be processed (ThreadSafe). Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ int SND_CountWaitingCommand(void) { int freeCount = SND_CountFreeCommand(); int reservedCount = SND_CountReservedCommand(); return SND_COMMAND_NUM - freeCount - reservedCount; } #else /* SDK_ARM7 */ /*---------------------------------------------------------------------------* Name: SND_CommandProc Description: Processes the command list. Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ void SND_CommandProc(void) { OSMessage message; const SNDCommand *command_p; SNDCommand command; while (OS_ReceiveMessage(&sCommandMesgQueue, &message, OS_MESSAGE_NOBLOCK)) { command_p = (const SNDCommand *)message; while (command_p != NULL) { // Note: MainMemory Access command = *command_p; switch (command.id) { case SND_COMMAND_START_SEQ: SND_StartSeq((int)command.arg[0], (const void *)command.arg[1], command.arg[2], (struct SNDBankData *)command.arg[3]); break; case SND_COMMAND_STOP_SEQ: SND_StopSeq((int)command.arg[0]); break; case SND_COMMAND_PREPARE_SEQ: SND_PrepareSeq((int)command.arg[0], (const void *)command.arg[1], command.arg[2], (struct SNDBankData *)command.arg[3]); break; case SND_COMMAND_START_PREPARED_SEQ: SND_StartPreparedSeq((int)command.arg[0]); break; case SND_COMMAND_PAUSE_SEQ: SND_PauseSeq((int)command.arg[0], (BOOL)command.arg[1]); break; case SND_COMMAND_SKIP_SEQ: SND_SkipSeq((int)command.arg[0], (u32)command.arg[1]); break; case SND_COMMAND_PLAYER_PARAM: SNDi_SetPlayerParam((int)command.arg[0], command.arg[1], command.arg[2], (int)command.arg[3]); break; case SND_COMMAND_TRACK_PARAM: SNDi_SetTrackParam((int)UNPACK_COMMAND(command.arg[0], 0, 24), command.arg[1], command.arg[2], command.arg[3], (int)UNPACK_COMMAND(command.arg[0], 24, 8)); break; case SND_COMMAND_MUTE_TRACK: SND_SetTrackMute((int)command.arg[0], command.arg[1], (SNDSeqMute) command.arg[2]); break; case SND_COMMAND_ALLOCATABLE_CHANNEL: SND_SetTrackAllocatableChannel((int)command.arg[0], command.arg[1], command.arg[2]); break; case SND_COMMAND_PLAYER_LOCAL_VAR: SND_SetPlayerLocalVariable((int)command.arg[0], (int)command.arg[1], (s16)command.arg[2]); break; case SND_COMMAND_PLAYER_GLOBAL_VAR: SND_SetPlayerGlobalVariable((int)command.arg[0], (s16)command.arg[1]); break; case SND_COMMAND_START_TIMER: StartTimer(command.arg[0], command.arg[1], command.arg[2], command.arg[3]); break; case SND_COMMAND_STOP_TIMER: StopTimer(command.arg[0], command.arg[1], command.arg[2], command.arg[3]); break; case SND_COMMAND_SETUP_CAPTURE: SND_SetupCapture((SNDCapture)UNPACK_COMMAND(command.arg[2], 31, 1), (SNDCaptureFormat)UNPACK_COMMAND(command.arg[2], 30, 1), (void *)command.arg[0], (int)command.arg[1], (BOOL)UNPACK_COMMAND(command.arg[2], 29, 1), (SNDCaptureIn)UNPACK_COMMAND(command.arg[2], 28, 1), (SNDCaptureOut)UNPACK_COMMAND(command.arg[2], 27, 1)); break; case SND_COMMAND_SETUP_ALARM: SND_SetupAlarm((int)command.arg[0], (OSTick)command.arg[1], (OSTick)command.arg[2], (int)command.arg[3]); break; case SND_COMMAND_CHANNEL_TIMER: SetChannelTimer((u32)command.arg[0], (int)command.arg[1]); break; case SND_COMMAND_CHANNEL_VOLUME: SetChannelVolume((u32)command.arg[0], (int)command.arg[1], (SNDChannelDataShift)command.arg[2]); break; case SND_COMMAND_CHANNEL_PAN: SetChannelPan((u32)command.arg[0], (int)command.arg[1]); break; case SND_COMMAND_SETUP_CHANNEL_PCM: SND_SetupChannelPcm((int)UNPACK_COMMAND(command.arg[0], 0, 16), /* chNo */ (const void *)UNPACK_COMMAND(command.arg[1], 0, 27), /* dataaddr */ (SNDWaveFormat)UNPACK_COMMAND(command.arg[3], 24, 2), /* format */ (SNDChannelLoop)UNPACK_COMMAND(command.arg[3], 26, 2), /* loop */ (int)UNPACK_COMMAND(command.arg[3], 0, 16), /* loopStart */ (int)UNPACK_COMMAND(command.arg[2], 0, 22), /* loopLen */ (int)UNPACK_COMMAND(command.arg[2], 24, 7), /* volume */ (SNDChannelDataShift)UNPACK_COMMAND(command.arg[2], 22, 2), /* SHIFT */ (int)UNPACK_COMMAND(command.arg[0], 16, 16), /* timer */ (int)UNPACK_COMMAND(command.arg[3], 16, 7) /* pan */ ); break; case SND_COMMAND_SETUP_CHANNEL_PSG: SND_SetupChannelPsg((int)command.arg[0], /* chNo */ (SNDDuty)command.arg[3], /* duty */ (int)UNPACK_COMMAND(command.arg[1], 0, 7), /* volume */ (SNDChannelDataShift)UNPACK_COMMAND(command.arg[1], 8, 2), /* SHIFT */ (int)UNPACK_COMMAND(command.arg[2], 8, 16), /* timer */ (int)UNPACK_COMMAND(command.arg[2], 0, 7) /* pan */ ); break; case SND_COMMAND_SETUP_CHANNEL_NOISE: SND_SetupChannelNoise((int)command.arg[0], /* chNo */ (int)UNPACK_COMMAND(command.arg[1], 0, 7), /* volume */ (SNDChannelDataShift)UNPACK_COMMAND(command.arg[1], 8, 2), /* SHIFT */ (int)UNPACK_COMMAND(command.arg[2], 8, 16), /* timer */ (int)UNPACK_COMMAND(command.arg[2], 0, 7) /* pan */ ); break; case SND_COMMAND_SURROUND_DECAY: SNDi_SetSurroundDecay((int)command.arg[0]); break; case SND_COMMAND_MASTER_VOLUME: SND_SetMasterVolume((int)command.arg[0]); break; case SND_COMMAND_MASTER_PAN: SND_SetMasterPan((int)command.arg[0]); break; case SND_COMMAND_OUTPUT_SELECTOR: SND_SetOutputSelector((SNDOutput)command.arg[0], (SNDOutput)command.arg[1], (SNDChannelOut)command.arg[2], (SNDChannelOut)command.arg[3]); break; case SND_COMMAND_LOCK_CHANNEL: SND_LockChannel(command.arg[0], command.arg[1]); break; case SND_COMMAND_UNLOCK_CHANNEL: SND_UnlockChannel(command.arg[0], command.arg[1]); break; case SND_COMMAND_STOP_UNLOCKED_CHANNEL: SND_StopUnlockedChannel(command.arg[0], command.arg[1]); break; case SND_COMMAND_INVALIDATE_SEQ: SND_InvalidateSeq((const void *)command.arg[0], (const void *)command.arg[1]); break; case SND_COMMAND_INVALIDATE_BANK: SND_InvalidateBank((const void *)command.arg[0], (const void *)command.arg[1]); break; case SND_COMMAND_INVALIDATE_WAVE: SND_InvalidateWave((const void *)command.arg[0], (const void *)command.arg[1]); break; case SND_COMMAND_SHARED_WORK: SNDi_SharedWork = (SNDSharedWork *)command.arg[0]; break; case SND_COMMAND_READ_DRIVER_INFO: ReadDriverInfo((SNDDriverInfo *) command.arg[0]); break; } command_p = command.next; } // end of while ( command_p != NULL ) /* Command list processing complete */ SDK_NULL_ASSERT(SNDi_SharedWork); SNDi_SharedWork->finishCommandTag++; } } #endif /* SDK_ARM9 */ /****************************************************************************** Static function ******************************************************************************/ /*---------------------------------------------------------------------------* Name: PxiFifoCallback Description: PXI callback. Arguments: tag - PXI tag data - User data (address or message number) err - Error flag Returns: None. *---------------------------------------------------------------------------*/ static void PxiFifoCallback(PXIFifoTag tag, u32 data, BOOL /*err */ ) { OSIntrMode enabled; BOOL result; #ifdef SDK_DEBUG SDK_ASSERT(tag == PXI_FIFO_TAG_SOUND); #else #pragma unused( tag ) #endif enabled = OS_DisableInterrupts(); #ifdef SDK_ARM9 #pragma unused( result ) SNDi_CallAlarmHandler((int)data); #else /* SDK_ARM7 */ if (data >= HW_MAIN_MEM) { /* This is controlled by the sender, so it should not fail */ result = OS_SendMessage(&sCommandMesgQueue, (OSMessage)data, OS_MESSAGE_NOBLOCK); SDK_ASSERTMSG(result, "Failed OS_SendMessage"); } else { switch (data) { case SND_MSG_REQUEST_COMMAND_PROC: { (void)SND_SendWakeupMessage(); break; } } } #endif /* SDK_ARM9 */ (void)OS_RestoreInterrupts(enabled); } /*---------------------------------------------------------------------------* Name: InitPXI Description: Initializes PXI. Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ static void InitPXI(void) { // Register the callback and attempt initial synchronization with the other party PXI_SetFifoRecvCallback(PXI_FIFO_TAG_SOUND, PxiFifoCallback); #ifdef SDK_ARM9 if (IsCommandAvailable()) { while (!PXI_IsCallbackReady(PXI_FIFO_TAG_SOUND, PXI_PROC_ARM7)) { OS_SpinWait(100); } } #endif } #ifdef SDK_ARM9 /*---------------------------------------------------------------------------* Name: RequestCommandProc Description: Request command processing (ThreadSafe). Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ static void RequestCommandProc(void) { while (PXI_SendWordByFifo(PXI_FIFO_TAG_SOUND, SND_MSG_REQUEST_COMMAND_PROC, FALSE) < 0) { // retry } } /*---------------------------------------------------------------------------* Name: AllocCommand Description: Allocates command (ThreadSafe). Arguments: None. Returns: Command or NULL. *---------------------------------------------------------------------------*/ static SNDCommand *AllocCommand(void) { OSIntrMode bak_psr = OS_DisableInterrupts(); SNDCommand *command; if (sFreeList == NULL) { (void)OS_RestoreInterrupts(bak_psr); return NULL; } command = sFreeList; sFreeList = sFreeList->next; if (sFreeList == NULL) sFreeListEnd = NULL; (void)OS_RestoreInterrupts(bak_psr); return command; } /*---------------------------------------------------------------------------* Name: IsCommandAvailable Description: Checks the validity of a command routine. Arguments: None. Returns: Whether or not the command routine is valid. *---------------------------------------------------------------------------*/ static BOOL IsCommandAvailable(void) { OSIntrMode prev_mode; u32 res; if (!OS_IsRunOnEmulator()) return TRUE; prev_mode = OS_DisableInterrupts(); /* Confirm sound validity */ *(vu32 *)0x4fff200 = 0x10; res = *(vu32 *)0x4fff200; (void)OS_RestoreInterrupts(prev_mode); return res ? TRUE : FALSE; } #else /* SDK_ARM7 */ static void SetChannelTimer(u32 chBitMask, int timer) { int ch; for (ch = 0; ch < SND_CHANNEL_NUM && chBitMask != 0; ch++, chBitMask >>= 1) { if ((chBitMask & 0x01) == 0) continue; SND_SetChannelTimer(ch, timer); } } static void SetChannelVolume(u32 chBitMask, int volume, SNDChannelDataShift shift) { int ch; for (ch = 0; ch < SND_CHANNEL_NUM && chBitMask != 0; ch++, chBitMask >>= 1) { if ((chBitMask & 0x01) == 0) continue; SND_SetChannelVolume(ch, volume, shift); } } static void SetChannelPan(u32 chBitMask, int pan) { int ch; for (ch = 0; ch < SND_CHANNEL_NUM && chBitMask != 0; ch++, chBitMask >>= 1) { if ((chBitMask & 0x01) == 0) continue; SND_SetChannelPan(ch, pan); } } static void StartTimer(u32 chBitMask, u32 capBitMask, u32 alarmBitMask, u32 /*flags */ ) { OSIntrMode enabled; int i; enabled = OS_DisableInterrupts(); for (i = 0; i < SND_CHANNEL_NUM && chBitMask != 0; i++, chBitMask >>= 1) { if ((chBitMask & 0x01) == 0) continue; SND_StartChannel(i); } if (capBitMask & (1 << SND_CAPTURE_0)) { if (capBitMask & (1 << SND_CAPTURE_1)) { SND_StartCaptureBoth(); } else { SND_StartCapture(SND_CAPTURE_0); } } else if (capBitMask & (1 << SND_CAPTURE_1)) { SND_StartCapture(SND_CAPTURE_1); } for (i = 0; i < SND_ALARM_NUM && alarmBitMask != 0; i++, alarmBitMask >>= 1) { if ((alarmBitMask & 0x01) == 0) continue; SND_StartAlarm(i); } (void)OS_RestoreInterrupts(enabled); SND_UpdateSharedWork(); } static void StopTimer(u32 chBitMask, u32 capBitMask, u32 alarmBitMask, u32 flags) { OSIntrMode enabled; int i; enabled = OS_DisableInterrupts(); for (i = 0; i < SND_ALARM_NUM && alarmBitMask != 0; i++, alarmBitMask >>= 1) { if ((alarmBitMask & 0x01) == 0) continue; SND_StopAlarm(i); } for (i = 0; i < SND_CHANNEL_NUM && chBitMask != 0; i++, chBitMask >>= 1) { if ((chBitMask & 0x01) == 0) continue; SND_StopChannel(i, (s32)flags); } if (capBitMask & (1 << SND_CAPTURE_0)) { SND_StopCapture(SND_CAPTURE_0); } if (capBitMask & (1 << SND_CAPTURE_1)) { SND_StopCapture(SND_CAPTURE_1); } (void)OS_RestoreInterrupts(enabled); SND_UpdateSharedWork(); } static void ReadDriverInfo(SNDDriverInfo * info) { int ch; MI_CpuCopy32(&SNDi_Work, &info->work, sizeof(SNDi_Work)); info->workAddress = &SNDi_Work; for (ch = 0; ch < SND_CHANNEL_NUM; ch++) { info->chCtrl[ch] = SND_GetChannelControl(ch); } info->lockedChannels = SND_GetLockedChannel(0); } #endif /* SDK_ARM9 */ /*====== End of snd_command.c ======*/