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