1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - libraries - snd - common
3   File:     snd_command.c
4 
5   Copyright 2004-2008 Nintendo. All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law. They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Date:: 2008-09-18#$
14   $Rev: 8573 $
15   $Author: okubata_ryoma $
16  *---------------------------------------------------------------------------*/
17 
18 #include <nitro/snd/common/command.h>
19 
20 #include <nitro/misc.h>
21 #include <nitro/os.h>
22 #include <nitro/pxi.h>
23 #include <nitro/mi.h>
24 
25 #include <nitro/snd/common/seq.h>
26 #include <nitro/snd/common/capture.h>
27 #include <nitro/snd/common/work.h>
28 #include <nitro/snd/common/global.h>
29 #include <nitro/snd/common/util.h>
30 #include <nitro/snd/common/alarm.h>
31 #include <nitro/snd/common/main.h>
32 
33 /******************************************************************************
34     Macro definitions
35  ******************************************************************************/
36 
37 #define SND_COMMAND_NUM 256
38 
39 #define SND_PXI_FIFO_MESSAGE_BUFSIZE   8
40 
41 #define SND_MSG_REQUEST_COMMAND_PROC   0
42 
43 #define UNPACK_COMMAND( arg, shift, bit ) ( ( (arg) >> (shift) ) & ( ( 1 << (bit) ) - 1 ) )
44 
45 /******************************************************************************
46     Static variable
47  ******************************************************************************/
48 
49 #ifdef SDK_ARM9
50 
51 static SNDCommand sCommandArray[SND_COMMAND_NUM] ATTRIBUTE_ALIGN(32);   /* Command array */
52 static SNDCommand *sFreeList;          /* Free command list */
53 static SNDCommand *sFreeListEnd;       /* End of free command list */
54 
55 static SNDCommand *sReserveList;       /* Reserved command list */
56 static SNDCommand *sReserveListEnd;    /* End of reserved command list */
57 
58 static SNDCommand *sWaitingCommandListQueue[SND_PXI_FIFO_MESSAGE_BUFSIZE + 1];
59 static int sWaitingCommandListQueueRead;
60 static int sWaitingCommandListQueueWrite;
61 
62 static int sWaitingCommandListCount;   /* Issued command list count */
63 
64 static u32 sCurrentTag;                /* Current tag */
65 static u32 sFinishedTag;               /* Completed tag */
66 
67 static SNDSharedWork sSharedWork ATTRIBUTE_ALIGN(32);
68 
69 #else  /* SDK_ARM7 */
70 
71 static OSMessage sCommandMesgBuffer[SND_PXI_FIFO_MESSAGE_BUFSIZE];
72 static OSMessageQueue sCommandMesgQueue;
73 
74 #endif /* SDK_ARM9 */
75 
76 
77 /******************************************************************************
78     Static function declarations
79  ******************************************************************************/
80 
81 static void PxiFifoCallback(PXIFifoTag tag, u32 data, BOOL err);
82 static void InitPXI(void);
83 
84 #ifdef SDK_ARM9
85 static void RequestCommandProc(void);
86 static SNDCommand *AllocCommand(void);
87 static BOOL IsCommandAvailable(void);
88 #else
89 static void SetChannelTimer(u32 chBitMask, int timer);
90 static void SetChannelVolume(u32 chBitMask, int volume, SNDChannelDataShift shift);
91 static void SetChannelPan(u32 chBitMask, int pan);
92 static void StartTimer(u32 chBitMask, u32 capBitMask, u32 alarmBitMask, u32 flags);
93 static void StopTimer(u32 chBitMask, u32 capBitMask, u32 alarmBitMask, u32 flags);
94 static void ReadDriverInfo(SNDDriverInfo * info);
95 #endif
96 
97 /******************************************************************************
98     Public functions
99  ******************************************************************************/
100 
101 /*---------------------------------------------------------------------------*
102   Name:         SND_CommandInit
103 
104   Description:  Initializes the command library.
105 
106   Arguments:    None.
107 
108   Returns:      None.
109  *---------------------------------------------------------------------------*/
SND_CommandInit(void)110 void SND_CommandInit(void)
111 {
112 #ifdef SDK_ARM9
113     SNDCommand *command;
114     int     i;
115 #endif /* SDK_ARM9 */
116 
117 #ifdef SDK_ARM7
118     OS_InitMessageQueue(&sCommandMesgQueue, sCommandMesgBuffer, SND_PXI_FIFO_MESSAGE_BUFSIZE);
119 #endif
120 
121     InitPXI();
122 
123 #ifdef SDK_ARM9
124     /* Create free list */
125     sFreeList = &sCommandArray[0];
126     for (i = 0; i < SND_COMMAND_NUM - 1; i++)
127     {
128         sCommandArray[i].next = &sCommandArray[i + 1];
129     }
130     sCommandArray[SND_COMMAND_NUM - 1].next = NULL;
131     sFreeListEnd = &sCommandArray[SND_COMMAND_NUM - 1];
132 
133     /* Initialize reserve list */
134     sReserveList = NULL;
135     sReserveListEnd = NULL;
136 
137     /* Initialize other variables */
138     sWaitingCommandListCount = 0;
139 
140     sWaitingCommandListQueueRead = 0;
141     sWaitingCommandListQueueWrite = 0;
142 
143     sCurrentTag = 1;
144     sFinishedTag = 0;
145 
146     /* Initialize shared work */
147     SNDi_SharedWork = &sSharedWork;
148     SNDi_InitSharedWork(SNDi_SharedWork);
149 
150     command = SND_AllocCommand(SND_COMMAND_BLOCK);
151     if (command != NULL)
152     {
153         command->id = SND_COMMAND_SHARED_WORK;
154         command->arg[0] = (u32)SNDi_SharedWork;
155 
156         SND_PushCommand(command);
157         (void)SND_FlushCommand(SND_COMMAND_BLOCK);
158     }
159 
160 #else  /* SDK_ARM7 */
161 
162     SNDi_SharedWork = NULL;
163 
164 #endif /* SDK_ARM9 */
165 }
166 
167 
168 #ifdef SDK_ARM9
169 
170 /*---------------------------------------------------------------------------*
171   Name:         SND_RecvCommandReply
172 
173   Description:  Receives reply (ThreadSafe).
174 
175   Arguments:    flags - BLOCK or NOBLOCK
176 
177   Returns:      Processed command list, or NULL.
178   *---------------------------------------------------------------------------*/
SND_RecvCommandReply(u32 flags)179 const SNDCommand *SND_RecvCommandReply(u32 flags)
180 {
181     OSIntrMode bak_psr = OS_DisableInterrupts();
182     SNDCommand *commandList;
183     SNDCommand *commandListEnd;
184 
185     if (flags & SND_COMMAND_BLOCK)
186     {
187         while (sFinishedTag == SNDi_GetFinishedCommandTag())
188         {
189             // Retry
190             (void)OS_RestoreInterrupts(bak_psr);
191             OS_SpinWait(100);
192             bak_psr = OS_DisableInterrupts();
193         }
194     }
195     else
196     {
197         if (sFinishedTag == SNDi_GetFinishedCommandTag())
198         {
199             (void)OS_RestoreInterrupts(bak_psr);
200             return NULL;
201         }
202     }
203 
204     /* POP from the waiting command list */
205     commandList = sWaitingCommandListQueue[sWaitingCommandListQueueRead];
206     sWaitingCommandListQueueRead++;
207     if (sWaitingCommandListQueueRead > SND_PXI_FIFO_MESSAGE_BUFSIZE)
208         sWaitingCommandListQueueRead = 0;
209 
210     /* Get the end of the command list */
211     commandListEnd = commandList;
212     while (commandListEnd->next != NULL)
213     {
214         commandListEnd = commandListEnd->next;
215     }
216 
217     /* Join to the end of the free list  */
218     if (sFreeListEnd != NULL)
219     {
220         sFreeListEnd->next = commandList;
221     }
222     else
223     {
224         sFreeList = commandList;
225     }
226     sFreeListEnd = commandListEnd;
227 
228     /* Update counter */
229     sWaitingCommandListCount--;
230     sFinishedTag++;
231 
232     (void)OS_RestoreInterrupts(bak_psr);
233     return commandList;
234 }
235 
236 /*---------------------------------------------------------------------------*
237   Name:         SND_AllocCommand
238 
239   Description:  Allocates command (ThreadSafe).
240 
241   Arguments:    flags - BLOCK or NOBLOCK
242 
243   Returns:      Commands.
244  *---------------------------------------------------------------------------*/
SND_AllocCommand(u32 flags)245 SNDCommand *SND_AllocCommand(u32 flags)
246 {
247     SNDCommand *command;
248 
249     if (!IsCommandAvailable())
250         return NULL;
251 
252     command = AllocCommand();
253     if (command != NULL)
254         return command;
255 
256     if ((flags & SND_COMMAND_BLOCK) == 0)
257         return NULL;
258 
259     if (SND_CountWaitingCommand() > 0)
260     {
261         /* There are commands waiting to be processed */
262 
263         /* Try receiving the completed command list */
264         while (SND_RecvCommandReply(SND_COMMAND_NOBLOCK) != NULL)
265         {
266         }
267 
268         /* Is there a free command? */
269         command = AllocCommand();
270         if (command != NULL)
271             return command;
272     }
273     else
274     {
275         /* There are no commands waiting to be processed */
276 
277         /* Issue the current command list */
278         (void)SND_FlushCommand(SND_COMMAND_BLOCK);
279     }
280 
281     /* Request immediate processing */
282     RequestCommandProc();
283 
284     /* Wait for command processing to complete */
285     do
286     {
287         (void)SND_RecvCommandReply(SND_COMMAND_BLOCK);
288         command = AllocCommand();
289     } while (command == NULL);
290 
291     return command;
292 }
293 
294 /*---------------------------------------------------------------------------*
295   Name:         SND_PushCommand
296 
297   Description:  Adds a command to the command list (ThreadSafe).
298 
299   Arguments:    Command to add
300 
301   Returns:      None.
302  *---------------------------------------------------------------------------*/
SND_PushCommand(struct SNDCommand * command)303 void SND_PushCommand(struct SNDCommand *command)
304 {
305     OSIntrMode bak_psr;
306 
307     SDK_NULL_ASSERT(command);
308 
309     bak_psr = OS_DisableInterrupts();
310 
311     // Add to end of sReserveList
312 
313     if (sReserveListEnd == NULL)
314     {
315         sReserveList = command;
316         sReserveListEnd = command;
317     }
318     else
319     {
320         sReserveListEnd->next = command;
321         sReserveListEnd = command;
322     }
323 
324     command->next = NULL;
325 
326     (void)OS_RestoreInterrupts(bak_psr);
327 }
328 
329 /*---------------------------------------------------------------------------*
330   Name:         SND_FlushCommand
331 
332   Description:  Sends the command list (ThreadSafe).
333 
334   Arguments:    flags - BLOCK or NOBLOCK
335 
336   Returns:      Whether it was successful.
337  *---------------------------------------------------------------------------*/
SND_FlushCommand(u32 flags)338 BOOL SND_FlushCommand(u32 flags)
339 {
340     OSIntrMode bak_psr = OS_DisableInterrupts();
341 
342     if (sReserveList == NULL)
343     {
344         /* There are no reserved commands, so do nothing */
345         (void)OS_RestoreInterrupts(bak_psr);
346         return TRUE;
347     }
348 
349     if (sWaitingCommandListCount >= SND_PXI_FIFO_MESSAGE_BUFSIZE)
350     {
351         /* A backlog of command processing on ARM7 has built up */
352         if ((flags & SND_COMMAND_BLOCK) == 0)
353         {
354             (void)OS_RestoreInterrupts(bak_psr);
355             return FALSE;
356         }
357 
358         do
359         {
360             (void)SND_RecvCommandReply(SND_COMMAND_BLOCK);
361         } while (sWaitingCommandListCount >= SND_PXI_FIFO_MESSAGE_BUFSIZE);
362 
363         /* Verified again in SND_RecvCommandReply because of the occurrence of interrupt processing */
364         if (sReserveList == NULL)
365         {
366             /* There are no reserved commands, so do nothing */
367             (void)OS_RestoreInterrupts(bak_psr);
368             return TRUE;
369         }
370     }
371 
372     /* Issue command list */
373     DC_FlushRange(sCommandArray, sizeof(sCommandArray));
374     if (PXI_SendWordByFifo(PXI_FIFO_TAG_SOUND, (u32)sReserveList, FALSE) < 0)
375     {
376         if ((flags & SND_COMMAND_BLOCK) == 0)
377         {
378             (void)OS_RestoreInterrupts(bak_psr);
379             return FALSE;
380         }
381 
382         while (sWaitingCommandListCount >= SND_PXI_FIFO_MESSAGE_BUFSIZE ||
383                PXI_SendWordByFifo(PXI_FIFO_TAG_SOUND, (u32)sReserveList, FALSE) < 0)
384         {
385             /* Wait until successful */
386             (void)OS_RestoreInterrupts(bak_psr);
387             (void)SND_RecvCommandReply(SND_COMMAND_NOBLOCK);
388             bak_psr = OS_DisableInterrupts();
389 
390             DC_FlushRange(sCommandArray, sizeof(sCommandArray));
391             /* Verified again because of the occurrence of interrupt processing */
392             if (sReserveList == NULL)
393             {
394                 /* There are no reserved commands, so do nothing */
395                 (void)OS_RestoreInterrupts(bak_psr);
396                 return TRUE;
397             }
398         }
399     }
400 
401     /* PUSH into the command wait queue */
402     sWaitingCommandListQueue[sWaitingCommandListQueueWrite] = sReserveList;
403     sWaitingCommandListQueueWrite++;
404     if (sWaitingCommandListQueueWrite > SND_PXI_FIFO_MESSAGE_BUFSIZE)
405         sWaitingCommandListQueueWrite = 0;
406 
407     /* Update variables */
408     sReserveList = NULL;
409     sReserveListEnd = NULL;
410 
411     sWaitingCommandListCount++;
412     sCurrentTag++;
413 
414     (void)OS_RestoreInterrupts(bak_psr);
415 
416     if (flags & SND_COMMAND_IMMEDIATE)
417     {
418         /* Request immediate command processing */
419         RequestCommandProc();
420     }
421 
422     return TRUE;
423 }
424 
425 /*---------------------------------------------------------------------------*
426   Name:         SND_WaitForCommandProc
427 
428   Description:  Synchronizes the completion of command processing (ThreadSafe).
429 
430   Arguments:    tag - Command tag
431 
432   Returns:      None.
433  *---------------------------------------------------------------------------*/
SND_WaitForCommandProc(u32 tag)434 void SND_WaitForCommandProc(u32 tag)
435 {
436     if (SND_IsFinishedCommandTag(tag))
437     {
438         /* Already completed */
439         return;
440     }
441 
442     /* Try receiving the completed command list */
443     while (SND_RecvCommandReply(SND_COMMAND_NOBLOCK) != NULL)
444     {
445     }
446     if (SND_IsFinishedCommandTag(tag))
447     {
448         /* It has completed */
449         return;
450     }
451 
452     /* Request immediate command processing */
453     RequestCommandProc();
454 
455     /* Wait for finish */
456     while (!SND_IsFinishedCommandTag(tag))
457     {
458         (void)SND_RecvCommandReply(SND_COMMAND_BLOCK);
459     }
460 }
461 
462 /*---------------------------------------------------------------------------*
463   Name:         SND_WaitForFreeCommand
464 
465   Description:  Waits for free commands (ThreadSafe).
466 
467   Arguments:    count - Required number of free commands
468 
469   Returns:      None.
470  *---------------------------------------------------------------------------*/
SND_WaitForFreeCommand(int count)471 void SND_WaitForFreeCommand(int count)
472 {
473     int     freeCount = SND_CountFreeCommand();
474 
475     SDK_MAX_ASSERT(count, SND_COMMAND_NUM);
476 
477     if (freeCount >= count)
478         return;
479 
480     if (freeCount + SND_CountWaitingCommand() >= count)
481     {
482         /* OK if we wait for the completion of a command waiting to be processed */
483 
484         /* Try receiving the completed command list */
485         while (SND_RecvCommandReply(SND_COMMAND_NOBLOCK) != NULL)
486         {
487         }
488 
489         /* Is there a free command? */
490         if (SND_CountFreeCommand() >= count)
491             return;
492     }
493     else
494     {
495         /* It is necessary to process reserved commands  */
496 
497         /* Issue the current command list */
498         (void)SND_FlushCommand(SND_COMMAND_BLOCK);
499     }
500 
501     /* Request immediate processing */
502     RequestCommandProc();
503 
504     /* Wait for command processing to complete */
505     do
506     {
507         (void)SND_RecvCommandReply(SND_COMMAND_BLOCK);
508     } while (SND_CountFreeCommand() < count);
509 }
510 
511 /*---------------------------------------------------------------------------*
512   Name:         SND_GetCurrentCommandTag
513 
514   Description:  Gets command tag (ThreadSafe).
515 
516   Arguments:    None.
517 
518   Returns:      Command tag.
519  *---------------------------------------------------------------------------*/
SND_GetCurrentCommandTag(void)520 u32 SND_GetCurrentCommandTag(void)
521 {
522     OSIntrMode bak_psr = OS_DisableInterrupts();
523     u32     tag;
524 
525     if (sReserveList == NULL)
526     {
527         tag = sFinishedTag;
528     }
529     else
530     {
531         tag = sCurrentTag;
532     }
533 
534     (void)OS_RestoreInterrupts(bak_psr);
535     return tag;
536 }
537 
538 /*---------------------------------------------------------------------------*
539   Name:         SND_IsFinishedCommandTag
540 
541   Description:  Checks whether or not a command tag has already been processed (ThreadSafe).
542 
543   Arguments:    tag - Command tag
544 
545   Returns:      Whether it was processed or not.
546  *---------------------------------------------------------------------------*/
SND_IsFinishedCommandTag(u32 tag)547 BOOL SND_IsFinishedCommandTag(u32 tag)
548 {
549     OSIntrMode bak_psr = OS_DisableInterrupts();
550     BOOL    result;
551 
552     if (tag > sFinishedTag)
553     {
554         if (tag - sFinishedTag < 0x80000000)
555         {
556             result = FALSE;
557         }
558         else
559         {
560             result = TRUE;
561         }
562     }
563     else
564     {
565         if (sFinishedTag - tag < 0x80000000)
566         {
567             result = TRUE;
568         }
569         else
570         {
571             result = FALSE;
572         }
573     }
574 
575     (void)OS_RestoreInterrupts(bak_psr);
576     return result;
577 }
578 
579 /*---------------------------------------------------------------------------*
580   Name:         SND_CountFreeCommand
581 
582   Description:  Gets the number of free commands (ThreadSafe).
583 
584   Arguments:    None.
585 
586   Returns:      Number of free commands.
587  *---------------------------------------------------------------------------*/
SND_CountFreeCommand(void)588 int SND_CountFreeCommand(void)
589 {
590     OSIntrMode bak_psr = OS_DisableInterrupts();
591     SNDCommand *command;
592     int     count = 0;
593 
594     command = sFreeList;
595     while (command != NULL)
596     {
597         ++count;
598         command = command->next;
599     }
600 
601     (void)OS_RestoreInterrupts(bak_psr);
602     return count;
603 }
604 
605 /*---------------------------------------------------------------------------*
606   Name:         SND_CountReservedCommand
607 
608   Description:  Gets the number of reserved commands (ThreadSafe).
609 
610   Arguments:    None.
611 
612   Returns:      Number of reserved commands.
613  *---------------------------------------------------------------------------*/
SND_CountReservedCommand(void)614 int SND_CountReservedCommand(void)
615 {
616     OSIntrMode bak_psr = OS_DisableInterrupts();
617     SNDCommand *command;
618     int     count = 0;
619 
620     command = sReserveList;
621     while (command != NULL)
622     {
623         ++count;
624         command = command->next;
625     }
626 
627     (void)OS_RestoreInterrupts(bak_psr);
628     return count;
629 }
630 
631 /*---------------------------------------------------------------------------*
632   Name:         SND_CountWaitingCommand
633 
634   Description:  Gets the number of commands waiting to be processed (ThreadSafe).
635 
636   Arguments:    None.
637 
638   Returns:      None.
639  *---------------------------------------------------------------------------*/
SND_CountWaitingCommand(void)640 int SND_CountWaitingCommand(void)
641 {
642     int     freeCount = SND_CountFreeCommand();
643     int     reservedCount = SND_CountReservedCommand();
644 
645     return SND_COMMAND_NUM - freeCount - reservedCount;
646 }
647 
648 #else  /* SDK_ARM7 */
649 
650 /*---------------------------------------------------------------------------*
651   Name:         SND_CommandProc
652 
653   Description:  Processes the command list.
654 
655   Arguments:    None.
656 
657   Returns:      None.
658  *---------------------------------------------------------------------------*/
SND_CommandProc(void)659 void SND_CommandProc(void)
660 {
661     OSMessage message;
662     const SNDCommand *command_p;
663     SNDCommand command;
664 
665     while (OS_ReceiveMessage(&sCommandMesgQueue, &message, OS_MESSAGE_NOBLOCK))
666     {
667         command_p = (const SNDCommand *)message;
668 
669         while (command_p != NULL)
670         {
671             // Note: MainMemory Access
672             command = *command_p;
673 
674             switch (command.id)
675             {
676             case SND_COMMAND_START_SEQ:
677                 SND_StartSeq((int)command.arg[0],
678                              (const void *)command.arg[1],
679                              command.arg[2], (struct SNDBankData *)command.arg[3]);
680                 break;
681 
682             case SND_COMMAND_STOP_SEQ:
683                 SND_StopSeq((int)command.arg[0]);
684                 break;
685 
686             case SND_COMMAND_PREPARE_SEQ:
687                 SND_PrepareSeq((int)command.arg[0],
688                                (const void *)command.arg[1],
689                                command.arg[2], (struct SNDBankData *)command.arg[3]);
690                 break;
691 
692             case SND_COMMAND_START_PREPARED_SEQ:
693                 SND_StartPreparedSeq((int)command.arg[0]);
694                 break;
695 
696             case SND_COMMAND_PAUSE_SEQ:
697                 SND_PauseSeq((int)command.arg[0], (BOOL)command.arg[1]);
698                 break;
699 
700             case SND_COMMAND_SKIP_SEQ:
701                 SND_SkipSeq((int)command.arg[0], (u32)command.arg[1]);
702                 break;
703 
704             case SND_COMMAND_PLAYER_PARAM:
705                 SNDi_SetPlayerParam((int)command.arg[0],
706                                     command.arg[1], command.arg[2], (int)command.arg[3]);
707                 break;
708 
709             case SND_COMMAND_TRACK_PARAM:
710                 SNDi_SetTrackParam((int)UNPACK_COMMAND(command.arg[0], 0, 24),
711                                    command.arg[1],
712                                    command.arg[2],
713                                    command.arg[3], (int)UNPACK_COMMAND(command.arg[0], 24, 8));
714                 break;
715 
716             case SND_COMMAND_MUTE_TRACK:
717                 SND_SetTrackMute((int)command.arg[0], command.arg[1], (SNDSeqMute) command.arg[2]);
718                 break;
719 
720             case SND_COMMAND_ALLOCATABLE_CHANNEL:
721                 SND_SetTrackAllocatableChannel((int)command.arg[0], command.arg[1], command.arg[2]);
722                 break;
723 
724             case SND_COMMAND_PLAYER_LOCAL_VAR:
725                 SND_SetPlayerLocalVariable((int)command.arg[0],
726                                            (int)command.arg[1], (s16)command.arg[2]);
727                 break;
728 
729             case SND_COMMAND_PLAYER_GLOBAL_VAR:
730                 SND_SetPlayerGlobalVariable((int)command.arg[0], (s16)command.arg[1]);
731                 break;
732 
733             case SND_COMMAND_START_TIMER:
734                 StartTimer(command.arg[0], command.arg[1], command.arg[2], command.arg[3]);
735                 break;
736 
737             case SND_COMMAND_STOP_TIMER:
738                 StopTimer(command.arg[0], command.arg[1], command.arg[2], command.arg[3]);
739                 break;
740 
741             case SND_COMMAND_SETUP_CAPTURE:
742                 SND_SetupCapture((SNDCapture)UNPACK_COMMAND(command.arg[2], 31, 1),
743                                  (SNDCaptureFormat)UNPACK_COMMAND(command.arg[2], 30, 1),
744                                  (void *)command.arg[0],
745                                  (int)command.arg[1],
746                                  (BOOL)UNPACK_COMMAND(command.arg[2], 29, 1),
747                                  (SNDCaptureIn)UNPACK_COMMAND(command.arg[2], 28, 1),
748                                  (SNDCaptureOut)UNPACK_COMMAND(command.arg[2], 27, 1));
749                 break;
750 
751             case SND_COMMAND_SETUP_ALARM:
752                 SND_SetupAlarm((int)command.arg[0],
753                                (OSTick)command.arg[1], (OSTick)command.arg[2], (int)command.arg[3]);
754                 break;
755 
756             case SND_COMMAND_CHANNEL_TIMER:
757                 SetChannelTimer((u32)command.arg[0], (int)command.arg[1]);
758                 break;
759 
760             case SND_COMMAND_CHANNEL_VOLUME:
761                 SetChannelVolume((u32)command.arg[0],
762                                  (int)command.arg[1], (SNDChannelDataShift)command.arg[2]);
763                 break;
764 
765             case SND_COMMAND_CHANNEL_PAN:
766                 SetChannelPan((u32)command.arg[0], (int)command.arg[1]);
767                 break;
768 
769             case SND_COMMAND_SETUP_CHANNEL_PCM:
770                 SND_SetupChannelPcm((int)UNPACK_COMMAND(command.arg[0], 0, 16), /* chNo */
771                                     (const void *)UNPACK_COMMAND(command.arg[1], 0, 27),        /* dataaddr */
772                                     (SNDWaveFormat)UNPACK_COMMAND(command.arg[3], 24, 2),       /* format */
773                                     (SNDChannelLoop)UNPACK_COMMAND(command.arg[3], 26, 2),      /* loop */
774                                     (int)UNPACK_COMMAND(command.arg[3], 0, 16), /* loopStart */
775                                     (int)UNPACK_COMMAND(command.arg[2], 0, 22), /* loopLen */
776                                     (int)UNPACK_COMMAND(command.arg[2], 24, 7), /* volume */
777                                     (SNDChannelDataShift)UNPACK_COMMAND(command.arg[2], 22, 2), /* SHIFT */
778                                     (int)UNPACK_COMMAND(command.arg[0], 16, 16),        /* timer */
779                                     (int)UNPACK_COMMAND(command.arg[3], 16, 7)  /* pan */
780                     );
781                 break;
782 
783             case SND_COMMAND_SETUP_CHANNEL_PSG:
784                 SND_SetupChannelPsg((int)command.arg[0],        /* chNo */
785                                     (SNDDuty)command.arg[3],    /* duty */
786                                     (int)UNPACK_COMMAND(command.arg[1], 0, 7),  /* volume */
787                                     (SNDChannelDataShift)UNPACK_COMMAND(command.arg[1], 8, 2),  /* SHIFT */
788                                     (int)UNPACK_COMMAND(command.arg[2], 8, 16), /* timer */
789                                     (int)UNPACK_COMMAND(command.arg[2], 0, 7)   /* pan */
790                     );
791                 break;
792 
793             case SND_COMMAND_SETUP_CHANNEL_NOISE:
794                 SND_SetupChannelNoise((int)command.arg[0],      /* chNo */
795                                       (int)UNPACK_COMMAND(command.arg[1], 0, 7),        /* volume */
796                                       (SNDChannelDataShift)UNPACK_COMMAND(command.arg[1], 8, 2),        /* SHIFT */
797                                       (int)UNPACK_COMMAND(command.arg[2], 8, 16),       /* timer */
798                                       (int)UNPACK_COMMAND(command.arg[2], 0, 7) /* pan */
799                     );
800                 break;
801 
802             case SND_COMMAND_SURROUND_DECAY:
803                 SNDi_SetSurroundDecay((int)command.arg[0]);
804                 break;
805 
806             case SND_COMMAND_MASTER_VOLUME:
807                 SND_SetMasterVolume((int)command.arg[0]);
808                 break;
809 
810             case SND_COMMAND_MASTER_PAN:
811                 SND_SetMasterPan((int)command.arg[0]);
812                 break;
813 
814             case SND_COMMAND_OUTPUT_SELECTOR:
815                 SND_SetOutputSelector((SNDOutput)command.arg[0],
816                                       (SNDOutput)command.arg[1],
817                                       (SNDChannelOut)command.arg[2], (SNDChannelOut)command.arg[3]);
818                 break;
819 
820             case SND_COMMAND_LOCK_CHANNEL:
821                 SND_LockChannel(command.arg[0], command.arg[1]);
822                 break;
823 
824             case SND_COMMAND_UNLOCK_CHANNEL:
825                 SND_UnlockChannel(command.arg[0], command.arg[1]);
826                 break;
827 
828             case SND_COMMAND_STOP_UNLOCKED_CHANNEL:
829                 SND_StopUnlockedChannel(command.arg[0], command.arg[1]);
830                 break;
831 
832             case SND_COMMAND_INVALIDATE_SEQ:
833                 SND_InvalidateSeq((const void *)command.arg[0], (const void *)command.arg[1]);
834                 break;
835 
836             case SND_COMMAND_INVALIDATE_BANK:
837                 SND_InvalidateBank((const void *)command.arg[0], (const void *)command.arg[1]);
838                 break;
839 
840             case SND_COMMAND_INVALIDATE_WAVE:
841                 SND_InvalidateWave((const void *)command.arg[0], (const void *)command.arg[1]);
842                 break;
843 
844             case SND_COMMAND_SHARED_WORK:
845                 SNDi_SharedWork = (SNDSharedWork *)command.arg[0];
846                 break;
847 
848             case SND_COMMAND_READ_DRIVER_INFO:
849                 ReadDriverInfo((SNDDriverInfo *) command.arg[0]);
850                 break;
851             }
852 
853             command_p = command.next;
854 
855         }                              // end of while ( command_p != NULL )
856 
857         /* Command list processing complete */
858         SDK_NULL_ASSERT(SNDi_SharedWork);
859         SNDi_SharedWork->finishCommandTag++;
860     }
861 }
862 
863 #endif /* SDK_ARM9 */
864 
865 /******************************************************************************
866     Static function
867  ******************************************************************************/
868 
869 /*---------------------------------------------------------------------------*
870   Name:         PxiFifoCallback
871 
872   Description:  PXI callback.
873 
874   Arguments:    tag  - PXI tag
875                 data - User data (address or message number)
876                 err  - Error flag
877 
878   Returns:      None.
879  *---------------------------------------------------------------------------*/
PxiFifoCallback(PXIFifoTag tag,u32 data,BOOL)880 static void PxiFifoCallback(PXIFifoTag tag, u32 data, BOOL /*err */ )
881 {
882     OSIntrMode enabled;
883     BOOL    result;
884 
885 #ifdef SDK_DEBUG
886     SDK_ASSERT(tag == PXI_FIFO_TAG_SOUND);
887 #else
888 #pragma unused( tag )
889 #endif
890 
891     enabled = OS_DisableInterrupts();
892 
893 #ifdef SDK_ARM9
894 
895 #pragma unused( result )
896     SNDi_CallAlarmHandler((int)data);
897 
898 #else  /* SDK_ARM7 */
899 
900     if (data >= HW_MAIN_MEM)
901     {
902         /* This is controlled by the sender, so it should not fail */
903         result = OS_SendMessage(&sCommandMesgQueue, (OSMessage)data, OS_MESSAGE_NOBLOCK);
904         SDK_ASSERTMSG(result, "Failed OS_SendMessage");
905     }
906     else
907     {
908         switch (data)
909         {
910         case SND_MSG_REQUEST_COMMAND_PROC:
911             {
912                 (void)SND_SendWakeupMessage();
913                 break;
914             }
915         }
916     }
917 
918 #endif /* SDK_ARM9 */
919 
920     (void)OS_RestoreInterrupts(enabled);
921 }
922 
923 /*---------------------------------------------------------------------------*
924   Name:         InitPXI
925 
926   Description:  Initializes PXI.
927 
928   Arguments:    None.
929 
930   Returns:      None.
931  *---------------------------------------------------------------------------*/
InitPXI(void)932 static void InitPXI(void)
933 {
934     // Register the callback and attempt initial synchronization with the other party
935     PXI_SetFifoRecvCallback(PXI_FIFO_TAG_SOUND, PxiFifoCallback);
936 
937 #ifdef SDK_ARM9
938     if (IsCommandAvailable())
939     {
940         while (!PXI_IsCallbackReady(PXI_FIFO_TAG_SOUND, PXI_PROC_ARM7))
941         {
942             OS_SpinWait(100);
943         }
944     }
945 #endif
946 }
947 
948 #ifdef SDK_ARM9
949 
950 /*---------------------------------------------------------------------------*
951   Name:         RequestCommandProc
952 
953   Description:  Request command processing (ThreadSafe).
954 
955   Arguments:    None.
956 
957   Returns:      None.
958  *---------------------------------------------------------------------------*/
RequestCommandProc(void)959 static void RequestCommandProc(void)
960 {
961     while (PXI_SendWordByFifo(PXI_FIFO_TAG_SOUND, SND_MSG_REQUEST_COMMAND_PROC, FALSE) < 0)
962     {
963         // retry
964     }
965 }
966 
967 /*---------------------------------------------------------------------------*
968   Name:         AllocCommand
969 
970   Description:  Allocates command (ThreadSafe).
971 
972   Arguments:    None.
973 
974   Returns:      Command or NULL.
975  *---------------------------------------------------------------------------*/
AllocCommand(void)976 static SNDCommand *AllocCommand(void)
977 {
978     OSIntrMode bak_psr = OS_DisableInterrupts();
979     SNDCommand *command;
980 
981     if (sFreeList == NULL)
982     {
983         (void)OS_RestoreInterrupts(bak_psr);
984         return NULL;
985     }
986 
987     command = sFreeList;
988     sFreeList = sFreeList->next;
989 
990     if (sFreeList == NULL)
991         sFreeListEnd = NULL;
992 
993     (void)OS_RestoreInterrupts(bak_psr);
994     return command;
995 }
996 
997 /*---------------------------------------------------------------------------*
998   Name:         IsCommandAvailable
999 
1000   Description:  Checks the validity of a command routine.
1001 
1002   Arguments:    None.
1003 
1004   Returns:      Whether or not the command routine is valid.
1005  *---------------------------------------------------------------------------*/
IsCommandAvailable(void)1006 static BOOL IsCommandAvailable(void)
1007 {
1008     OSIntrMode prev_mode;
1009     u32     res;
1010 
1011     if (!OS_IsRunOnEmulator())
1012         return TRUE;
1013 
1014     prev_mode = OS_DisableInterrupts();
1015 
1016     /* Confirm sound validity */
1017     *(vu32 *)0x4fff200 = 0x10;
1018     res = *(vu32 *)0x4fff200;
1019 
1020     (void)OS_RestoreInterrupts(prev_mode);
1021 
1022     return res ? TRUE : FALSE;
1023 }
1024 
1025 
1026 #else  /* SDK_ARM7 */
1027 
1028 
SetChannelTimer(u32 chBitMask,int timer)1029 static void SetChannelTimer(u32 chBitMask, int timer)
1030 {
1031     int     ch;
1032 
1033     for (ch = 0; ch < SND_CHANNEL_NUM && chBitMask != 0; ch++, chBitMask >>= 1)
1034     {
1035         if ((chBitMask & 0x01) == 0)
1036             continue;
1037         SND_SetChannelTimer(ch, timer);
1038     }
1039 }
1040 
SetChannelVolume(u32 chBitMask,int volume,SNDChannelDataShift shift)1041 static void SetChannelVolume(u32 chBitMask, int volume, SNDChannelDataShift shift)
1042 {
1043     int     ch;
1044 
1045     for (ch = 0; ch < SND_CHANNEL_NUM && chBitMask != 0; ch++, chBitMask >>= 1)
1046     {
1047         if ((chBitMask & 0x01) == 0)
1048             continue;
1049         SND_SetChannelVolume(ch, volume, shift);
1050     }
1051 }
1052 
SetChannelPan(u32 chBitMask,int pan)1053 static void SetChannelPan(u32 chBitMask, int pan)
1054 {
1055     int     ch;
1056 
1057     for (ch = 0; ch < SND_CHANNEL_NUM && chBitMask != 0; ch++, chBitMask >>= 1)
1058     {
1059         if ((chBitMask & 0x01) == 0)
1060             continue;
1061         SND_SetChannelPan(ch, pan);
1062     }
1063 }
1064 
1065 
StartTimer(u32 chBitMask,u32 capBitMask,u32 alarmBitMask,u32)1066 static void StartTimer(u32 chBitMask, u32 capBitMask, u32 alarmBitMask, u32 /*flags */ )
1067 {
1068     OSIntrMode enabled;
1069     int     i;
1070 
1071     enabled = OS_DisableInterrupts();
1072 
1073     for (i = 0; i < SND_CHANNEL_NUM && chBitMask != 0; i++, chBitMask >>= 1)
1074     {
1075         if ((chBitMask & 0x01) == 0)
1076             continue;
1077         SND_StartChannel(i);
1078     }
1079 
1080     if (capBitMask & (1 << SND_CAPTURE_0))
1081     {
1082         if (capBitMask & (1 << SND_CAPTURE_1))
1083         {
1084             SND_StartCaptureBoth();
1085         }
1086         else
1087         {
1088             SND_StartCapture(SND_CAPTURE_0);
1089         }
1090     }
1091     else if (capBitMask & (1 << SND_CAPTURE_1))
1092     {
1093         SND_StartCapture(SND_CAPTURE_1);
1094     }
1095 
1096     for (i = 0; i < SND_ALARM_NUM && alarmBitMask != 0; i++, alarmBitMask >>= 1)
1097     {
1098         if ((alarmBitMask & 0x01) == 0)
1099             continue;
1100         SND_StartAlarm(i);
1101     }
1102 
1103     (void)OS_RestoreInterrupts(enabled);
1104 
1105     SND_UpdateSharedWork();
1106 }
1107 
StopTimer(u32 chBitMask,u32 capBitMask,u32 alarmBitMask,u32 flags)1108 static void StopTimer(u32 chBitMask, u32 capBitMask, u32 alarmBitMask, u32 flags)
1109 {
1110     OSIntrMode enabled;
1111     int     i;
1112 
1113     enabled = OS_DisableInterrupts();
1114 
1115     for (i = 0; i < SND_ALARM_NUM && alarmBitMask != 0; i++, alarmBitMask >>= 1)
1116     {
1117         if ((alarmBitMask & 0x01) == 0)
1118             continue;
1119         SND_StopAlarm(i);
1120     }
1121 
1122     for (i = 0; i < SND_CHANNEL_NUM && chBitMask != 0; i++, chBitMask >>= 1)
1123     {
1124         if ((chBitMask & 0x01) == 0)
1125             continue;
1126         SND_StopChannel(i, (s32)flags);
1127     }
1128 
1129     if (capBitMask & (1 << SND_CAPTURE_0))
1130     {
1131         SND_StopCapture(SND_CAPTURE_0);
1132     }
1133     if (capBitMask & (1 << SND_CAPTURE_1))
1134     {
1135         SND_StopCapture(SND_CAPTURE_1);
1136     }
1137 
1138     (void)OS_RestoreInterrupts(enabled);
1139 
1140     SND_UpdateSharedWork();
1141 }
1142 
ReadDriverInfo(SNDDriverInfo * info)1143 static void ReadDriverInfo(SNDDriverInfo * info)
1144 {
1145     int     ch;
1146 
1147     MI_CpuCopy32(&SNDi_Work, &info->work, sizeof(SNDi_Work));
1148 
1149     info->workAddress = &SNDi_Work;
1150 
1151     for (ch = 0; ch < SND_CHANNEL_NUM; ch++)
1152     {
1153         info->chCtrl[ch] = SND_GetChannelControl(ch);
1154     }
1155 
1156     info->lockedChannels = SND_GetLockedChannel(0);
1157 }
1158 
1159 #endif /* SDK_ARM9 */
1160 
1161 /*====== End of snd_command.c ======*/
1162