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  */
DSPStream_AllocateBuffers(DSP_HSTREAM hStream,UINT uSize,OUT BYTE ** apBuffer,UINT uNumBufs)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  */
DSPStream_Close(DSP_HSTREAM hStream)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  */
DSPStream_FreeBuffers(DSP_HSTREAM hStream,IN BYTE ** apBuffer,UINT uNumBufs)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  */
DSPStream_GetInfo(DSP_HSTREAM hStream,OUT struct DSP_STREAMINFO * pStreamInfo,UINT uStreamInfoSize)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  */
DSPStream_Idle(DSP_HSTREAM hStream,bool bFlush)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  */
DSPStream_Issue(DSP_HSTREAM hStream,IN BYTE * pBuffer,ULONG dwDataSize,ULONG dwBufSize,IN DWORD dwArg)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  */
DSPStream_Open(DSP_HNODE hNode,UINT uDirection,UINT uIndex,IN OPTIONAL struct DSP_STREAMATTRIN * pAttrIn,OUT DSP_HSTREAM * phStream)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  */
DSPStream_PrepareBuffer(DSP_HSTREAM hStream,UINT uSize,BYTE * pBuffer)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  */
DSPStream_Reclaim(DSP_HSTREAM hStream,OUT BYTE ** pBufPtr,OUT ULONG * pDataSize,OUT ULONG * pBufSize,OUT DWORD * pdwArg)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
DSPStream_RegisterNotify(DSP_HSTREAM hStream,UINT uEventMask,UINT uNotifyType,struct DSP_NOTIFICATION * hNotification)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  */
DSPStream_Select(IN DSP_HSTREAM * aStreamTab,UINT nStreams,OUT UINT * pMask,UINT uTimeout)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  */
DSPStream_UnprepareBuffer(DSP_HSTREAM hStream,UINT uSize,BYTE * pBuffer)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  */
GetStrmInfo(DSP_HSTREAM hStream,struct STRM_INFO * pStrmInfo,UINT uStreamInfoSize)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