/*
* dspbridge/src/api/linux/DSPStrm.c
*
* DSP-BIOS Bridge driver support functions for TI OMAP processors.
*
* Copyright (C) 2007 Texas Instruments, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation version 2.1 of the License.
*
* This program is distributed .as is. WITHOUT ANY WARRANTY of any kind,
* whether express or implied; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
/*
* ======== DSPStrm.c ========
* Description:
* This is the source for the DSP/BIOS Bridge API stream module. The
* parameters are validated at the API level, but the bulk of the
* work is done at the driver level through the PM STRM module.
*
* Public Functions:
* DSPStream_AllocateBuffers
* DSPStream_Close
* DSPStream_FreeBuffers
* DSPStream_GetInfo
* DSPStream_Idle
* DSPStream_Issue
* DSPStream_Open
* DSPStream_Reclaim
* DSPStream_RegisterNotify
* DSPStream_Select
*
*! Revision History
*! ================
*! 13-Mar-2002 map Checking for invalid direction in DSPStream_Open()
*! 12-Mar-2002 map Checking for invalid node handle in
*! DSPStream_Open().
*! 11-Mar-2002 map Checking that bufsize is not smaller than specified
*! number of bytes in buffer in DSPStream_Issue().
*! 06-Jan-2002 ag STRMMODE_ZEROCOPY(SM buffer swap) enabled.
*! 17-Dec-2001 ag STRMMODE_RDMA(DDMA) enabled.
*! 04-Dec-2001 ag Changed user event name string in DSPStream_Open().
*! Added stream direction and index.
*! 16-Nov-2001 ag Added SM allocation for streaming.
*! 07-Jun-2001 sg Made buffer allocate/free fxn names plural.
*! 18-May-2001 jeh Close event handle in DSPStream_Open() if failure.
*! 11-Apr-2001 rr: DSPStream_UnPrepareBuffer checks for pBuffer == NULL
*! (not for *pBuffer).
*! 13-Dec-2000 jeh Return DSP_EPOINTER, not DSP_EHANDLE in
*! DSPStream_Select() for NULL pointers.
*! Also set *pMask to 0 if nStreams is 0.
*! 05-Dec-2000 jeh Return DSP_ESIZE, not DSP_EVALUE in DSPStream_GetInfo,
*! set status to DSP_SOK in DSPStream_UnprepareBuffer().
*! 10-Nov-2000 rr: DSP_PBUFFER modified to BYTE *. RegisterNotify
*! catches Invalid Events and Masks.
*! 23-Oct-2000 jeh Free buffers in DSPStream_FreeBuffer().
*! 28-Sep-2000 jeh Removed DSP_BUFFERATTR param from DSP_StreamAllocateBuffer.
*! 07-Sep-2000 jeh Changed type HANDLE in DSPStream_RegisterNotify to
*! DSP_HNOTIFICATION.
*! 04-Aug-2000 rr: Name changed to DSPStrm.c
*! 27-Jul-2000 rr: Types updated to ver 0.8 API.
*! 18-Jul-2000 rr: STRM API calls into the Class driver.
*! Only parameters are validated here.
*! 15-May-2000 gp: Return DSP_EHANDLE fromo DSPStream_Close().
*! 19-Apr-2000 ww: Updated based on code review.
*! 12-Apr-2000 ww: Created based on DirectDSP API specification, Version 0.6.
*
*/
/* ----------------------------------- Host OS */
#include <host_os.h>
/* ----------------------------------- DSP/BIOS Bridge */
#include <std.h>
#include <dbdefs.h>
#include <errbase.h>
/* ----------------------------------- OS Adaptation Layer */
#include <csl.h>
/* ----------------------------------- Others */
#include <dsptrap.h>
#include <memry.h>
/* ----------------------------------- This */
#include "_dbdebug.h"
#include <DSPStream.h>
/* ----------------------------------- Defines, Data Structures, Typedefs */
#define STRM_MAXLOCKPAGES 64
/* ----------------------------------- Globals */
extern int hMediaFile; /* class driver handle */
/* ----------------------------------- Function Prototypes */
static DSP_STATUS GetStrmInfo(DSP_HSTREAM hStream, struct STRM_INFO *pStrmInfo,
UINT uStreamInfoSize);
/*
* ======== DSPStream_AllocateBuffers ========
* Purpose:
* Allocate data buffers for use with a specific stream.
*/
DBAPI DSPStream_AllocateBuffers(DSP_HSTREAM hStream, UINT uSize,
OUT BYTE **apBuffer, UINT uNumBufs)
{
UINT i;
UINT uAllocated = 0;
DSP_STATUS status = DSP_SOK;
Trapped_Args tempStruct;
PVOID pBuf = NULL;
struct STRM_INFO strmInfo;
struct DSP_STREAMINFO userInfo;
DEBUGMSG(DSPAPI_ZONE_FUNCTION,
(TEXT("NODE: DSPStream_AllocateBuffers:\r\n")));
if (!hStream) {
/* Invalid pointer */
status = DSP_EHANDLE;
DEBUGMSG(DSPAPI_ZONE_ERROR,
(TEXT("NODE: DSPStream_AllocateBuffers: "
"hStrm is Invalid \r\n")));
return status;
}
if (!apBuffer) {
/* Invalid parameter */
status = DSP_EPOINTER;
DEBUGMSG(DSPAPI_ZONE_ERROR,
(TEXT("NODE: DSPStream_AllocateBuffers: "
"Invalid pointer in the Input\r\n")));
return status;
}
for (i = 0; i < uNumBufs; i++)
apBuffer[i] = NULL;
strmInfo.pUser = &userInfo;
status = GetStrmInfo(hStream, &strmInfo, sizeof(struct DSP_STREAMINFO));
if (!DSP_SUCCEEDED(status)) {
status = DSP_EFAIL;
DEBUGMSG(DSPAPI_ZONE_ERROR,
(TEXT("DSPStream_AllocateBuffers: "
"DSP_FAILED to get strm info\r\n")));
return status;
}
if (strmInfo.uSegment > 0) {
/* Alloc SM */
tempStruct.ARGS_STRM_ALLOCATEBUFFER.hStream = hStream;
tempStruct.ARGS_STRM_ALLOCATEBUFFER.uSize = uSize;
tempStruct.ARGS_STRM_ALLOCATEBUFFER.apBuffer = apBuffer;
tempStruct.ARGS_STRM_ALLOCATEBUFFER.uNumBufs = uNumBufs;
/* Call DSP Trap */
status = DSPTRAP_Trap(&tempStruct,
CMD_STRM_ALLOCATEBUFFER_OFFSET);
} else {
/* Allocate local buffers */
for (i = 0; i < uNumBufs; i++) {
pBuf = MEM_Alloc(uSize, MEM_NONPAGED);
if (!pBuf) {
status = DSP_EMEMORY;
uAllocated = i;
break;
} else
apBuffer[i] = pBuf;
}
if (DSP_FAILED(status)) {
/* Free buffers allocated so far */
for (i = 0; i < uAllocated; i++) {
MEM_Free(apBuffer[i]);
apBuffer[i] = NULL;
}
}
}
return status;
}
/*
* ======== DSPStream_Close ========
* Purpose:
* Close a stream and free the underlying stream object.
*/
DBAPI DSPStream_Close(DSP_HSTREAM hStream)
{
#ifndef LINUX
HANDLE hEvent;
#endif
DSP_STATUS status = DSP_SOK;
Trapped_Args tempStruct;
struct STRM_INFO strmInfo;
struct DSP_STREAMINFO userInfo;
struct CMM_OBJECT *hCmm = NULL; /* SM Mgr handle */
struct CMM_INFO pInfo; /* CMM info; use for virtual space allocation */
DEBUGMSG(DSPAPI_ZONE_FUNCTION, (TEXT("NODE: DSPStream_Close:\r\n")));
if (!hStream) {
/* Invalid pointer */
status = DSP_EHANDLE;
DEBUGMSG(DSPAPI_ZONE_ERROR,
(TEXT("NODE: DSPStream_Close: hStrm is Invalid \r\n")));
return status;
}
/* Unmap stream's process virtual space, if any */
strmInfo.pUser = &userInfo;
status = GetStrmInfo(hStream, &strmInfo, sizeof(struct DSP_STREAMINFO));
if (!DSP_SUCCEEDED(status)) {
status = DSP_EFAIL;
DEBUGMSG(DSPAPI_ZONE_ERROR, (TEXT("NODE: DSPStream_Close: "
"ERROR in Getting Strm Info \r\n")));
return status;
}
if (strmInfo.pVirtBase != NULL) {
/* Get segment size.
>0 is SM segment. Get default SM Mgr */
tempStruct.ARGS_CMM_GETHANDLE.hProcessor = NULL;
tempStruct.ARGS_CMM_GETHANDLE.phCmmMgr = &hCmm;
status = DSPTRAP_Trap(&tempStruct, CMD_CMM_GETHANDLE_OFFSET);
if (DSP_SUCCEEDED(status)) {
/* Get SM segment info from CMM */
tempStruct.ARGS_CMM_GETINFO.hCmmMgr = hCmm;
tempStruct.ARGS_CMM_GETINFO.pCmmInfo = &pInfo;
status = DSPTRAP_Trap(&tempStruct,
CMD_CMM_GETINFO_OFFSET);
}
/* strmInfo.uSegment is probably already OK here,
so following checks may not be required */
if (DSP_SUCCEEDED(status) &&
(pInfo.ulNumGPPSMSegs >= strmInfo.uSegment)) {
/* segInfo index starts at 0 */
if ((pInfo.segInfo[strmInfo.uSegment-1].dwSegBasePa
!= 0) && (pInfo.segInfo[strmInfo.uSegment-1]\
.ulTotalSegSize) > 0) {
if (munmap(strmInfo.pVirtBase,
pInfo.segInfo[strmInfo.uSegment-1]\
.ulTotalSegSize)) {
status = DSP_EFAIL;
}
}
} else
status = DSP_EBADSEGID; /*no SM segments */
}
#ifndef LINUX /* Events are handled in kernel */
if (DSP_SUCCEEDED(status)) {
/* Get the user event from the stream */
/* Set up the structure */
tempStruct.ARGS_STRM_GETEVENTHANDLE.hStream = hStream;
tempStruct.ARGS_STRM_GETEVENTHANDLE.phEvent = &hEvent;
status = DSPTRAP_Trap(&tempStruct,
CMD_STRM_GETEVENTHANDLE_OFFSET);
}
#endif
if (DSP_SUCCEEDED(status)) {
/* Now close the stream */
tempStruct.ARGS_STRM_CLOSE.hStream = hStream;
status = DSPTRAP_Trap(&tempStruct, CMD_STRM_CLOSE_OFFSET);
}
#ifndef LINUX /* Events are handled in kernel */
if (DSP_SUCCEEDED(status))
CloseHandle(hEvent);
#endif
return status;
}
/*
* ======== DSPStream_FreeBuffers ========
* Purpose:
* Free a previously allocated stream data buffer.
*/
DBAPI DSPStream_FreeBuffers(DSP_HSTREAM hStream, IN BYTE **apBuffer,
UINT uNumBufs)
{
UINT i;
DSP_STATUS status = DSP_SOK;
Trapped_Args tempStruct;
struct STRM_INFO strmInfo;
struct DSP_STREAMINFO userInfo;
DEBUGMSG(DSPAPI_ZONE_FUNCTION,
(TEXT("NODE:DSPStream_FreeBuffers:\r\n")));
if (!hStream) {
/* Invalid pointer */
status = DSP_EHANDLE;
DEBUGMSG(DSPAPI_ZONE_ERROR,
(TEXT("NODE: DSPStream_FreeBuffers: "
"hStrm is Invalid \r\n")));
goto func_end;
}
if (!apBuffer) {
/* Invalid parameter */
status = DSP_EPOINTER;
DEBUGMSG(DSPAPI_ZONE_ERROR,
(TEXT("NODE: DSPStream_FreeBuffers: "
"Invalid pointer in the Input\r\n")));
goto func_end;
}
strmInfo.pUser = &userInfo; /* need valid user info ptr */
status = GetStrmInfo(hStream, &strmInfo, sizeof(struct DSP_STREAMINFO));
if (!DSP_SUCCEEDED(status)) {
DEBUGMSG(DSPAPI_ZONE_ERROR,
(TEXT("DSPStream_FreeBuffers. "
"Free Failed. Bad mode.")));
status = DSP_EFAIL;
goto func_end;
}
if (strmInfo.uSegment > 0) {
/* Free SM allocations */
tempStruct.ARGS_STRM_FREEBUFFER.hStream = hStream;
tempStruct.ARGS_STRM_FREEBUFFER.apBuffer = apBuffer;
tempStruct.ARGS_STRM_FREEBUFFER.uNumBufs = uNumBufs;
/* Call DSP Trap */
status = DSPTRAP_Trap(&tempStruct, CMD_STRM_FREEBUFFER_OFFSET);
if (DSP_FAILED(status)) {
DEBUGMSG(DSPAPI_ZONE_ERROR,
(TEXT("DSPStream_FreeBuffers: "
"Failed to Free Buf")));
status = DSP_EFAIL;
}
} else {
for (i = 0; i < uNumBufs; i++) {
/* Free local allocation */
if (apBuffer[i]) {
MEM_Free((PVOID)apBuffer[i]);
apBuffer[i] = NULL;
}
} /* end for */
}
func_end:
/* Return DSP_SOK if OS calls returned 0 */
if (status == 0)
status = DSP_SOK;
return status;
}
/*
* ======== DSPStream_GetInfo ========
* Purpose:
* Get information about a stream.
*/
DBAPI DSPStream_GetInfo(DSP_HSTREAM hStream,
OUT struct DSP_STREAMINFO *pStreamInfo, UINT uStreamInfoSize)
{
DSP_STATUS status = DSP_SOK;
struct STRM_INFO strmInfo;/* include stream's private virt addr info */
DEBUGMSG(DSPAPI_ZONE_FUNCTION, (TEXT("NODE: DSPStream_GetInfo:\r\n")));
strmInfo.pUser = pStreamInfo;
status = GetStrmInfo(hStream, &strmInfo, uStreamInfoSize);
/* Return DSP_SOK if OS calls returned 0 */
if (status == 0)
status = DSP_SOK;
return status;
}
/*
* ======== DSPStream_Idle ========
* Purpose:
* Terminate I/O with a particular stream, and (optionally)
* flush output data buffers.
*/
DBAPI DSPStream_Idle(DSP_HSTREAM hStream, bool bFlush)
{
DSP_STATUS status = DSP_SOK;
Trapped_Args tempStruct;
DEBUGMSG(DSPAPI_ZONE_FUNCTION, (TEXT("NODE: DSPStream_Idle:\r\n")));
if (hStream) {
/* Set up the structure */
/* Call DSP Trap */
tempStruct.ARGS_STRM_IDLE.hStream = hStream;
tempStruct.ARGS_STRM_IDLE.bFlush = bFlush;
status = DSPTRAP_Trap(&tempStruct, CMD_STRM_IDLE_OFFSET);
} else {
/* Invalid pointer */
status = DSP_EHANDLE;
DEBUGMSG(DSPAPI_ZONE_ERROR, (TEXT("NODE: DSPStream_Idle: "
"hStrm is Invalid \r\n")));
}
return status;
}
/*
* ======== DSPStream_Issue ========
* Purpose:
* Send a buffer of data to a stream.
*/
DBAPI DSPStream_Issue(DSP_HSTREAM hStream, IN BYTE *pBuffer,
ULONG dwDataSize, ULONG dwBufSize, IN DWORD dwArg)
{
DSP_STATUS status = DSP_SOK;
Trapped_Args tempStruct;
DEBUGMSG(DSPAPI_ZONE_FUNCTION, (TEXT("NODE: DSPStream_Issue:\r\n")));
if (hStream) {
/* Check the size of the buffer */
if (pBuffer) {
/* Check that the size isn't too small */
if (dwDataSize > dwBufSize) {
status = DSP_EINVALIDARG;
DEBUGMSG(DSPAPI_ZONE_ERROR,
(TEXT("NODE: DSPStream_Issue: "
"Invalid argument in the Input\r\n")));
} else {
/* Set up the structure */
tempStruct.ARGS_STRM_ISSUE.hStream = hStream;
tempStruct.ARGS_STRM_ISSUE.pBuffer = pBuffer;
tempStruct.ARGS_STRM_ISSUE.dwBytes = dwDataSize;
tempStruct.ARGS_STRM_ISSUE.dwBufSize =
dwBufSize;
tempStruct.ARGS_STRM_ISSUE.dwArg = dwArg;
/* Call DSP Trap */
status = DSPTRAP_Trap(&tempStruct,
CMD_STRM_ISSUE_OFFSET);
/* Return DSP_SOK if OS calls returned 0 */
if (status == 0)
status = DSP_SOK;
}
} else {
/* Invalid parameter */
status = DSP_EPOINTER;
DEBUGMSG(DSPAPI_ZONE_ERROR,
(TEXT("NODE: DSPStream_Issue: "
"Invalid pointer in the Input\r\n")));
}
} else {
/* Invalid pointer */
status = DSP_EHANDLE;
DEBUGMSG(DSPAPI_ZONE_ERROR, (TEXT("NODE: DSPStream_Issue: "
"hStrm is Invalid \r\n")));
}
return status;
}
/*
* ======== DSPStream_Open ========
* Purpose:
* Retrieve a stream handle for sending/receiving data buffers
* to/from a task node on a DSP.
*/
DBAPI DSPStream_Open(DSP_HNODE hNode, UINT uDirection, UINT uIndex,
IN OPTIONAL struct DSP_STREAMATTRIN *pAttrIn,
OUT DSP_HSTREAM *phStream)
{
DSP_STATUS status = DSP_SOK;
Trapped_Args tempStruct;
struct STRM_ATTR strmAttrs;
#ifndef LINUX /* Events are handled in kernel */
CHAR szEventName[STRM_MAXEVTNAMELEN];
WCHAR wszEventName[STRM_MAXEVTNAMELEN];
CHAR szTemp[STRM_MAXEVTNAMELEN];
#endif
struct CMM_OBJECT *hCmm = NULL; /* SM Mgr handle */
struct CMM_INFO pInfo;/* CMM info; use for virtual space allocation */
DEBUGMSG(DSPAPI_ZONE_FUNCTION, (TEXT("NODE: DSPStream_Open:\r\n")));
if (!hNode) {
status = DSP_EHANDLE;
DEBUGMSG(DSPAPI_ZONE_ERROR, (TEXT("NODE: DSPStream_Open: "
"Invalid handle in the Input\r\n")));
return status;
}
if (uDirection != DSP_TONODE && uDirection != DSP_FROMNODE) {
status = DSP_EDIRECTION;
DEBUGMSG(DSPAPI_ZONE_ERROR, (TEXT("NODE: DSPStream_Open: "
"Invalid direction in the Input\r\n")));
return status;
}
if (!phStream) {
status = DSP_EPOINTER;
DEBUGMSG(DSPAPI_ZONE_ERROR,
(TEXT("NODE: DSPStream_Open: "
"Invalid pointer in the Input\r\n")));
return status;
}
*phStream = NULL;
strmAttrs.hUserEvent = NULL;
#ifndef LINUX /* Events are handled in kernel */
/* Create a 'named' user event that is unique.*/
strmAttrs.pStreamAttrIn = pAttrIn;
szEventName[0] = 'E';
szEventName[1] = 'V';
szEventName[2] = '\0';
/* append hNode handle string */
strncat(szEventName, _ultoa((ULONG)hNode, szTemp, 16), 8);
/* now append stream index and direction */
strncat(szEventName, _ultoa((ULONG)uDirection, szTemp, 16), 2);
strmAttrs.pstrEventName =
strncat(szEventName, _ultoa((ULONG)uIndex, szTemp, 16), 3);
(Void)CSL_AnsiToWchar(wszEventName, szEventName, STRM_MAXEVTNAMELEN);
/* Create an auto reset event. */
strmAttrs.hUserEvent = CreateEvent(NULL,false,false,wszEventName);
if (!strmAttrs.hUserEvent) {
status = DSP_EFAIL;
DEBUGMSG(DSPAPI_ZONE_ERROR, (TEXT("NODE: DSPStream_Open: "
"Failed to Create the Event \r\n")));
}
#endif
/* Default stream mode is PROCCOPY.
* Check for currently supported mode(s).*/
if (pAttrIn) {
if (pAttrIn->lMode == STRMMODE_LDMA) {
/* No System-DMA support */
status = DSP_ENOTIMPL;
} else
if ((pAttrIn->lMode != STRMMODE_PROCCOPY)
&& (pAttrIn->lMode != STRMMODE_ZEROCOPY)
&& (pAttrIn->lMode != STRMMODE_RDMA)) {
status = DSP_ESTRMMODE; /* illegal stream mode */
}
pAttrIn->uSegment = abs(pAttrIn->uSegment);
/* make non-neg */
}
/* If opening the stream for STRMMODE_ZEROCOPY or
* STRMMODE_RDMA(DSP-DMA) stream mode, then setup the
* stream's CMM translator for the specified SM segment.*/
strmAttrs.pVirtBase = NULL;
strmAttrs.ulVirtSize = 0;
if (DSP_SUCCEEDED(status) && pAttrIn) {
if ((pAttrIn->lMode == STRMMODE_ZEROCOPY) ||
(pAttrIn->lMode == STRMMODE_RDMA)) {
if (pAttrIn->uSegment == 0) {
status = DSP_ENOTSHAREDMEM; /* must be
SM segment */
goto loop_end;
}
/* >0 is SM segment. Get default SM Mgr */
tempStruct.ARGS_CMM_GETHANDLE.hProcessor = NULL;
tempStruct.ARGS_CMM_GETHANDLE.phCmmMgr = &hCmm;
status = DSPTRAP_Trap(&tempStruct,
CMD_CMM_GETHANDLE_OFFSET);
if (status == DSP_SOK) {
/* Get SM segment info from CMM */
tempStruct.ARGS_CMM_GETINFO.hCmmMgr = hCmm;
tempStruct.ARGS_CMM_GETINFO.pCmmInfo = &pInfo;
status = DSPTRAP_Trap(&tempStruct,
CMD_CMM_GETINFO_OFFSET);
if (status != DSP_SOK)
status = DSP_EFAIL;
} else
status = DSP_EFAIL;
if (!DSP_SUCCEEDED(status ||
!(pInfo.ulNumGPPSMSegs >= pAttrIn->uSegment))) {
status = DSP_EBADSEGID; /* no SM segments */
goto loop_end;
}
/* segInfo index starts at 0 */
if ((pInfo.segInfo[pAttrIn->uSegment-1].dwSegBasePa
== 0) || (pInfo.segInfo[pAttrIn->uSegment-1]\
.ulTotalSegSize) < 0) {
status = DSP_EFAIL;
DEBUGMSG(DSPAPI_ZONE_ERROR,
(TEXT("STRM:DSPStream_Open: "
"Bad SM info...why?\r\n")));
goto loop_end;
}
strmAttrs.pVirtBase = mmap(NULL,
pInfo.segInfo[pAttrIn->uSegment-1]\
.ulTotalSegSize, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_LOCKED, hMediaFile, pInfo\
.segInfo[pAttrIn->uSegment-1].dwSegBasePa);
if (strmAttrs.pVirtBase == NULL) {
status = DSP_EFAIL;
DEBUGMSG(DSPAPI_ZONE_ERROR,
(TEXT("STRM: DSPStream_Open: "
"Virt alloc failed\r\n")));
goto loop_end;
}
strmAttrs.ulVirtSize =
pInfo.segInfo[pAttrIn->uSegment-1].ulTotalSegSize;
}
}
loop_end:
if (DSP_SUCCEEDED(status)) {
/* Set up the structure */
strmAttrs.pStreamAttrIn = pAttrIn;
/* Call DSP Trap */
tempStruct.ARGS_STRM_OPEN.hNode = hNode;
tempStruct.ARGS_STRM_OPEN.uDirection = uDirection;
tempStruct.ARGS_STRM_OPEN.uIndex = uIndex;
tempStruct.ARGS_STRM_OPEN.pAttrIn = &strmAttrs;
tempStruct.ARGS_STRM_OPEN.phStream = phStream;
status = DSPTRAP_Trap(&tempStruct, CMD_STRM_OPEN_OFFSET);
#ifndef LINUX /* Events are handled in kernel */
if (DSP_FAILED(status))
CloseHandle(strmAttrs.hUserEvent);
#endif
}
return status;
}
/*
* ======== DSPStream_PrepareBuffer ========
* Purpose:
* Prepares a buffer.
*/
DBAPI DSPStream_PrepareBuffer(DSP_HSTREAM hStream, UINT uSize, BYTE *pBuffer)
{
DSP_STATUS status = DSP_SOK;
#ifndef LINUX
/* Pages are never swapped out (i.e. always locked in Linux) */
ULONG aPageTab[STRM_MAXLOCKPAGES];
/* Find the maximum # of pages that could be locked. x86 &
ARM=4Kb pages */
UINT cPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(NULL, uSize);
#endif
/* Do error checking here to API spec. We don't call down to WCD */
if (!hStream)
status = DSP_EHANDLE;
if (DSP_SUCCEEDED(status)) {
if (!pBuffer)
status = DSP_EPOINTER;
}
if (DSP_SUCCEEDED(status)) {
if (uSize <= 0)
status = DSP_ESIZE;
}
#ifndef LINUX
/* Pages are never swapped out (i.e. always locked in Linux) */
if (DSP_SUCCEEDED(status)) {
if (cPages > STRM_MAXLOCKPAGES)
status = DSP_EFAIL;
else {
if (!LockPages((LPVOID)pBuffer, uSize, aPageTab,
LOCKFLAG_WRITE))
status = DSP_EFAIL;
}
}
#endif
return status;
}
/*
* ======== DSPStream_Reclaim ========
* Purpose:
* Request a buffer back from a stream.
*/
DBAPI DSPStream_Reclaim(DSP_HSTREAM hStream, OUT BYTE **pBufPtr,
OUT ULONG *pDataSize, OUT ULONG *pBufSize, OUT DWORD *pdwArg)
{
DSP_STATUS status = DSP_SOK;
Trapped_Args tempStruct;
DEBUGMSG(DSPAPI_ZONE_FUNCTION, (TEXT("NODE: DSPStream_Reclaim:\r\n")));
if (hStream) {
/* Check the size of the buffer */
if ((pBufPtr) && (pDataSize) && (pdwArg)) {
/* Set up the structure */
/* Call DSP Trap */
tempStruct.ARGS_STRM_RECLAIM.hStream = hStream;
tempStruct.ARGS_STRM_RECLAIM.pBufPtr = pBufPtr;
tempStruct.ARGS_STRM_RECLAIM.pBytes = pDataSize;
tempStruct.ARGS_STRM_RECLAIM.pBufSize = pBufSize;
tempStruct.ARGS_STRM_RECLAIM.pdwArg = pdwArg;
status = DSPTRAP_Trap(&tempStruct,
CMD_STRM_RECLAIM_OFFSET);
} else {
/* Invalid parameter */
status = DSP_EPOINTER;
DEBUGMSG(DSPAPI_ZONE_ERROR,
(TEXT("NODE: DSPStream_Reclaim: "
"Invalid pointer in the Input\r\n")));
}
} else {
/* Invalid pointer */
status = DSP_EHANDLE;
DEBUGMSG(DSPAPI_ZONE_ERROR, (TEXT("NODE: DSPStream_Reclaim: "
"hStrm is Invalid \r\n")));
}
return status;
}
/*
* ======== DSPStream_RegisterNotify ========
* Purpose:
* Register to be notified of specific events for this stream.
*/
DBAPI
DSPStream_RegisterNotify(DSP_HSTREAM hStream, UINT uEventMask,
UINT uNotifyType, struct DSP_NOTIFICATION *hNotification)
{
DSP_STATUS status = DSP_SOK;
Trapped_Args tempStruct;
DEBUGMSG(DSPAPI_ZONE_FUNCTION,
(TEXT("NODE: DSPStream_RegisterNotify:\r\n")));
if ((hStream) && (hNotification)) {
if (IsValidStrmEvent(uEventMask)) {
if (IsValidNotifyMask(uNotifyType)) {
/* Set up the structure */
/* Call DSP Trap */
tempStruct.ARGS_STRM_REGISTERNOTIFY.hStream =
hStream;
tempStruct.ARGS_STRM_REGISTERNOTIFY.uEventMask =
uEventMask;
tempStruct.ARGS_STRM_REGISTERNOTIFY\
.uNotifyType = uNotifyType;
tempStruct.ARGS_STRM_REGISTERNOTIFY\
.hNotification = hNotification;
status = DSPTRAP_Trap(&tempStruct,
CMD_STRM_REGISTERNOTIFY_OFFSET);
} else {
status = DSP_ENOTIMPL;
DEBUGMSG(DSPAPI_ZONE_ERROR,
(TEXT("NODE: DSPStream_RegisterNotify: "
"Invalid Notify Mask \r\n")));
}
} else {
status = DSP_EVALUE;
DEBUGMSG(DSPAPI_ZONE_ERROR,
(TEXT("NODE: DSPStream_RegisterNotify: "
"Invalid Event Mask \r\n")));
}
} else {
/* Invalid handle */
status = DSP_EHANDLE;
DEBUGMSG(DSPAPI_ZONE_ERROR,
(TEXT("NODE: DSPStream_RegisterNotify: "
"Invalid Handle \r\n")));
}
return status;
}
/*
* ======== DSPStream_Select ========
* Purpose:
* Select a ready stream.
*/
DBAPI DSPStream_Select(IN DSP_HSTREAM *aStreamTab,
UINT nStreams, OUT UINT *pMask, UINT uTimeout)
{
DSP_STATUS status = DSP_SOK;
Trapped_Args tempStruct;
DEBUGMSG(DSPAPI_ZONE_FUNCTION, (TEXT("NODE: DSPStream_Select:\r\n")));
if ((aStreamTab) && (pMask)) {
if (nStreams) {
/* Set up the structure */
/* Call DSP Trap */
tempStruct.ARGS_STRM_SELECT.aStreamTab = aStreamTab;
tempStruct.ARGS_STRM_SELECT.nStreams = nStreams;
tempStruct.ARGS_STRM_SELECT.pMask = pMask;
tempStruct.ARGS_STRM_SELECT.uTimeout = uTimeout;
status = DSPTRAP_Trap(&tempStruct,
CMD_STRM_SELECT_OFFSET);
} else
/* nStreams == 0 */
*pMask = 0;
} else {
/* Invalid pointer */
status = DSP_EPOINTER;
DEBUGMSG(DSPAPI_ZONE_ERROR,
(TEXT("NODE: DSPStream_Select: hStrm is Invalid \r\n")));
}
return status;
}
/*
* ======== DSPStream_UnprepareBuffer ========
* Purpose:
* Unprepares a buffer.
*/
DBAPI DSPStream_UnprepareBuffer(DSP_HSTREAM hStream, UINT uSize,
BYTE *pBuffer)
{
DSP_STATUS status = DSP_SOK;
/* Do error checking here to API spec. We don't call down to WCD */
if (!hStream)
status = DSP_EHANDLE;
if (DSP_SUCCEEDED(status)) {
if (!pBuffer)
status = DSP_EPOINTER;
}
if (DSP_SUCCEEDED(status)) {
/*|| ((LPVOID)pBuffer == NULL) - already checked above */
if ((uSize <= 0))
status = DSP_EFAIL;
}
#ifndef LINUX /* Pages are never swapped out
(i.e. always locked in Linux) */
if (DSP_SUCCEEDED(status)) {
if (!UnlockPages((LPVOID) pBuffer, uSize))
status = DSP_EFAIL;
}
#endif
return status;
}
/*
* ======== GetStrmInfo ========
*/
static DSP_STATUS GetStrmInfo(DSP_HSTREAM hStream, struct STRM_INFO *pStrmInfo,
UINT uStreamInfoSize)
{
DSP_STATUS status = DSP_SOK;
Trapped_Args tempStruct;
if (hStream) {
/* Check the size of the buffer */
if (pStrmInfo && pStrmInfo->pUser) {
if (uStreamInfoSize >= sizeof(struct DSP_STREAMINFO)) {
/* user info */
/* Set up the structure */
/* Call DSP Trap */
tempStruct.ARGS_STRM_GETINFO.hStream = hStream;
tempStruct.ARGS_STRM_GETINFO.pStreamInfo =
pStrmInfo;
/* user returned struct DSP_STREAMINFO
info size */
tempStruct.ARGS_STRM_GETINFO.uStreamInfoSize =
uStreamInfoSize;
status = DSPTRAP_Trap(&tempStruct,
CMD_STRM_GETINFO_OFFSET);
} else {
status = DSP_ESIZE;
DEBUGMSG(DSPAPI_ZONE_ERROR,
(TEXT("NODE: DSPStream_GetInfo: "
"uStreamInfo size is less than the "
"size of struct DSP_STREAMINFO\r\n")));
}
} else {
/* Invalid parameter */
status = DSP_EPOINTER;
DEBUGMSG(DSPAPI_ZONE_ERROR,
(TEXT("NODE: DSPStream_GetInfo: "
"Invalid pointer\r\n")));
}
} else {
/* Invalid pointer */
status = DSP_EHANDLE;
DEBUGMSG(DSPAPI_ZONE_ERROR, (TEXT(
"NODE: DSPStream_GetInfo: hStrm is Invalid \r\n")));
}
return status;
}