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