1/*
2 * dspbridge/src/api/linux/DSPStrm.c
3 *
4 * DSP-BIOS Bridge driver support functions for TI OMAP processors.
5 *
6 * Copyright (C) 2007 Texas Instruments, Inc.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published
10 * by the Free Software Foundation version 2.1 of the License.
11 *
12 * This program is distributed .as is. WITHOUT ANY WARRANTY of any kind,
13 * whether express or implied; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 * Lesser General Public License for more details.
16 */
17
18/*
19 *  ======== DSPStrm.c ========
20 *  Description:
21 *      This is the source for the DSP/BIOS Bridge API stream module. The
22 *      parameters are validated at the API level, but the bulk of the
23 *      work is done at the driver level through the PM STRM module.
24 *
25 *  Public Functions:
26 *      DSPStream_AllocateBuffers
27 *      DSPStream_Close
28 *      DSPStream_FreeBuffers
29 *      DSPStream_GetInfo
30 *      DSPStream_Idle
31 *      DSPStream_Issue
32 *      DSPStream_Open
33 *      DSPStream_Reclaim
34 *      DSPStream_RegisterNotify
35 *      DSPStream_Select
36 *
37 *! Revision History
38 *! ================
39 *! 13-Mar-2002 map Checking for invalid direction in DSPStream_Open()
40 *! 12-Mar-2002 map Checking for invalid node handle in
41 *!                 DSPStream_Open().
42 *! 11-Mar-2002 map Checking that bufsize is not smaller than specified
43 *!                  number of bytes in buffer in DSPStream_Issue().
44 *! 06-Jan-2002 ag  STRMMODE_ZEROCOPY(SM buffer swap) enabled.
45 *! 17-Dec-2001 ag  STRMMODE_RDMA(DDMA) enabled.
46 *! 04-Dec-2001 ag  Changed user event name string in DSPStream_Open().
47 *!                 Added stream direction and index.
48 *! 16-Nov-2001 ag  Added SM allocation for streaming.
49 *! 07-Jun-2001 sg  Made buffer allocate/free fxn names plural.
50 *! 18-May-2001 jeh Close event handle in DSPStream_Open() if failure.
51 *! 11-Apr-2001 rr: DSPStream_UnPrepareBuffer checks for pBuffer == NULL
52 *!                 (not for *pBuffer).
53 *! 13-Dec-2000 jeh Return DSP_EPOINTER, not DSP_EHANDLE in
54 *!					DSPStream_Select() for NULL pointers.
55 *!					Also set *pMask to 0 if nStreams is 0.
56 *! 05-Dec-2000 jeh Return DSP_ESIZE, not DSP_EVALUE in DSPStream_GetInfo,
57 *!                 set status to DSP_SOK in DSPStream_UnprepareBuffer().
58 *! 10-Nov-2000 rr: DSP_PBUFFER modified to BYTE *. RegisterNotify
59 *!                 catches Invalid Events and Masks.
60 *! 23-Oct-2000 jeh Free buffers in DSPStream_FreeBuffer().
61 *! 28-Sep-2000 jeh Removed DSP_BUFFERATTR param from DSP_StreamAllocateBuffer.
62 *! 07-Sep-2000 jeh Changed type HANDLE in DSPStream_RegisterNotify to
63 *!                 DSP_HNOTIFICATION.
64 *! 04-Aug-2000 rr: Name changed to DSPStrm.c
65 *! 27-Jul-2000 rr: Types updated to ver 0.8 API.
66 *! 18-Jul-2000 rr: STRM API calls into the Class driver.
67 *!                 Only parameters are validated here.
68 *! 15-May-2000 gp: Return DSP_EHANDLE fromo DSPStream_Close().
69 *! 19-Apr-2000 ww: Updated based on code review.
70 *! 12-Apr-2000 ww: Created based on DirectDSP API specification, Version 0.6.
71 *
72 */
73
74/*  ----------------------------------- Host OS */
75#include <host_os.h>
76
77/*  ----------------------------------- DSP/BIOS Bridge */
78#include <std.h>
79#include <dbdefs.h>
80#include <errbase.h>
81
82/*  ----------------------------------- OS Adaptation Layer */
83#include <csl.h>
84
85/*  ----------------------------------- Others */
86#include <dsptrap.h>
87#include <memry.h>
88
89/*  ----------------------------------- This */
90#include "_dbdebug.h"
91
92#include <DSPStream.h>
93
94/*  ----------------------------------- Defines, Data Structures, Typedefs */
95#define STRM_MAXLOCKPAGES       64
96
97/*  ----------------------------------- Globals */
98extern int hMediaFile;		/* class driver handle */
99
100/*  ----------------------------------- Function Prototypes */
101static DSP_STATUS GetStrmInfo(DSP_HSTREAM hStream, struct STRM_INFO *pStrmInfo,
102			      UINT uStreamInfoSize);
103
104/*
105 *  ======== DSPStream_AllocateBuffers ========
106 *  Purpose:
107 *      Allocate data buffers for use with a specific stream.
108 */
109DBAPI DSPStream_AllocateBuffers(DSP_HSTREAM hStream, UINT uSize,
110			  OUT BYTE **apBuffer, UINT uNumBufs)
111{
112	UINT i;
113	UINT uAllocated = 0;
114	DSP_STATUS status = DSP_SOK;
115	Trapped_Args tempStruct;
116	PVOID pBuf = NULL;
117	struct STRM_INFO strmInfo;
118	struct DSP_STREAMINFO userInfo;
119
120	DEBUGMSG(DSPAPI_ZONE_FUNCTION,
121			(TEXT("NODE: DSPStream_AllocateBuffers:\r\n")));
122	if (!hStream) {
123		/* Invalid pointer */
124		status = DSP_EHANDLE;
125		DEBUGMSG(DSPAPI_ZONE_ERROR,
126				(TEXT("NODE: DSPStream_AllocateBuffers: "
127						"hStrm is Invalid \r\n")));
128		return status;
129	}
130	if (!apBuffer) {
131		/* Invalid parameter */
132		status = DSP_EPOINTER;
133		DEBUGMSG(DSPAPI_ZONE_ERROR,
134			(TEXT("NODE: DSPStream_AllocateBuffers: "
135				"Invalid pointer in the Input\r\n")));
136		return status;
137	}
138	for (i = 0; i < uNumBufs; i++)
139		apBuffer[i] = NULL;
140
141	strmInfo.pUser = &userInfo;
142	status = GetStrmInfo(hStream, &strmInfo, sizeof(struct DSP_STREAMINFO));
143	if (!DSP_SUCCEEDED(status)) {
144		status = DSP_EFAIL;
145		DEBUGMSG(DSPAPI_ZONE_ERROR,
146			(TEXT("DSPStream_AllocateBuffers: "
147				"DSP_FAILED to get strm info\r\n")));
148		return status;
149	}
150	if (strmInfo.uSegment > 0) {
151		/* Alloc SM */
152		tempStruct.ARGS_STRM_ALLOCATEBUFFER.hStream = hStream;
153		tempStruct.ARGS_STRM_ALLOCATEBUFFER.uSize = uSize;
154		tempStruct.ARGS_STRM_ALLOCATEBUFFER.apBuffer = apBuffer;
155		tempStruct.ARGS_STRM_ALLOCATEBUFFER.uNumBufs = uNumBufs;
156		/* Call DSP Trap */
157		status = DSPTRAP_Trap(&tempStruct,
158				CMD_STRM_ALLOCATEBUFFER_OFFSET);
159	} else {
160		/* Allocate local buffers */
161		for (i = 0; i < uNumBufs; i++) {
162			pBuf = MEM_Alloc(uSize, MEM_NONPAGED);
163			if (!pBuf) {
164				status = DSP_EMEMORY;
165				uAllocated = i;
166				break;
167			} else
168				apBuffer[i] = pBuf;
169
170		}
171		if (DSP_FAILED(status)) {
172			/* Free buffers allocated so far */
173			for (i = 0; i < uAllocated; i++) {
174				MEM_Free(apBuffer[i]);
175				apBuffer[i] = NULL;
176			}
177		}
178	}
179	return status;
180}
181
182/*
183 *  ======== DSPStream_Close ========
184 *  Purpose:
185 *      Close a stream and free the underlying stream object.
186 */
187DBAPI DSPStream_Close(DSP_HSTREAM hStream)
188{
189#ifndef LINUX
190	HANDLE hEvent;
191#endif
192	DSP_STATUS status = DSP_SOK;
193	Trapped_Args tempStruct;
194	struct STRM_INFO strmInfo;
195	struct DSP_STREAMINFO userInfo;
196	struct CMM_OBJECT *hCmm = NULL;	/* SM Mgr handle */
197	struct CMM_INFO pInfo;	/* CMM info; use for virtual space allocation */
198
199	DEBUGMSG(DSPAPI_ZONE_FUNCTION, (TEXT("NODE: DSPStream_Close:\r\n")));
200
201	if (!hStream) {
202		/* Invalid pointer */
203		status = DSP_EHANDLE;
204		DEBUGMSG(DSPAPI_ZONE_ERROR,
205			(TEXT("NODE: DSPStream_Close: hStrm is Invalid \r\n")));
206		return status;
207	}
208	/* Unmap stream's process virtual space, if any */
209	strmInfo.pUser = &userInfo;
210	status = GetStrmInfo(hStream, &strmInfo, sizeof(struct DSP_STREAMINFO));
211	if (!DSP_SUCCEEDED(status)) {
212		status = DSP_EFAIL;
213		DEBUGMSG(DSPAPI_ZONE_ERROR, (TEXT("NODE: DSPStream_Close: "
214					"ERROR in Getting Strm Info \r\n")));
215		return status;
216	}
217	if (strmInfo.pVirtBase != NULL) {
218		/* Get segment size.
219		 >0 is SM segment. Get default SM Mgr */
220		tempStruct.ARGS_CMM_GETHANDLE.hProcessor = NULL;
221		tempStruct.ARGS_CMM_GETHANDLE.phCmmMgr = &hCmm;
222		status = DSPTRAP_Trap(&tempStruct, CMD_CMM_GETHANDLE_OFFSET);
223		if (DSP_SUCCEEDED(status)) {
224			/* Get SM segment info from CMM */
225			tempStruct.ARGS_CMM_GETINFO.hCmmMgr = hCmm;
226			tempStruct.ARGS_CMM_GETINFO.pCmmInfo = &pInfo;
227			status = DSPTRAP_Trap(&tempStruct,
228					CMD_CMM_GETINFO_OFFSET);
229		}
230		/* strmInfo.uSegment is probably already OK here,
231		   so following checks may not be required */
232		if (DSP_SUCCEEDED(status) &&
233			(pInfo.ulNumGPPSMSegs >= strmInfo.uSegment)) {
234			/* segInfo index starts at 0 */
235			if ((pInfo.segInfo[strmInfo.uSegment-1].dwSegBasePa
236				!= 0) && (pInfo.segInfo[strmInfo.uSegment-1]\
237					.ulTotalSegSize) > 0) {
238				if (munmap(strmInfo.pVirtBase,
239					pInfo.segInfo[strmInfo.uSegment-1]\
240						.ulTotalSegSize)) {
241					status = DSP_EFAIL;
242				}
243			}
244		} else
245			status = DSP_EBADSEGID;	/*no SM segments */
246
247	}
248#ifndef LINUX			/* Events are handled in kernel */
249	if (DSP_SUCCEEDED(status)) {
250		/* Get the user event from the stream */
251		/* Set up the structure */
252		tempStruct.ARGS_STRM_GETEVENTHANDLE.hStream = hStream;
253		tempStruct.ARGS_STRM_GETEVENTHANDLE.phEvent = &hEvent;
254		status = DSPTRAP_Trap(&tempStruct,
255				CMD_STRM_GETEVENTHANDLE_OFFSET);
256	}
257#endif
258	if (DSP_SUCCEEDED(status)) {
259		/* Now close the stream */
260		tempStruct.ARGS_STRM_CLOSE.hStream = hStream;
261		status = DSPTRAP_Trap(&tempStruct, CMD_STRM_CLOSE_OFFSET);
262	}
263#ifndef LINUX			/* Events are handled in kernel */
264	if (DSP_SUCCEEDED(status))
265		CloseHandle(hEvent);
266
267#endif
268	return status;
269}
270
271/*
272 *  ======== DSPStream_FreeBuffers ========
273 *  Purpose:
274 *      Free a previously allocated stream data buffer.
275 */
276DBAPI DSPStream_FreeBuffers(DSP_HSTREAM hStream, IN BYTE **apBuffer,
277		UINT uNumBufs)
278{
279	UINT i;
280	DSP_STATUS status = DSP_SOK;
281	Trapped_Args tempStruct;
282	struct STRM_INFO strmInfo;
283	struct DSP_STREAMINFO userInfo;
284
285	DEBUGMSG(DSPAPI_ZONE_FUNCTION,
286			(TEXT("NODE:DSPStream_FreeBuffers:\r\n")));
287
288	if (!hStream) {
289		/* Invalid pointer */
290		status = DSP_EHANDLE;
291		DEBUGMSG(DSPAPI_ZONE_ERROR,
292			(TEXT("NODE: DSPStream_FreeBuffers: "
293						"hStrm is Invalid \r\n")));
294		goto func_end;
295	}
296	if (!apBuffer) {
297		/* Invalid parameter */
298		status = DSP_EPOINTER;
299		DEBUGMSG(DSPAPI_ZONE_ERROR,
300				(TEXT("NODE: DSPStream_FreeBuffers: "
301					"Invalid pointer in the Input\r\n")));
302		goto func_end;
303	}
304	strmInfo.pUser = &userInfo;	/* need valid user info ptr */
305	status = GetStrmInfo(hStream, &strmInfo, sizeof(struct DSP_STREAMINFO));
306	if (!DSP_SUCCEEDED(status)) {
307		DEBUGMSG(DSPAPI_ZONE_ERROR,
308				(TEXT("DSPStream_FreeBuffers. "
309						"Free Failed. Bad mode.")));
310		status = DSP_EFAIL;
311		goto func_end;
312	}
313	if (strmInfo.uSegment > 0) {
314		/* Free SM allocations */
315		tempStruct.ARGS_STRM_FREEBUFFER.hStream = hStream;
316		tempStruct.ARGS_STRM_FREEBUFFER.apBuffer = apBuffer;
317		tempStruct.ARGS_STRM_FREEBUFFER.uNumBufs = uNumBufs;
318		/* Call DSP Trap */
319		status = DSPTRAP_Trap(&tempStruct, CMD_STRM_FREEBUFFER_OFFSET);
320		if (DSP_FAILED(status)) {
321			DEBUGMSG(DSPAPI_ZONE_ERROR,
322				(TEXT("DSPStream_FreeBuffers: "
323						 "Failed to Free Buf")));
324			status = DSP_EFAIL;
325		}
326	} else {
327		for (i = 0; i < uNumBufs; i++) {
328			/* Free local allocation */
329			if (apBuffer[i]) {
330				MEM_Free((PVOID)apBuffer[i]);
331				apBuffer[i] = NULL;
332			}
333		}	/* end for */
334	}
335func_end:
336	/* Return DSP_SOK if OS calls returned 0 */
337	if (status == 0)
338		status = DSP_SOK;
339
340	return status;
341}
342
343/*
344 *  ======== DSPStream_GetInfo ========
345 *  Purpose:
346 *      Get information about a stream.
347 */
348DBAPI DSPStream_GetInfo(DSP_HSTREAM hStream,
349		  OUT struct DSP_STREAMINFO *pStreamInfo, UINT uStreamInfoSize)
350{
351	DSP_STATUS status = DSP_SOK;
352	struct STRM_INFO strmInfo;/* include stream's private virt addr info */
353
354	DEBUGMSG(DSPAPI_ZONE_FUNCTION, (TEXT("NODE: DSPStream_GetInfo:\r\n")));
355
356	strmInfo.pUser = pStreamInfo;
357	status = GetStrmInfo(hStream, &strmInfo, uStreamInfoSize);
358	/* Return DSP_SOK if OS calls returned 0 */
359	if (status == 0)
360		status = DSP_SOK;
361
362	return status;
363}
364
365/*
366 *  ======== DSPStream_Idle ========
367 *  Purpose:
368 *      Terminate I/O with a particular stream, and (optionally)
369 *      flush output data buffers.
370 */
371DBAPI DSPStream_Idle(DSP_HSTREAM hStream, bool bFlush)
372{
373	DSP_STATUS status = DSP_SOK;
374	Trapped_Args tempStruct;
375
376	DEBUGMSG(DSPAPI_ZONE_FUNCTION, (TEXT("NODE: DSPStream_Idle:\r\n")));
377
378	if (hStream) {
379		/* Set up the structure */
380		/* Call DSP Trap */
381		tempStruct.ARGS_STRM_IDLE.hStream = hStream;
382		tempStruct.ARGS_STRM_IDLE.bFlush = bFlush;
383		status = DSPTRAP_Trap(&tempStruct, CMD_STRM_IDLE_OFFSET);
384	} else {
385		/* Invalid pointer */
386		status = DSP_EHANDLE;
387		DEBUGMSG(DSPAPI_ZONE_ERROR, (TEXT("NODE: DSPStream_Idle: "
388						"hStrm is Invalid \r\n")));
389	}
390	return status;
391}
392
393/*
394 *  ======== DSPStream_Issue ========
395 *  Purpose:
396 *      Send a buffer of data to a stream.
397 */
398DBAPI DSPStream_Issue(DSP_HSTREAM hStream, IN BYTE *pBuffer,
399		ULONG dwDataSize, ULONG dwBufSize, IN DWORD dwArg)
400{
401	DSP_STATUS status = DSP_SOK;
402	Trapped_Args tempStruct;
403
404	DEBUGMSG(DSPAPI_ZONE_FUNCTION, (TEXT("NODE: DSPStream_Issue:\r\n")));
405
406	if (hStream) {
407		/* Check the size of the buffer */
408		if (pBuffer) {
409			/* Check that the size isn't too small */
410			if (dwDataSize > dwBufSize) {
411				status = DSP_EINVALIDARG;
412				DEBUGMSG(DSPAPI_ZONE_ERROR,
413					(TEXT("NODE: DSPStream_Issue: "
414					"Invalid argument in the Input\r\n")));
415			} else {
416				/* Set up the structure */
417				tempStruct.ARGS_STRM_ISSUE.hStream = hStream;
418				tempStruct.ARGS_STRM_ISSUE.pBuffer = pBuffer;
419				tempStruct.ARGS_STRM_ISSUE.dwBytes = dwDataSize;
420				tempStruct.ARGS_STRM_ISSUE.dwBufSize =
421							dwBufSize;
422				tempStruct.ARGS_STRM_ISSUE.dwArg = dwArg;
423				/* Call DSP Trap */
424				status = DSPTRAP_Trap(&tempStruct,
425					CMD_STRM_ISSUE_OFFSET);
426				/* Return DSP_SOK if OS calls returned 0 */
427				if (status == 0)
428					status = DSP_SOK;
429
430			}
431		} else {
432			/* Invalid parameter */
433			status = DSP_EPOINTER;
434			DEBUGMSG(DSPAPI_ZONE_ERROR,
435				(TEXT("NODE: DSPStream_Issue: "
436					"Invalid pointer in the Input\r\n")));
437		}
438	} else {
439		/* Invalid pointer */
440		status = DSP_EHANDLE;
441		DEBUGMSG(DSPAPI_ZONE_ERROR, (TEXT("NODE: DSPStream_Issue: "
442						"hStrm is Invalid \r\n")));
443	}
444
445	return status;
446}
447
448/*
449 *  ======== DSPStream_Open ========
450 *  Purpose:
451 *      Retrieve a stream handle for sending/receiving data buffers
452 *      to/from a task node on a DSP.
453 */
454DBAPI DSPStream_Open(DSP_HNODE hNode, UINT uDirection, UINT uIndex,
455	       IN OPTIONAL struct DSP_STREAMATTRIN *pAttrIn,
456	       OUT DSP_HSTREAM *phStream)
457{
458	DSP_STATUS status = DSP_SOK;
459	Trapped_Args tempStruct;
460	struct STRM_ATTR strmAttrs;
461#ifndef LINUX			/* Events are handled in kernel */
462	CHAR szEventName[STRM_MAXEVTNAMELEN];
463	WCHAR wszEventName[STRM_MAXEVTNAMELEN];
464	CHAR szTemp[STRM_MAXEVTNAMELEN];
465#endif
466	struct CMM_OBJECT *hCmm = NULL;	/* SM Mgr handle */
467	struct CMM_INFO pInfo;/* CMM info; use for virtual space allocation */
468
469	DEBUGMSG(DSPAPI_ZONE_FUNCTION, (TEXT("NODE: DSPStream_Open:\r\n")));
470
471	if (!hNode) {
472		status = DSP_EHANDLE;
473		DEBUGMSG(DSPAPI_ZONE_ERROR, (TEXT("NODE: DSPStream_Open: "
474					"Invalid handle in the Input\r\n")));
475		return status;
476	}
477	if (uDirection != DSP_TONODE && uDirection != DSP_FROMNODE) {
478		status = DSP_EDIRECTION;
479		DEBUGMSG(DSPAPI_ZONE_ERROR, (TEXT("NODE: DSPStream_Open: "
480					"Invalid direction in the Input\r\n")));
481		return status;
482	}
483	if (!phStream) {
484		status = DSP_EPOINTER;
485		DEBUGMSG(DSPAPI_ZONE_ERROR,
486			(TEXT("NODE: DSPStream_Open: "
487				"Invalid pointer in the Input\r\n")));
488		return status;
489	}
490	*phStream = NULL;
491	strmAttrs.hUserEvent = NULL;
492#ifndef LINUX			/* Events are handled in kernel */
493			 /* Create a 'named' user event that is unique.*/
494	strmAttrs.pStreamAttrIn = pAttrIn;
495	szEventName[0] = 'E';
496	szEventName[1] = 'V';
497	szEventName[2] = '\0';
498	/* append hNode handle string */
499	strncat(szEventName, _ultoa((ULONG)hNode, szTemp, 16), 8);
500	/* now append stream index and direction */
501	strncat(szEventName, _ultoa((ULONG)uDirection, szTemp, 16), 2);
502	strmAttrs.pstrEventName =
503		strncat(szEventName, _ultoa((ULONG)uIndex, szTemp, 16), 3);
504	(Void)CSL_AnsiToWchar(wszEventName, szEventName, STRM_MAXEVTNAMELEN);
505	/* Create an auto reset event. */
506	strmAttrs.hUserEvent = CreateEvent(NULL,false,false,wszEventName);
507	if (!strmAttrs.hUserEvent) {
508		status = DSP_EFAIL;
509		DEBUGMSG(DSPAPI_ZONE_ERROR, (TEXT("NODE: DSPStream_Open: "
510					"Failed to Create the Event \r\n")));
511	}
512#endif
513	 /*  Default stream mode is PROCCOPY.
514	 *  Check for currently supported mode(s).*/
515	if (pAttrIn) {
516		if (pAttrIn->lMode == STRMMODE_LDMA) {
517			/* No System-DMA support */
518			status = DSP_ENOTIMPL;
519		} else
520		    if ((pAttrIn->lMode != STRMMODE_PROCCOPY)
521				&& (pAttrIn->lMode != STRMMODE_ZEROCOPY)
522				&& (pAttrIn->lMode != STRMMODE_RDMA)) {
523			status = DSP_ESTRMMODE;	/* illegal stream mode */
524		}
525		pAttrIn->uSegment = abs(pAttrIn->uSegment);
526		/* make non-neg */
527	}
528	 /*  If opening the stream for STRMMODE_ZEROCOPY or
529	 *  STRMMODE_RDMA(DSP-DMA) stream mode, then setup the
530	 *  stream's  CMM translator for the specified SM segment.*/
531	strmAttrs.pVirtBase = NULL;
532	strmAttrs.ulVirtSize = 0;
533	if (DSP_SUCCEEDED(status) && pAttrIn) {
534		if ((pAttrIn->lMode == STRMMODE_ZEROCOPY) ||
535				(pAttrIn->lMode == STRMMODE_RDMA)) {
536			if (pAttrIn->uSegment == 0) {
537				status = DSP_ENOTSHAREDMEM;	/* must be
538								SM segment */
539				goto loop_end;
540			}
541			/* >0 is SM segment. Get default SM Mgr */
542			tempStruct.ARGS_CMM_GETHANDLE.hProcessor = NULL;
543			tempStruct.ARGS_CMM_GETHANDLE.phCmmMgr = &hCmm;
544			status = DSPTRAP_Trap(&tempStruct,
545					CMD_CMM_GETHANDLE_OFFSET);
546			if (status == DSP_SOK) {
547				/* Get SM segment info from CMM */
548				tempStruct.ARGS_CMM_GETINFO.hCmmMgr = hCmm;
549				tempStruct.ARGS_CMM_GETINFO.pCmmInfo = &pInfo;
550				status = DSPTRAP_Trap(&tempStruct,
551						CMD_CMM_GETINFO_OFFSET);
552				if (status != DSP_SOK)
553					status = DSP_EFAIL;
554			} else
555				status = DSP_EFAIL;
556
557			if (!DSP_SUCCEEDED(status ||
558				!(pInfo.ulNumGPPSMSegs >= pAttrIn->uSegment))) {
559				status = DSP_EBADSEGID; /* no SM segments */
560				goto loop_end;
561			}
562			/* segInfo index starts at 0 */
563			if ((pInfo.segInfo[pAttrIn->uSegment-1].dwSegBasePa
564				== 0) || (pInfo.segInfo[pAttrIn->uSegment-1]\
565					.ulTotalSegSize) < 0) {
566				status = DSP_EFAIL;
567				DEBUGMSG(DSPAPI_ZONE_ERROR,
568						(TEXT("STRM:DSPStream_Open: "
569						"Bad SM info...why?\r\n")));
570				goto loop_end;
571			}
572			strmAttrs.pVirtBase = mmap(NULL,
573				pInfo.segInfo[pAttrIn->uSegment-1]\
574				.ulTotalSegSize, PROT_READ | PROT_WRITE,
575				MAP_SHARED | MAP_LOCKED, hMediaFile, pInfo\
576				.segInfo[pAttrIn->uSegment-1].dwSegBasePa);
577			if (strmAttrs.pVirtBase == NULL) {
578				status = DSP_EFAIL;
579				DEBUGMSG(DSPAPI_ZONE_ERROR,
580					(TEXT("STRM: DSPStream_Open: "
581						"Virt alloc failed\r\n")));
582				goto loop_end;
583			}
584			strmAttrs.ulVirtSize =
585			pInfo.segInfo[pAttrIn->uSegment-1].ulTotalSegSize;
586		}
587	}
588loop_end:
589	if (DSP_SUCCEEDED(status)) {
590		/* Set up the structure */
591		strmAttrs.pStreamAttrIn = pAttrIn;
592		/* Call DSP Trap */
593		tempStruct.ARGS_STRM_OPEN.hNode = hNode;
594		tempStruct.ARGS_STRM_OPEN.uDirection = uDirection;
595		tempStruct.ARGS_STRM_OPEN.uIndex = uIndex;
596		tempStruct.ARGS_STRM_OPEN.pAttrIn = &strmAttrs;
597		tempStruct.ARGS_STRM_OPEN.phStream = phStream;
598		status = DSPTRAP_Trap(&tempStruct, CMD_STRM_OPEN_OFFSET);
599#ifndef LINUX			/* Events are handled in kernel */
600		if (DSP_FAILED(status))
601			CloseHandle(strmAttrs.hUserEvent);
602
603#endif
604	}
605	return status;
606}
607
608/*
609 *  ======== DSPStream_PrepareBuffer ========
610 *  Purpose:
611 *      Prepares a buffer.
612 */
613DBAPI DSPStream_PrepareBuffer(DSP_HSTREAM hStream, UINT uSize, BYTE *pBuffer)
614{
615	DSP_STATUS status = DSP_SOK;
616#ifndef LINUX
617	/*  Pages are never swapped out (i.e. always locked in Linux) */
618	ULONG aPageTab[STRM_MAXLOCKPAGES];
619	/* Find the maximum # of pages that could be locked. x86 &
620			ARM=4Kb pages */
621	UINT cPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(NULL, uSize);
622#endif
623	/* Do error checking here to API spec. We don't call down to WCD */
624	if (!hStream)
625		status = DSP_EHANDLE;
626
627	if (DSP_SUCCEEDED(status)) {
628		if (!pBuffer)
629			status = DSP_EPOINTER;
630	}
631
632	if (DSP_SUCCEEDED(status)) {
633		if (uSize <= 0)
634			status = DSP_ESIZE;
635	}
636#ifndef LINUX
637	/*  Pages are never swapped out (i.e. always locked in Linux) */
638	if (DSP_SUCCEEDED(status)) {
639		if (cPages > STRM_MAXLOCKPAGES)
640			status = DSP_EFAIL;
641		else {
642			if (!LockPages((LPVOID)pBuffer, uSize, aPageTab,
643					LOCKFLAG_WRITE))
644				status = DSP_EFAIL;
645		}
646	}
647#endif
648
649	return status;
650}
651
652/*
653 *  ======== DSPStream_Reclaim ========
654 *  Purpose:
655 *      Request a buffer back from a stream.
656 */
657DBAPI DSPStream_Reclaim(DSP_HSTREAM hStream, OUT BYTE **pBufPtr,
658		OUT ULONG *pDataSize, OUT ULONG *pBufSize, OUT DWORD *pdwArg)
659{
660	DSP_STATUS status = DSP_SOK;
661	Trapped_Args tempStruct;
662
663	DEBUGMSG(DSPAPI_ZONE_FUNCTION, (TEXT("NODE: DSPStream_Reclaim:\r\n")));
664
665	if (hStream) {
666		/* Check the size of the buffer */
667		if ((pBufPtr) && (pDataSize) && (pdwArg)) {
668			/* Set up the structure */
669			/* Call DSP Trap */
670			tempStruct.ARGS_STRM_RECLAIM.hStream = hStream;
671			tempStruct.ARGS_STRM_RECLAIM.pBufPtr = pBufPtr;
672			tempStruct.ARGS_STRM_RECLAIM.pBytes = pDataSize;
673			tempStruct.ARGS_STRM_RECLAIM.pBufSize = pBufSize;
674			tempStruct.ARGS_STRM_RECLAIM.pdwArg = pdwArg;
675			status = DSPTRAP_Trap(&tempStruct,
676					CMD_STRM_RECLAIM_OFFSET);
677		} else {
678			/* Invalid parameter */
679			status = DSP_EPOINTER;
680			DEBUGMSG(DSPAPI_ZONE_ERROR,
681				(TEXT("NODE: DSPStream_Reclaim: "
682					"Invalid pointer in the Input\r\n")));
683		}
684	} else {
685		/* Invalid pointer */
686		status = DSP_EHANDLE;
687		DEBUGMSG(DSPAPI_ZONE_ERROR, (TEXT("NODE: DSPStream_Reclaim: "
688						"hStrm is Invalid \r\n")));
689	}
690
691	return status;
692}
693
694/*
695 *  ======== DSPStream_RegisterNotify ========
696 *  Purpose:
697 *      Register to be notified of specific events for this stream.
698 */
699DBAPI
700DSPStream_RegisterNotify(DSP_HSTREAM hStream, UINT uEventMask,
701		 UINT uNotifyType, struct DSP_NOTIFICATION *hNotification)
702{
703	DSP_STATUS status = DSP_SOK;
704	Trapped_Args tempStruct;
705
706	DEBUGMSG(DSPAPI_ZONE_FUNCTION,
707			(TEXT("NODE: DSPStream_RegisterNotify:\r\n")));
708
709	if ((hStream) && (hNotification)) {
710		if (IsValidStrmEvent(uEventMask)) {
711			if (IsValidNotifyMask(uNotifyType)) {
712				/* Set up the structure */
713				/* Call DSP Trap */
714				tempStruct.ARGS_STRM_REGISTERNOTIFY.hStream =
715						hStream;
716				tempStruct.ARGS_STRM_REGISTERNOTIFY.uEventMask =
717						uEventMask;
718				tempStruct.ARGS_STRM_REGISTERNOTIFY\
719						.uNotifyType = uNotifyType;
720				tempStruct.ARGS_STRM_REGISTERNOTIFY\
721						.hNotification = hNotification;
722				status = DSPTRAP_Trap(&tempStruct,
723						CMD_STRM_REGISTERNOTIFY_OFFSET);
724			} else {
725				status = DSP_ENOTIMPL;
726				DEBUGMSG(DSPAPI_ZONE_ERROR,
727					(TEXT("NODE: DSPStream_RegisterNotify: "
728						"Invalid Notify Mask \r\n")));
729			}
730		} else {
731			status = DSP_EVALUE;
732			DEBUGMSG(DSPAPI_ZONE_ERROR,
733					(TEXT("NODE: DSPStream_RegisterNotify: "
734						"Invalid Event Mask \r\n")));
735		}
736	} else {
737		/* Invalid handle */
738		status = DSP_EHANDLE;
739		DEBUGMSG(DSPAPI_ZONE_ERROR,
740			(TEXT("NODE: DSPStream_RegisterNotify: "
741					"Invalid Handle \r\n")));
742	}
743
744	return status;
745}
746
747/*
748 *  ======== DSPStream_Select ========
749 *  Purpose:
750 *      Select a ready stream.
751 */
752DBAPI DSPStream_Select(IN DSP_HSTREAM *aStreamTab,
753		 UINT nStreams, OUT UINT *pMask, UINT uTimeout)
754{
755	DSP_STATUS status = DSP_SOK;
756	Trapped_Args tempStruct;
757
758	DEBUGMSG(DSPAPI_ZONE_FUNCTION, (TEXT("NODE: DSPStream_Select:\r\n")));
759
760	if ((aStreamTab) && (pMask)) {
761		if (nStreams) {
762			/* Set up the structure */
763			/* Call DSP Trap */
764			tempStruct.ARGS_STRM_SELECT.aStreamTab = aStreamTab;
765			tempStruct.ARGS_STRM_SELECT.nStreams = nStreams;
766			tempStruct.ARGS_STRM_SELECT.pMask = pMask;
767			tempStruct.ARGS_STRM_SELECT.uTimeout = uTimeout;
768			status = DSPTRAP_Trap(&tempStruct,
769					CMD_STRM_SELECT_OFFSET);
770		} else
771			/* nStreams == 0 */
772			*pMask = 0;
773	} else {
774		/* Invalid pointer */
775		status = DSP_EPOINTER;
776		DEBUGMSG(DSPAPI_ZONE_ERROR,
777		 (TEXT("NODE: DSPStream_Select: hStrm is Invalid \r\n")));
778	}
779
780	return status;
781}
782
783/*
784 *  ======== DSPStream_UnprepareBuffer ========
785 *  Purpose:
786 *      Unprepares a buffer.
787 */
788DBAPI DSPStream_UnprepareBuffer(DSP_HSTREAM hStream, UINT uSize,
789				BYTE *pBuffer)
790{
791	DSP_STATUS status = DSP_SOK;
792
793	/* Do error checking here to API spec. We don't call down to WCD */
794	if (!hStream)
795		status = DSP_EHANDLE;
796
797	if (DSP_SUCCEEDED(status)) {
798		if (!pBuffer)
799			status = DSP_EPOINTER;
800	}
801
802	if (DSP_SUCCEEDED(status)) {
803		/*|| ((LPVOID)pBuffer == NULL) - already checked above */
804		if ((uSize <= 0))
805			status = DSP_EFAIL;
806	}
807#ifndef LINUX			/*  Pages are never swapped out
808						(i.e. always locked in Linux) */
809	if (DSP_SUCCEEDED(status)) {
810		if (!UnlockPages((LPVOID) pBuffer, uSize))
811			status = DSP_EFAIL;
812	}
813#endif
814
815	return status;
816}
817
818/*
819 *  ======== GetStrmInfo ========
820 */
821static DSP_STATUS GetStrmInfo(DSP_HSTREAM hStream, struct STRM_INFO *pStrmInfo,
822							UINT uStreamInfoSize)
823{
824	DSP_STATUS status = DSP_SOK;
825	Trapped_Args tempStruct;
826
827	if (hStream) {
828		/* Check the size of the buffer */
829		if (pStrmInfo && pStrmInfo->pUser) {
830			if (uStreamInfoSize >= sizeof(struct DSP_STREAMINFO)) {
831				/* user info */
832				/* Set up the structure */
833				/* Call DSP Trap */
834				tempStruct.ARGS_STRM_GETINFO.hStream = hStream;
835				tempStruct.ARGS_STRM_GETINFO.pStreamInfo =
836						pStrmInfo;
837				/* user returned struct DSP_STREAMINFO
838						info size */
839				tempStruct.ARGS_STRM_GETINFO.uStreamInfoSize =
840						uStreamInfoSize;
841				status = DSPTRAP_Trap(&tempStruct,
842						CMD_STRM_GETINFO_OFFSET);
843			} else {
844				status = DSP_ESIZE;
845				DEBUGMSG(DSPAPI_ZONE_ERROR,
846					 (TEXT("NODE: DSPStream_GetInfo: "
847					 "uStreamInfo size is less than the "
848					 "size of struct DSP_STREAMINFO\r\n")));
849			}
850		} else {
851			/* Invalid parameter */
852			status = DSP_EPOINTER;
853			DEBUGMSG(DSPAPI_ZONE_ERROR,
854				 (TEXT("NODE: DSPStream_GetInfo: "
855					"Invalid pointer\r\n")));
856		}
857	} else {
858		/* Invalid pointer */
859		status = DSP_EHANDLE;
860		DEBUGMSG(DSPAPI_ZONE_ERROR, (TEXT(
861			"NODE: DSPStream_GetInfo: hStrm is Invalid \r\n")));
862	}
863
864	return status;
865}
866
867