Home | History | Annotate | Download | only in libbridge
      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 */
     98 extern int hMediaFile;		/* class driver handle */
     99 
    100 /*  ----------------------------------- Function Prototypes */
    101 static 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  */
    109 DBAPI 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  */
    187 DBAPI 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  */
    276 DBAPI 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 	}
    335 func_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  */
    348 DBAPI 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  */
    371 DBAPI 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  */
    398 DBAPI 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  */
    454 DBAPI 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 	}
    588 loop_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  */
    613 DBAPI 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  */
    657 DBAPI 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  */
    699 DBAPI
    700 DSPStream_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  */
    752 DBAPI 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  */
    788 DBAPI 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  */
    821 static 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