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:: 2008-11-21#$
14   $Rev: 9387 $
15   $Author: kitase_hirotake $
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     {
416         DSPPipeMonitor *monitor = (DSPPipeMonitor *)DSPiPipeMonitorAddress;
417         DSPPipe        *target = &monitor->pipe[port][peer];
418         if (!pipe)
419         {
420             pipe = &DSPiDefaultPipe[port][peer];
421         }
422         DSP_LoadData((DSPAddrInARM)target, pipe, sizeof(*pipe));
423     }
424     return pipe;
425 }
426 
427 /*---------------------------------------------------------------------------*
428   Name:         DSP_SyncPipe
429 
430   Description:  Update DSP pipe information to the latest content.
431 
432   Arguments:    pipe: Pipe information
433 
434   Returns:      None.
435  *---------------------------------------------------------------------------*/
DSP_SyncPipe(DSPPipe * pipe)436 void DSP_SyncPipe(DSPPipe *pipe)
437 {
438     (void)DSP_LoadPipe(pipe,
439                  ((pipe->flags & DSP_PIPE_FLAG_PORTMASK) >> 1),
440                  (pipe->flags & 1));
441 }
442 
443 /*---------------------------------------------------------------------------*
444   Name:         DSP_FlushPipe
445 
446   Description:  Flushes the DSP pipe stream
447 
448   Arguments:    pipe: Pipe information
449                 port: Pipe port number
450                 peer: DSP_PIPE_INPUT or DSP_PIPE_OUTPUT
451 
452   Returns:      None.
453  *---------------------------------------------------------------------------*/
DSP_FlushPipe(DSPPipe * pipe)454 void DSP_FlushPipe(DSPPipe *pipe)
455 {
456     // Write back to the DSP only the pointer updated from the ARM side
457     int     port = ((pipe->flags & DSP_PIPE_FLAG_PORTMASK) >> 1);
458     int     peer = (pipe->flags & 1);
459     DSPPipeMonitor *monitor = (DSPPipeMonitor *)DSPiPipeMonitorAddress;
460     DSPPipe        *target = &monitor->pipe[port][peer];
461     if (peer == DSP_PIPE_INPUT)
462     {
463         DSP_StoreData((DSPAddrInARM)&target->rpos, &pipe->rpos, sizeof(target->rpos));
464     }
465     else
466     {
467         DSP_StoreData((DSPAddrInARM)&target->wpos, &pipe->wpos, sizeof(target->wpos));
468     }
469     // Update notification to DSP side
470     DSP_SendData(DSP_PIPE_COMMAND_REGISTER, (u16)(pipe->flags & DSP_PIPE_FLAG_PORTMASK));
471 }
472 
473 /*---------------------------------------------------------------------------*
474   Name:         DSP_GetPipeReadableSize
475 
476   Description:  Get maximum size that currently can be read from the specified DSP pipe
477 
478   Arguments:    pipe: Pipe information
479 
480   Returns:      Maximum size that currently can be read
481  *---------------------------------------------------------------------------*/
DSP_GetPipeReadableSize(const DSPPipe * pipe)482 u16 DSP_GetPipeReadableSize(const DSPPipe *pipe)
483 {
484     return DSP_BYTE_TO_UNIT(((pipe->wpos - pipe->rpos) +
485            (((pipe->rpos ^ pipe->wpos) < 0x8000) ? 0 : pipe->length)) & ~0x8000);
486 }
487 
488 /*---------------------------------------------------------------------------*
489   Name:         DSP_GetPipeWritableSize
490 
491   Description:  Get maximum size that currently can be written to the specified DSP pipe
492 
493   Arguments:    pipe: Pipe information
494 
495   Returns:      Maximum size that currently can be written
496  *---------------------------------------------------------------------------*/
DSP_GetPipeWritableSize(const DSPPipe * pipe)497 u16 DSP_GetPipeWritableSize(const DSPPipe *pipe)
498 {
499     return DSP_BYTE_TO_UNIT(((pipe->rpos - pipe->wpos) +
500            (((pipe->wpos ^ pipe->rpos) < 0x8000) ? 0 : pipe->length)) & ~0x8000);
501 }
502 
503 /*---------------------------------------------------------------------------*
504   Name:         DSP_ReadPipe
505 
506   Description:  Read data from the DSP pipe communication port
507 
508   Arguments:    pipe: Pipe information
509                 buffer: Transfer destination buffer
510                 length: Transfer size (However, the units are the word size of that environment)
511                          Be careful that the ARM side is 1-byte units, and the DSP side is 2-byte units.
512 
513   Returns:      None.
514  *---------------------------------------------------------------------------*/
DSP_ReadPipe(DSPPipe * pipe,void * buffer,u16 length)515 void DSP_ReadPipe(DSPPipe *pipe, void *buffer, u16 length)
516 {
517     OSIntrMode  bak = OS_DisableInterrupts();
518     u8         *dst = (u8 *)buffer;
519     BOOL        modified = FALSE;
520     length = DSP_UNIT_TO_BYTE(length);
521     DSP_SyncPipe(pipe);
522     while (length > 0)
523     {
524         u16     rpos = pipe->rpos;
525         u16     wpos = pipe->wpos;
526         u16     phase = (u16)(rpos ^ wpos);
527         // Wait for completion if read-empty
528         if (phase == 0x0000)
529         {
530             if (modified)
531             {
532                 DSP_FlushPipe(pipe);
533                 modified = FALSE;
534             }
535             DSPi_WaitForPipe(pipe);
536         }
537         else
538         {
539             // If not, read from a safe range
540             u16     pos = (u16)(rpos & ~0x8000);
541             u16     end = (u16)((phase < 0x8000) ? (wpos & ~0x8000) : pipe->length);
542             u16     len = (u16)((length < end - pos) ? length : (end - pos));
543             len = (u16)(len & ~(DSP_WORD_UNIT - 1));
544             DSP_LoadData(DSP_ADDR_TO_ARM(pipe->address) + pos, dst, len);
545             length -= len;
546             dst += DSP_BYTE_TO_UNIT(len);
547             pipe->rpos = (u16)((pos + len < pipe->length) ? (rpos + len) : (~rpos & 0x8000));
548             modified = TRUE;
549         }
550     }
551     // If there is an addition, notify here
552     if (modified)
553     {
554         DSP_FlushPipe(pipe);
555         modified = FALSE;
556     }
557     (void)OS_RestoreInterrupts(bak);
558 }
559 
560 /*---------------------------------------------------------------------------*
561   Name:         DSP_WritePipe
562 
563   Description:  Writes data to the DSP pipe communication port
564 
565   Arguments:    pipe: Pipe information
566                 buffer: Transfer source buffer
567                 length: Transfer size (However, the units are the word size of that environment)
568                          Note that the ARM side is 1-byte units, and the DSP side is 2-byte units.
569 
570   Returns:      None.
571  *---------------------------------------------------------------------------*/
DSP_WritePipe(DSPPipe * pipe,const void * buffer,u16 length)572 void DSP_WritePipe(DSPPipe *pipe, const void *buffer, u16 length)
573 {
574     OSIntrMode  bak = OS_DisableInterrupts();
575     const u8   *src = (const u8 *)buffer;
576     BOOL        modified = FALSE;
577     length = DSP_UNIT_TO_BYTE(length);
578     DSP_SyncPipe(pipe);
579     while (length > 0)
580     {
581         u16     rpos = pipe->rpos;
582         u16     wpos = pipe->wpos;
583         u16     phase = (u16)(rpos ^ wpos);
584         // If write-full, wait for completion
585         if (phase == 0x8000)
586         {
587             if (modified)
588             {
589                 DSP_FlushPipe(pipe);
590                 modified = FALSE;
591             }
592             DSPi_WaitForPipe(pipe);
593         }
594         else
595         {
596             // If not, write to a safe range
597             u16     pos = (u16)(wpos & ~0x8000);
598             u16     end = (u16)((phase < 0x8000) ? pipe->length : (rpos & ~0x8000));
599             u16     len = (u16)((length < end - pos) ? length : (end - pos));
600             len = (u16)(len & ~(DSP_WORD_UNIT - 1));
601             DSP_StoreData(DSP_ADDR_TO_ARM(pipe->address) + pos, src, len);
602             length -= len;
603             src += DSP_BYTE_TO_UNIT(len);
604             pipe->wpos = (u16)((pos + len < pipe->length) ? (wpos + len) : (~wpos & 0x8000));
605             modified = TRUE;
606         }
607     }
608     // If there is an addition, notify here
609     if (modified)
610     {
611         DSP_FlushPipe(pipe);
612         modified = FALSE;
613     }
614     (void)OS_RestoreInterrupts(bak);
615 }
616 
617 /*---------------------------------------------------------------------------*
618   Name:         DSP_HookPipeNotification
619 
620   Description:  Pipe notification hook that should be called in a DSP interrupt
621 
622   Arguments:    None.
623 
624   Returns:      None.
625  *---------------------------------------------------------------------------*/
DSP_HookPipeNotification(void)626 void DSP_HookPipeNotification(void)
627 {
628     // CR2 dedicated for pipe communication
629     // However, for some reason a CR interrupt was not generated, so currently, substitute semaphore with only one bit
630     //
631     while (((DSP_GetSemaphore() & 0x8000) != 0) || DSP_RecvDataIsReady(DSP_PIPE_COMMAND_REGISTER))
632     {
633         DSP_ClearSemaphore(0x8000);
634         while (DSP_RecvDataIsReady(DSP_PIPE_COMMAND_REGISTER))
635         {
636             // Initially, the shared structure address is notified from the DSP side
637             if (DSPiPipeMonitorAddress == 0)
638             {
639                 DSPiPipeMonitorAddress = DSP_ADDR_TO_ARM(DSP_RecvData(DSP_PIPE_COMMAND_REGISTER));
640             }
641             // Thereafter, only updated pipes are notified
642             else
643             {
644                 u16     recvdata = DSP_RecvData(DSP_PIPE_COMMAND_REGISTER);
645                 int     port = (recvdata >> 1);
646                 int     peer = (recvdata & 1);
647                 // If a monitoring source exists on the ARM side, verify the pipe information
648                 if (DSPiCallback[port])
649                 {
650                     (*DSPiCallback[port])(DSPiCallbackArgument[port], port, peer);
651                 }
652                 else
653                 {
654                     DSPPipe pipe[1];
655                     (void)DSP_LoadPipe(pipe, port, peer);
656                     // If updating the file opened on the DSP side, notify the thread
657                     if ((peer == DSP_PIPE_INPUT) && ((pipe->flags & DSP_PIPE_FLAG_BOUND) != 0))
658                     {
659                         DSPi_NotifyFileIOUpdation(port);
660                     }
661                 }
662             }
663             // Notify update to thread during blocking
664             OS_WakeupThread(DSPiBlockingQueue);
665         }
666     }
667 }
668