1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - library - dsp
3   File:     dsp_pipe.c
4 
5   Copyright 2007-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:: 2009-06-11#$
14   $Rev: 10742 $
15   $Author: yosizaki $
16  *---------------------------------------------------------------------------*/
17 
18 #include <twl.h>
19 #include <twl/dsp.h>
20 #include <twl/dsp/common/pipe.h>
21 
22 
23 /*---------------------------------------------------------------------------*/
24 /* Variables */
25 
26 // Base address in DSP for pipe information
27 static DSPAddrInARM     DSPiPipeMonitorAddress = 0;
28 static OSThreadQueue    DSPiBlockingQueue[1];
29 static DSPPipe          DSPiDefaultPipe[DSP_PIPE_PORT_MAX][DSP_PIPE_PEER_MAX];
30 static DSPPipeCallback  DSPiCallback[DSP_PIPE_PORT_MAX];
31 static void*           (DSPiCallbackArgument[DSP_PIPE_PORT_MAX]);
32 
33 // File I/O processing thread structure
34 typedef struct DSPFileIOContext
35 {
36     BOOL            initialized;
37     OSThread        th[1];
38     OSMessage       msga[1];
39     OSMessageQueue  msgq[1];
40     volatile int    pollbits;
41     FSFile          file[DSP_PIPE_PORT_MAX][1];
42     u8              stack[4096];
43 }
44 DSPFileIOContext;
45 
46 static DSPFileIOContext DSPiThread[1];
47 
48 
49 /*---------------------------------------------------------------------------*/
50 /* functions */
51 
52 /*---------------------------------------------------------------------------*
53   Name:         DSPi_FileIOProc
54 
55   Description:  File I/O processing procedure
56 
57   Arguments:    arg: DSPFileIOThread structure
58 
59   Returns:      None.
60  *---------------------------------------------------------------------------*/
DSPi_FileIOProc(void * arg)61 static void DSPi_FileIOProc(void *arg)
62 {
63     DSPFileIOContext   *ctx = (DSPFileIOContext *)arg;
64     for (;;)
65     {
66         // If necessary, wait for notice and get one port that is requested.
67         OSIntrMode  bak = OS_DisableInterrupts();
68         int         port;
69         for (;;)
70         {
71             port = (int)MATH_CTZ((u32)ctx->pollbits);
72             if (port < DSP_PIPE_PORT_MAX)
73             {
74                 break;
75             }
76             else
77             {
78                 OSMessage   msg[1];
79                 (void)OS_ReceiveMessage(ctx->msgq, msg, OS_MESSAGE_BLOCK);
80             }
81         }
82         ctx->pollbits &= ~(1 << port);
83         (void)OS_RestoreInterrupts(bak);
84         // Read command from corresponding pipe
85         {
86             FSFile     *file = ctx->file[port];
87             DSPPipe     in[1], out[1];
88             u16         command;
89             (void)DSP_LoadPipe(in, port, DSP_PIPE_INPUT);
90             (void)DSP_LoadPipe(out, port, DSP_PIPE_OUTPUT);
91             while (DSP_GetPipeReadableSize(in) >= sizeof(command))
92             {
93                 DSP_ReadPipe(in, &command, sizeof(command));
94                 switch (command)
95                 {
96                 case DSP_PIPE_IO_COMMAND_OPEN:
97                     // fopen command
98                     {
99                         u16     mode;
100                         u16     len;
101                         char    path[FS_ENTRY_LONGNAME_MAX + 1];
102                         u16     result;
103                         DSP_ReadPipe(in, &mode, sizeof(mode));
104                         DSP_ReadPipe(in, &len, sizeof(len));
105                         len = DSP_WORD_TO_ARM(len);
106                         DSP_ReadPipe(in, path, len);
107                         path[len] = '\0';
108                         (void)FS_OpenFileEx(file, path, mode);
109                         result = (u16)(FS_IsFile(file) ? 1 : 0);
110                         DSP_WritePipe(out, &result, sizeof(result));
111                     }
112                     break;
113                 case DSP_PIPE_IO_COMMAND_MEMMAP:
114                     // memmap command
115                     {
116                         DSPAddrInARM    addr;
117                         DSPAddrInARM    length;
118                         u16     result;
119                         DSP_ReadPipe(in, &addr, sizeof(addr));
120                         DSP_ReadPipe(in, &length, sizeof(length));
121                         addr = DSP_32BIT_TO_ARM(addr);
122                         length = DSP_32BIT_TO_ARM(length);
123                         length = DSP_ADDR_TO_ARM(length);
124                         (void)FS_CreateFileFromMemory(file, (void*)addr, length);
125                         result = (u16)(FS_IsFile(file) ? 1 : 0);
126                         DSP_WritePipe(out, &result, sizeof(result));
127                     }
128                     break;
129                 case DSP_PIPE_IO_COMMAND_CLOSE:
130                     // fclose command
131                     {
132                         u16     result;
133                         (void)FS_CloseFile(file);
134                         result = 1;
135                         DSP_WritePipe(out, &result, sizeof(result));
136                     }
137                     break;
138                 case DSP_PIPE_IO_COMMAND_SEEK:
139                     // fseek command
140                     {
141                         s32     position;
142                         u16     whence;
143                         s32     result;
144                         DSP_ReadPipe(in, &position, sizeof(position));
145                         DSP_ReadPipe(in, &whence, sizeof(whence));
146                         position = (s32)DSP_32BIT_TO_ARM(position);
147                         (void)FS_SeekFile(file, position, (FSSeekFileMode)whence);
148                         result = (s32)FS_GetFilePosition(file);
149                         result = (s32)DSP_32BIT_TO_DSP(result);
150                         DSP_WritePipe(out, &result, sizeof(result));
151                     }
152                     break;
153                 case DSP_PIPE_IO_COMMAND_READ:
154                     // fread command
155                     {
156                         DSPWord length;
157                         u32     rest;
158                         u16     result;
159                         DSP_ReadPipe(in, &length, sizeof(length));
160                         length = DSP_WORD_TO_ARM(length);
161                         // Get actual size and restrict in advance
162                         rest = FS_GetFileLength(file) - FS_GetFilePosition(file);
163                         length = (DSPWord)MATH_MIN(length, rest);
164                         result = DSP_WORD_TO_DSP(length);
165                         DSP_WritePipe(out, &result, sizeof(result));
166                         while (length > 0)
167                         {
168                             u8      tmp[256];
169                             u16     n = (u16)MATH_MIN(length, 256);
170                             (void)FS_ReadFile(file, tmp, (s32)n);
171                             DSP_WritePipe(out, tmp, n);
172                             length -= n;
173                         }
174                     }
175                     break;
176                 case DSP_PIPE_IO_COMMAND_WRITE:
177                     // fwrite command
178                     {
179                         DSPWord length;
180                         DSP_ReadPipe(in, &length, sizeof(length));
181                         length = DSP_WORD_TO_ARM(length);
182                         while (length > 0)
183                         {
184                             u8      tmp[256];
185                             u16     n = (u16)MATH_MIN(length, 256);
186                             DSP_ReadPipe(in, tmp, (u16)n);
187                             (void)FS_WriteFile(file, tmp, (s32)n);
188                             length -= n;
189                         }
190                     }
191                     break;
192                 }
193             }
194         }
195     }
196 }
197 
198 /*---------------------------------------------------------------------------*
199   Name:         DSPi_NotifyFileIOUpdation
200 
201   Description:  Notifies update of file I/O
202 
203   Arguments:    port: Updated port number
204 
205   Returns:      None.
206  *---------------------------------------------------------------------------*/
DSPi_NotifyFileIOUpdation(int port)207 static void DSPi_NotifyFileIOUpdation(int port)
208 {
209     DSPFileIOContext   *ctx = DSPiThread;
210     OSIntrMode          bak = OS_DisableInterrupts();
211     // Generate thread if necessary
212     if (!ctx->initialized)
213     {
214         int                 i;
215         for (i = 0; i < DSP_PIPE_PORT_MAX; ++i)
216         {
217             FS_InitFile(ctx->file[i]);
218         }
219         OS_InitMessageQueue(ctx->msgq, ctx->msga, 1);
220         ctx->pollbits = 0;
221         ctx->initialized = TRUE;
222         OS_CreateThread(ctx->th, DSPi_FileIOProc, ctx,
223                         &ctx->stack[sizeof(ctx->stack)], sizeof(ctx->stack), 13);
224         OS_WakeupThreadDirect(ctx->th);
225     }
226     // Throw message for notification
227     // NOBLOCK because it is acceptable for notifications not to line up in the queue if the same ones have accumulated
228     ctx->pollbits |= (1 << port);
229     (void)OS_SendMessage(ctx->msgq, (OSMessage)port, OS_MESSAGE_NOBLOCK);
230     (void)OS_RestoreInterrupts(bak);
231 }
232 
233 /*---------------------------------------------------------------------------*
234   Name:         DSPi_PipeCallbackToConsole
235 
236   Description:  DSP_PIPE_CONSOLE transmission handler
237 
238   Arguments:    userdata : Optional user-defined argument
239                 port: Port number
240                 peer: Transmission direction
241 
242   Returns:      None.
243  *---------------------------------------------------------------------------*/
DSPi_PipeCallbackToConsole(void * userdata,int port,int peer)244 static void DSPi_PipeCallbackToConsole(void *userdata, int port, int peer)
245 {
246     (void)userdata;
247     if (peer == DSP_PIPE_INPUT)
248     {
249         DSPPipe pipe[1];
250         (void)DSP_LoadPipe(pipe, port, peer);
251         {
252             u16     max = DSP_GetPipeReadableSize(pipe);
253             u16     pos = 0;
254             while (pos < max)
255             {
256                 enum { tmplen = 128 };
257                 char    buffer[tmplen + 2];
258                 u16     length = (u16)((max - pos < tmplen) ? (max - pos) : tmplen);
259                 DSP_ReadPipe(pipe, buffer, length);
260                 pos += length;
261                 // Debug output of the console output from DSP
262                 // Each printf output is delivered padded in u16 units, be careful that '\0' is inserted at irregular intervals.
263                 //
264                 {
265                     const char *str = (const char *)buffer;
266                     int     current = 0;
267                     int     pos;
268                     for (pos = 0; pos < length; ++pos)
269                     {
270                         if (str[pos] == '\0')
271                         {
272                             OS_TPrintf("%s", &str[current]);
273                             current = pos + 1;
274                         }
275                     }
276                     if (current < length)
277                     {
278                         OS_TPrintf("%.*s", (length - current), &str[current]);
279                     }
280                 }
281             }
282         }
283     }
284 }
285 
286 /*---------------------------------------------------------------------------*
287   Name:         DSPi_PipeCallbackForDMA
288 
289   Description:  DSP_PIPE_DMA transmission handler
290 
291   Arguments:    userdata : Optional user-defined argument
292                 port: Port number
293                 peer: Transmission direction
294 
295   Returns:      None.
296  *---------------------------------------------------------------------------*/
DSPi_PipeCallbackForDMA(void * userdata,int port,int peer)297 static void DSPi_PipeCallbackForDMA(void *userdata, int port, int peer)
298 {
299     (void)userdata;
300     if (peer == DSP_PIPE_INPUT)
301     {
302         DSPPipe pipe[1];
303         (void)DSP_LoadPipe(pipe, port, peer);
304         {
305             u16     max = DSP_GetPipeReadableSize(pipe);
306             u16     pos = 0;
307             while (pos < max)
308             {
309                 enum { tmplen = 128 };
310                 char    buffer[tmplen + 2];
311                 u16     length = (u16)((max - pos < tmplen) ? (max - pos) : tmplen);
312                 DSP_ReadPipe(pipe, buffer, length);
313                 pos += length;
314                 // Debug output of the console output from DSP
315                 // Each printf output is delivered padded in u16 units, be careful that '\0' is inserted at irregular intervals.
316                 //
317                 {
318                     const char *str = (const char *)buffer;
319                     int     current = 0;
320                     int     pos;
321                     for (pos = 0; pos < length; ++pos)
322                     {
323                         if (str[pos] == '\0')
324                         {
325                             OS_TPrintf("%s", &str[current]);
326                             current = pos + 1;
327                         }
328                     }
329                     if (current < length)
330                     {
331                         OS_TPrintf("%.*s", (length - current), &str[current]);
332                     }
333                 }
334             }
335         }
336     }
337 }
338 
339 /*---------------------------------------------------------------------------*
340   Name:         DSPi_WaitForPipe
341 
342   Description:  Idling update specified DSP pipe information
343 
344   Arguments:    pipe: Pipe information
345 
346   Returns:      None.
347  *---------------------------------------------------------------------------*/
DSPi_WaitForPipe(DSPPipe * pipe)348 static void DSPi_WaitForPipe(DSPPipe *pipe)
349 {
350     OS_SleepThread(DSPiBlockingQueue);
351     (void)DSP_SyncPipe(pipe);
352 }
353 
354 /*---------------------------------------------------------------------------*
355   Name:         DSP_InitPipe
356 
357   Description:  Initializes DSP pipe communication.
358                 Occupy DSP command replay register 2
359 
360   Arguments:    None.
361 
362   Returns:      None.
363  *---------------------------------------------------------------------------*/
DSP_InitPipe(void)364 void DSP_InitPipe(void)
365 {
366     int     i;
367     DSPiPipeMonitorAddress = 0;
368     OS_InitThreadQueue(DSPiBlockingQueue);
369     for (i = 0; i < DSP_PIPE_PORT_MAX; ++i)
370     {
371         DSPiCallback[i] = NULL;
372         DSPiCallbackArgument[i] = NULL;
373     }
374     // DSP_PIPE_CONSOLE is the debug console for DSP
375     DSPiCallback[DSP_PIPE_CONSOLE] = DSPi_PipeCallbackToConsole;
376 }
377 
378 /*---------------------------------------------------------------------------*
379   Name:         DSP_SetPipeCallback
380 
381   Description:  Sets the DSP pipe communcation callback
382 
383   Arguments:    port: Pipe port number
384                 callback: Callback for readable/writable events
385                 userdata : Optional user-defined argument
386 
387   Returns:      None.
388  *---------------------------------------------------------------------------*/
DSP_SetPipeCallback(int port,void (* callback)(void *,int,int),void * userdata)389 void DSP_SetPipeCallback(int port, void (*callback)(void *, int, int), void *userdata)
390 {
391     DSPiCallback[port] = callback;
392     DSPiCallbackArgument[port] = userdata;
393 }
394 
395 /*---------------------------------------------------------------------------*
396   Name:         DSP_LoadPipe
397 
398   Description:  Loads DSP pipe information
399 
400   Arguments:    pipe: Storage destination of pipe information (Not NULL on the DSP side)
401                 port: Pipe port number
402                 peer: DSP_PIPE_INPUT or DSP_PIPE_OUTPUT
403 
404   Returns:      Pointer of the loaded pipe information
405  *---------------------------------------------------------------------------*/
DSP_LoadPipe(DSPPipe * pipe,int port,int peer)406 DSPPipe* DSP_LoadPipe(DSPPipe *pipe, int port, int peer)
407 {
408     // Idle until notified of the monitor address
409     OSIntrMode  bak = OS_DisableInterrupts();
410     while (!DSPiPipeMonitorAddress)
411     {
412         OS_SleepThread(DSPiBlockingQueue);
413     }
414     (void)OS_RestoreInterrupts(bak);
415     if (((port >= 0) && (port < DSP_PIPE_PORT_MAX)) &&
416         ((peer >= 0) && (peer < DSP_PIPE_PEER_MAX)))
417     {
418         DSPPipeMonitor *monitor = (DSPPipeMonitor *)DSPiPipeMonitorAddress;
419         DSPPipe        *target = &monitor->pipe[port][peer];
420         if (!pipe)
421         {
422             pipe = &DSPiDefaultPipe[port][peer];
423         }
424         DSP_LoadData((DSPAddrInARM)target, pipe, sizeof(*pipe));
425     }
426     return pipe;
427 }
428 
429 /*---------------------------------------------------------------------------*
430   Name:         DSP_SyncPipe
431 
432   Description:  Update DSP pipe information to the latest content.
433 
434   Arguments:    pipe: Pipe information
435 
436   Returns:      None.
437  *---------------------------------------------------------------------------*/
DSP_SyncPipe(DSPPipe * pipe)438 void DSP_SyncPipe(DSPPipe *pipe)
439 {
440     (void)DSP_LoadPipe(pipe,
441                  ((pipe->flags & DSP_PIPE_FLAG_PORTMASK) >> 1),
442                  (pipe->flags & 1));
443 }
444 
445 /*---------------------------------------------------------------------------*
446   Name:         DSP_FlushPipe
447 
448   Description:  Flushes the DSP pipe stream
449 
450   Arguments:    pipe: Pipe information
451                 port: Pipe port number
452                 peer: DSP_PIPE_INPUT or DSP_PIPE_OUTPUT
453 
454   Returns:      None.
455  *---------------------------------------------------------------------------*/
DSP_FlushPipe(DSPPipe * pipe)456 void DSP_FlushPipe(DSPPipe *pipe)
457 {
458     // Write back to the DSP only the pointer updated from the ARM side
459     int     port = ((pipe->flags & DSP_PIPE_FLAG_PORTMASK) >> 1);
460     int     peer = (pipe->flags & 1);
461     DSPPipeMonitor *monitor = (DSPPipeMonitor *)DSPiPipeMonitorAddress;
462     DSPPipe        *target = &monitor->pipe[port][peer];
463     if (peer == DSP_PIPE_INPUT)
464     {
465         DSP_StoreData((DSPAddrInARM)&target->rpos, &pipe->rpos, sizeof(target->rpos));
466     }
467     else
468     {
469         DSP_StoreData((DSPAddrInARM)&target->wpos, &pipe->wpos, sizeof(target->wpos));
470     }
471     // Update notification to DSP side
472     DSP_SendData(DSP_PIPE_COMMAND_REGISTER, (u16)(pipe->flags & DSP_PIPE_FLAG_PORTMASK));
473 }
474 
475 /*---------------------------------------------------------------------------*
476   Name:         DSP_GetPipeReadableSize
477 
478   Description:  Get maximum size that currently can be read from the specified DSP pipe
479 
480   Arguments:    pipe: Pipe information
481 
482   Returns:      Maximum size that currently can be read
483  *---------------------------------------------------------------------------*/
DSP_GetPipeReadableSize(const DSPPipe * pipe)484 u16 DSP_GetPipeReadableSize(const DSPPipe *pipe)
485 {
486     return DSP_BYTE_TO_UNIT(((pipe->wpos - pipe->rpos) +
487            (((pipe->rpos ^ pipe->wpos) < 0x8000) ? 0 : pipe->length)) & ~0x8000);
488 }
489 
490 /*---------------------------------------------------------------------------*
491   Name:         DSP_GetPipeWritableSize
492 
493   Description:  Get maximum size that currently can be written to the specified DSP pipe
494 
495   Arguments:    pipe: Pipe information
496 
497   Returns:      Maximum size that currently can be written
498  *---------------------------------------------------------------------------*/
DSP_GetPipeWritableSize(const DSPPipe * pipe)499 u16 DSP_GetPipeWritableSize(const DSPPipe *pipe)
500 {
501     return DSP_BYTE_TO_UNIT(((pipe->rpos - pipe->wpos) +
502            (((pipe->wpos ^ pipe->rpos) < 0x8000) ? 0 : pipe->length)) & ~0x8000);
503 }
504 
505 /*---------------------------------------------------------------------------*
506   Name:         DSP_ReadPipe
507 
508   Description:  Read data from the DSP pipe communication port
509 
510   Arguments:    pipe: Pipe information
511                 buffer: Transfer destination buffer
512                 length: Transfer size (However, the units are the word size of that environment)
513                          Be careful that the ARM side is 1-byte units, and the DSP side is 2-byte units.
514 
515   Returns:      None.
516  *---------------------------------------------------------------------------*/
DSP_ReadPipe(DSPPipe * pipe,void * buffer,u16 length)517 void DSP_ReadPipe(DSPPipe *pipe, void *buffer, u16 length)
518 {
519     OSIntrMode  bak = OS_DisableInterrupts();
520     u8         *dst = (u8 *)buffer;
521     BOOL        modified = FALSE;
522     length = DSP_UNIT_TO_BYTE(length);
523     DSP_SyncPipe(pipe);
524     while (length > 0)
525     {
526         u16     rpos = pipe->rpos;
527         u16     wpos = pipe->wpos;
528         u16     phase = (u16)(rpos ^ wpos);
529         // Wait for completion if read-empty
530         if (phase == 0x0000)
531         {
532             if (modified)
533             {
534                 DSP_FlushPipe(pipe);
535                 modified = FALSE;
536             }
537             DSPi_WaitForPipe(pipe);
538         }
539         else
540         {
541             // If not, read from a safe range
542             u16     pos = (u16)(rpos & ~0x8000);
543             u16     end = (u16)((phase < 0x8000) ? (wpos & ~0x8000) : pipe->length);
544             u16     len = (u16)((length < end - pos) ? length : (end - pos));
545             len = (u16)(len & ~(DSP_WORD_UNIT - 1));
546             DSP_LoadData(DSP_ADDR_TO_ARM(pipe->address) + pos, dst, len);
547             length -= len;
548             dst += DSP_BYTE_TO_UNIT(len);
549             pipe->rpos = (u16)((pos + len < pipe->length) ? (rpos + len) : (~rpos & 0x8000));
550             modified = TRUE;
551         }
552     }
553     // If there is an addition, notify here
554     if (modified)
555     {
556         DSP_FlushPipe(pipe);
557         modified = FALSE;
558     }
559     (void)OS_RestoreInterrupts(bak);
560 }
561 
562 /*---------------------------------------------------------------------------*
563   Name:         DSP_WritePipe
564 
565   Description:  Writes data to the DSP pipe communication port
566 
567   Arguments:    pipe: Pipe information
568                 buffer: Transfer source buffer
569                 length: Transfer size (However, the units are the word size of that environment)
570                          Note that the ARM side is 1-byte units, and the DSP side is 2-byte units.
571 
572   Returns:      None.
573  *---------------------------------------------------------------------------*/
DSP_WritePipe(DSPPipe * pipe,const void * buffer,u16 length)574 void DSP_WritePipe(DSPPipe *pipe, const void *buffer, u16 length)
575 {
576     OSIntrMode  bak = OS_DisableInterrupts();
577     const u8   *src = (const u8 *)buffer;
578     BOOL        modified = FALSE;
579     length = DSP_UNIT_TO_BYTE(length);
580     DSP_SyncPipe(pipe);
581     while (length > 0)
582     {
583         u16     rpos = pipe->rpos;
584         u16     wpos = pipe->wpos;
585         u16     phase = (u16)(rpos ^ wpos);
586         // If write-full, wait for completion
587         if (phase == 0x8000)
588         {
589             if (modified)
590             {
591                 DSP_FlushPipe(pipe);
592                 modified = FALSE;
593             }
594             DSPi_WaitForPipe(pipe);
595         }
596         else
597         {
598             // If not, write to a safe range
599             u16     pos = (u16)(wpos & ~0x8000);
600             u16     end = (u16)((phase < 0x8000) ? pipe->length : (rpos & ~0x8000));
601             u16     len = (u16)((length < end - pos) ? length : (end - pos));
602             len = (u16)(len & ~(DSP_WORD_UNIT - 1));
603             DSP_StoreData(DSP_ADDR_TO_ARM(pipe->address) + pos, src, len);
604             length -= len;
605             src += DSP_BYTE_TO_UNIT(len);
606             pipe->wpos = (u16)((pos + len < pipe->length) ? (wpos + len) : (~wpos & 0x8000));
607             modified = TRUE;
608         }
609     }
610     // If there is an addition, notify here
611     if (modified)
612     {
613         DSP_FlushPipe(pipe);
614         modified = FALSE;
615     }
616     (void)OS_RestoreInterrupts(bak);
617 }
618 
619 /*---------------------------------------------------------------------------*
620   Name:         DSP_HookPipeNotification
621 
622   Description:  Pipe notification hook that should be called in a DSP interrupt
623 
624   Arguments:    None.
625 
626   Returns:      None.
627  *---------------------------------------------------------------------------*/
DSP_HookPipeNotification(void)628 void DSP_HookPipeNotification(void)
629 {
630     // CR2 dedicated for pipe communication
631     // However, for some reason a CR interrupt was not generated, so currently, substitute semaphore with only one bit
632     //
633     while (((DSP_GetSemaphore() & 0x8000) != 0) || DSP_RecvDataIsReady(DSP_PIPE_COMMAND_REGISTER))
634     {
635         DSP_ClearSemaphore(0x8000);
636         while (DSP_RecvDataIsReady(DSP_PIPE_COMMAND_REGISTER))
637         {
638             // Initially, the shared structure address is notified from the DSP side
639             if (DSPiPipeMonitorAddress == 0)
640             {
641                 DSPiPipeMonitorAddress = DSP_ADDR_TO_ARM(DSP_RecvData(DSP_PIPE_COMMAND_REGISTER));
642             }
643             // Thereafter, only updated pipes are notified
644             else
645             {
646                 u16     recvdata = DSP_RecvData(DSP_PIPE_COMMAND_REGISTER);
647                 int     port = (recvdata >> 1);
648                 int     peer = (recvdata & 1);
649                 if ((port >= 0) && (port < DSP_PIPE_PORT_MAX))
650                 {
651                     // If a monitoring source exists on the ARM side, verify the pipe information
652                     if (DSPiCallback[port])
653                     {
654                         (*DSPiCallback[port])(DSPiCallbackArgument[port], port, peer);
655                     }
656                     else
657                     {
658                         DSPPipe pipe[1];
659                         (void)DSP_LoadPipe(pipe, port, peer);
660                         // If updating the file opened on the DSP side, notify the thread
661                         if ((peer == DSP_PIPE_INPUT) && ((pipe->flags & DSP_PIPE_FLAG_BOUND) != 0))
662                         {
663                             DSPi_NotifyFileIOUpdation(port);
664                         }
665                     }
666                 }
667             }
668             // Notify update to thread during blocking
669             OS_WakeupThread(DSPiBlockingQueue);
670         }
671     }
672 }
673