source: svn/newcon3bcm2_21bu/magnum/syslib/pvrlib/bpvrlib_dynrec.c

Last change on this file was 76, checked in by megakiss, 10 years ago

1W 대기전력을 만족시키기 위하여 POWEROFF시 튜너를 Standby 상태로 함

  • Property svn:executable set to *
File size: 31.2 KB
Line 
1/***************************************************************************
2 *      Copyright (c) 2003-2005, Broadcom Corporation
3 *      All Rights Reserved
4 *      Confidential Property of Broadcom Corporation
5 *
6 *  THIS SOFTWARE MAY ONLY BE USED SUBJECT TO AN EXECUTED SOFTWARE LICENSE
7 *  AGREEMENT   BETWEEN THE USER AND BROADCOM.  YOU HAVE NO RIGHT TO USE OR
8 *  EXPLOIT THIS MATERIAL EXCEPT SUBJECT TO THE TERMS OF SUCH AN AGREEMENT.
9 *
10 * This file was based upon: /vobs/magnum/syslib/pvrlib/bpvrlib_rec.c@@Hydra_Software_Devel/9
11 *
12 * $brcm_Workfile: bpvrlib_dynrec.c $
13 * $brcm_Revision: Hydra_Software_Devel/7 $
14 * $brcm_Date: 8/17/05 10:48a $
15 *
16 * Revision History:
17 *
18 * $brcm_Log: /magnum/syslib/pvrlib/bpvrlib_dynrec.c $
19 *
20 * Hydra_Software_Devel/7   8/17/05 10:48a marcusk
21 * PR16713: Fixed memory leak.
22 *
23 * Hydra_Software_Devel/6   4/10/04 3:02p marcusk
24 * PR10559: When overflow happens process all data from record channel
25 * before starting again
26 *
27 * Hydra_Software_Devel/5   3/12/04 3:25p vsilyaev
28 * PR 8927: Added API to return events to the application.
29 *
30 * Hydra_Software_Devel/4   3/1/04 3:47p marcusk
31 * PR9930: Fixed warnings for VxWorks build.
32 *
33 * Hydra_Software_Devel/3   1/21/04 4:43p marcusk
34 * PR8927: Fixed to work with latest version of XPT porting interface.
35 * Validate channel number.
36 *
37 * Hydra_Software_Devel/2   1/15/04 4:40p marcusk
38 * PR8927: Initial working version of the dynamic buffer record syslib.
39 *
40 * Hydra_Software_Devel/1   1/15/04 11:23a marcusk
41 * PR8927: Initial version.
42 *
43 *************************************************************/
44#include "bstd.h"
45#include "blst_squeue.h"
46#include "bkni.h"
47#include "bpvrlib_dynrec.h"
48#include "bmem.h"
49
50#include "bint.h"
51#include "bchp_int_id_xpt_int.h"
52
53BDBG_MODULE(BPVRlib_Rec);
54
55#define BPVRLIB_REC_P_ADD_TO_FREE_LIST_ISR(recHandle, p_descEntry) \
56        do{ \
57                BLST_SQ_INSERT_TAIL(&((recHandle)->recMasterHandle->freeDescList), p_descEntry, link); \
58                (recHandle)->recMasterHandle->numFreeDesc++; \
59        }while(0)
60
61#define BPVRLIB_REC_P_ADD_TO_FREE_LIST( recHandle, p_descEntry ) \
62        do{ \
63                BKNI_EnterCriticalSection(); \
64                BPVRLIB_REC_P_ADD_TO_FREE_LIST_ISR(recHandle, p_descEntry); \
65                BKNI_LeaveCriticalSection(); \
66        }while(0)
67
68#define BPVRLIB_REC_P_REMOVE_FROM_FREE_LIST_ISR( recHandle, p_descEntry ) \
69                do{ \
70                        p_descEntry = BLST_SQ_FIRST(&((recHandle)->recMasterHandle->freeDescList)); \
71                        BLST_SQ_REMOVE_HEAD( &((recHandle)->recMasterHandle->freeDescList), link ); \
72                        recHandle->recMasterHandle->numFreeDesc--; \
73                }while(0)
74
75#define BPVRLIB_REC_P_REMOVE_FROM_FREE_LIST( recHandle, p_descEntry ) \
76        do{ \
77                BKNI_EnterCriticalSection(); \
78                BPVRLIB_REC_P_REMOVE_FROM_FREE_LIST_ISR(recHandle, p_descEntry); \
79                BKNI_LeaveCriticalSection(); \
80        }while(0)
81
82#define BPVRLIB_REC_P_ADD_TO_HARDWARE_ISR( err, recHandle, p_descEntry ) \
83                do { \
84                        BXPT_SetLastDescriptorFlag(p_descEntry->p_desc); \
85                        BLST_SQ_INSERT_TAIL( &recHandle->hwDescList, p_descEntry, link ); \
86                        recHandle->stats.numInHwDesc++; \
87                        BDBG_MSG(("Adding %s descriptor",(recHandle->recMasterHandle->chanType==BXPT_ChanType_eRecord)?"Rec":"Scd")); \
88                        err = BXPT_Record_AddDescriptors(recHandle->xptRecHandle, recHandle->recMasterHandle->chanType, p_descEntry->p_desc, p_descEntry->p_desc); \
89                }while(0)
90
91#define BPVRLIB_REC_P_ADD_TO_HARDWARE( err, recHandle, p_descEntry ) \
92        do { \
93                BKNI_EnterCriticalSection(); \
94                BPVRLIB_REC_P_ADD_TO_HARDWARE_ISR( err, recHandle, p_descEntry ); \
95                BKNI_LeaveCriticalSection(); \
96        }while(0)
97
98typedef struct BPVRlib_Rec_P_DescEntry
99{
100        BLST_SQ_ENTRY(BPVRlib_Rec_P_DescEntry) link;
101        BXPT_PvrDescriptor *p_desc;
102} BPVRlib_Rec_P_DescEntry;
103
104typedef BLST_SQ_HEAD(BPVRlib_Rec_P_DescList, BPVRlib_Rec_P_DescEntry) BPVRlib_Rec_P_DescList;
105
106typedef struct BPVRlib_Rec_P_MasterHandle
107{
108        unsigned                                        usageCount;                     /* Number of channels currently allocated */
109        uint8_t                                         *p_bfr;                         /* Pointer to ring buffer */
110        bool                                            bfrAllocated;           /* false (buffer pointer passed in), true (buffer allocated internally) */
111        size_t                                          bfrSize;                        /* Size of ring buffer */
112        uint8_t                                         *p_descBfr;             /* Buffer used for descriptor allocation */
113        BPVRlib_Rec_P_DescEntry         *p_descEntries;         /* Buffer used to store descriptor list entries */
114        BPVRlib_Rec_P_DescList          freeDescList;           /* List containing all free descriptors */
115        uint32_t                                        numDesc;                        /* Num of descriptors used for Record */
116        uint32_t                                        numFreeDesc;            /* Num of free descriptors available */
117        BPVRlib_Rec_CopyMemoryCb        copyMemCb;                      /* Callback used to copy data into the ring buffer */
118        BXPT_ChanType                           chanType;                       /* Channel type */
119        BMEM_Handle                             memHandle;                      /* Mem handle */
120        BXPT_Handle                             xptHandle;                      /* XPT handle */
121        BINT_Handle                                     intHandle;                      /* BINT handle */
122} BPVRlib_Rec_P_MasterHandle;
123
124typedef struct BPVRlib_Rec_P_Handle
125{
126        BPVRlib_Rec_MasterHandle        recMasterHandle;        /* Pointer to the master handle */
127        BXPT_Record_Handle              xptRecHandle;           /* XPT Record Handle */
128        unsigned                                        chanNum;                        /* Channel number */
129        bool                                            isInProgress;           /* Record is in progress */
130        bool                                            allRecordDataFound;     /* Set when last bits of record data is added to ring buffer */
131        BKNI_EventHandle                        doneEvent;                      /* Event used to signal when the record is done */
132        BKNI_EventHandle                        descEvent;                      /* Event used to signal when a descriptor is done */
133        BPVRlib_Rec_P_DescList          hwDescList;                     /* List containing descriptors that are loading in hardware */
134        BPVRlib_Rec_P_DescList          compDescList;           /* List containing descriptors that are loading in hardware */
135        uint32_t                                        curCompDescOffset;      /* Byte offset that has been read from our current completed descriptor */
136        uint32_t                                        numBytesRead;           /* Number of bytes that have been read, but not re-added into hardware */
137        uint32_t                                        timeoutValue;           /* Max number of msec to wait for an event to occur */
138        BPVRlib_Rec_Stats                       stats;                          /* Statistics */
139        BINT_CallbackHandle             hRecInt;                        /* cb Handle for rec interrupt */
140        BINT_CallbackHandle             hDoneInt;                       /* cb Handle for done interrupt */
141        uint32_t                                        minDesc;                        /* Minimum number of descriptors to use with this channel */
142} BPVRlib_Rec_P_Handle;
143
144static void BPVRlib_Rec_P_Record_isr( void * pParm1, int parm2 );
145static BERR_Code BPVRlib_Rec_P_CreateIntCallbacks( BPVRlib_Rec_Handle recHandle );
146static BERR_Code BPVRlib_Rec_P_EnableInterrupts( BPVRlib_Rec_Handle recHandle );
147static BERR_Code BPVRlib_Rec_P_DisableInterrupts( BPVRlib_Rec_Handle recHandle );
148static BERR_Code BPVRlib_Rec_P_GetDescSize( BPVRlib_Rec_Handle recHandle, BXPT_PvrDescriptor *p_desc, size_t *p_descSize );
149
150BERR_Code BPVRlib_Rec_Open(
151        BPVRlib_Rec_MasterHandle *pRecMasterHandle,     /* [out] context handle */
152        BXPT_Handle xptHandle,                          /* XPT handle */
153        BMEM_Handle memHandle,                          /* Mem handle */
154        BINT_Handle intHandle,                          /* Int handle */
155        BXPT_ChanType chanType,                         /* Record channel type */
156        uint8_t *p_bfr,                                         /* pointer to buffer that should be used for record buffer, 0 to allocate the buffer internally */
157        size_t bfrSize,                                         /* size of record record buffer (in bytes) */
158        uint32_t numDesc,                                       /* number of descriptors to use (minimum of 2 per record channel to be used) */
159        BPVRlib_Rec_CopyMemoryCb copyMemCb      /* function pointer for memory copies (optional) */
160        )
161{
162        BERR_Code               err = BERR_SUCCESS;
163        uint32_t                i;
164        BXPT_PvrDescriptor      *p_desc;
165        BPVRlib_Rec_MasterHandle recHandle;
166        size_t descSize = bfrSize / numDesc;
167        size_t bfrOffset;
168
169        if( ((bfrSize / numDesc) % 4) || bfrSize == 0 )
170        {
171                err = BERR_TRACE(BERR_INVALID_PARAMETER) ;
172                BDBG_ERR(("pvr_recordAllocate(): (buffer size / number of descriptors) must be multiple of 32 bits!"));
173                goto done;
174        }
175
176        recHandle = BKNI_Malloc( sizeof(BPVRlib_Rec_P_MasterHandle) );
177        if( recHandle == NULL )
178        {
179                err = BERR_TRACE(BERR_OUT_OF_SYSTEM_MEMORY);
180                goto done;
181        }
182
183        BKNI_Memset( recHandle, 0, sizeof(BPVRlib_Rec_P_MasterHandle) );
184
185        if( p_bfr == NULL )
186        {
187                p_bfr = BMEM_Alloc( memHandle, bfrSize );
188                if( p_bfr == NULL )
189                {
190                        err = BERR_TRACE(BERR_OUT_OF_DEVICE_MEMORY);
191                        goto error;
192                }
193                recHandle->bfrAllocated = true;
194        }
195
196        /* Save parameters */
197        recHandle->p_bfr                = p_bfr;
198        recHandle->bfrSize              = bfrSize;
199        recHandle->numDesc              = numDesc;
200        recHandle->copyMemCb    = copyMemCb;
201        recHandle->xptHandle    = xptHandle;
202        recHandle->memHandle    = memHandle;
203        recHandle->chanType             = chanType;
204        recHandle->xptHandle    = xptHandle;
205        recHandle->intHandle    = intHandle;
206
207        /* Init our lists */
208        BLST_SQ_INIT( &recHandle->freeDescList );
209
210        /* Descriptors must be 16 byte aligned so allocate an extra 15 bytes */
211        recHandle->p_descBfr = BMEM_AllocAligned( recHandle->memHandle, (sizeof(BXPT_PvrDescriptor)*numDesc), 4 /* 16 byte aligned */, 0 );
212        p_desc = (BXPT_PvrDescriptor *)recHandle->p_descBfr;
213        if( p_desc == NULL )
214        {
215                err = BERR_TRACE(BERR_OUT_OF_DEVICE_MEMORY);
216                goto error;             
217        }
218
219        /* Allocate storage for our descriptor entries */
220        recHandle->p_descEntries = BKNI_Malloc( sizeof(BPVRlib_Rec_P_DescEntry) * numDesc );
221        if( recHandle->p_descEntries == NULL )
222        {
223                err = BERR_TRACE(BERR_OUT_OF_SYSTEM_MEMORY);
224                goto error;             
225        }
226
227        bfrOffset = 0;
228        /* Assign a descriptor to each descriptor list entry and add them to the free list */
229        for( i = 0; i < numDesc; i++ )
230        {
231                BDBG_ASSERT( bfrOffset + descSize <= bfrSize );
232                recHandle->p_descEntries[i].p_desc = &p_desc[i];
233
234                err = BXPT_Record_CreateDesc(recHandle->xptHandle, recHandle->p_descEntries[i].p_desc, p_bfr+bfrOffset, descSize, true, NULL);
235                if( err != BERR_SUCCESS )
236                {
237                        goto error;
238                }
239                BDBG_WRN(("Created descriptor, %08X, %ld", recHandle->p_descEntries[i].p_desc->BufferStartAddr, recHandle->p_descEntries[i].p_desc->BufferLength));
240
241                BLST_SQ_INSERT_TAIL(&recHandle->freeDescList, &recHandle->p_descEntries[i], link);
242                recHandle->numFreeDesc++;
243                bfrOffset += descSize;
244        }
245       
246done:
247        *pRecMasterHandle = recHandle;
248        return err;
249
250error:
251        BPVRlib_Rec_Close( recHandle );
252        return err;
253}
254
255BERR_Code BPVRlib_Rec_Close( 
256                                BPVRlib_Rec_MasterHandle recHandle              /* context handle */
257                                )
258{
259        if( recHandle->usageCount )
260        {
261                return BERR_TRACE(BERR_UNKNOWN);
262        }
263
264        if( recHandle->p_descBfr != NULL ) BMEM_Free( recHandle->memHandle, recHandle->p_descBfr );
265        if( recHandle->bfrAllocated == true ) BMEM_Free( recHandle->memHandle, recHandle->p_bfr );
266        if( recHandle->p_descEntries != NULL ) BKNI_Free( recHandle->p_descEntries );
267
268        BKNI_Free(recHandle);
269
270        return BERR_SUCCESS;
271}
272
273BERR_Code BPVRlib_Rec_ChannelOpen(
274        BPVRlib_Rec_Handle *pRecChanHandle,     /* [out] context handle */
275        BPVRlib_Rec_MasterHandle recMasterHandle, /* master handle context */
276        BXPT_Record_Handle xptRecHandle,        /* XPT record handle */
277        unsigned chanNum,                                               /* record channel number */
278        uint32_t minDesc                                        /* minimum number of descriptors that should be always allocated for this record channel (0 is auto) */
279        )
280{
281        BPVRlib_Rec_Handle recHandle;
282        BERR_Code err;
283        BXPT_Capability xptCaps;
284
285        BXPT_GetCapability(recMasterHandle->xptHandle, &xptCaps );
286
287        if( chanNum >= xptCaps.MaxRecords )
288        {
289                err = BERR_TRACE(BERR_INVALID_PARAMETER);
290                goto done;
291        }
292
293        recHandle = BKNI_Malloc( sizeof(BPVRlib_Rec_P_Handle) );
294        if( recHandle == NULL )
295        {
296                err = BERR_TRACE(BERR_OUT_OF_SYSTEM_MEMORY);
297                goto done;
298        }
299
300        BKNI_Memset( recHandle, 0, sizeof(BPVRlib_Rec_P_Handle) );
301
302        recHandle->chanNum = chanNum;
303        recHandle->xptRecHandle = xptRecHandle;
304        recHandle->recMasterHandle = recMasterHandle;
305        recHandle->timeoutValue = -1;
306
307        if( minDesc == 0 )
308        {
309                minDesc = 3;
310        }       
311
312        recHandle->minDesc = minDesc;
313
314        /* Init our lists */
315        BLST_SQ_INIT( &recHandle->compDescList );
316        BLST_SQ_INIT( &recHandle->hwDescList );
317
318        err = BKNI_CreateEvent(&recHandle->doneEvent);
319        if( err != BERR_SUCCESS )
320        {
321                goto done;
322        }
323        err = BKNI_CreateEvent(&recHandle->descEvent);
324        if( err != BERR_SUCCESS )
325        {
326                goto done;
327        }
328        err = BPVRlib_Rec_P_CreateIntCallbacks(recHandle);
329        if( err != BERR_SUCCESS )
330        {
331                goto done;
332        }
333
334        BKNI_EnterCriticalSection();
335        recHandle->recMasterHandle->usageCount++;
336        BKNI_LeaveCriticalSection();
337       
338done:
339        *pRecChanHandle = recHandle;
340        return err;
341
342}
343
344BERR_Code BPVRlib_Rec_ChannelClose(
345        BPVRlib_Rec_Handle recHandle
346        )
347{
348        if( recHandle->isInProgress )
349        {
350                return BERR_TRACE(BERR_UNKNOWN);
351        }
352
353        BKNI_EnterCriticalSection();
354        recHandle->recMasterHandle->usageCount--;
355        BKNI_LeaveCriticalSection();   
356
357        if( recHandle->doneEvent ) BKNI_DestroyEvent(recHandle->doneEvent);
358        if( recHandle->descEvent ) BKNI_DestroyEvent(recHandle->descEvent);
359
360        BKNI_Free(recHandle);
361
362        return BERR_SUCCESS;
363}
364
365BERR_Code
366BPVRlib_Rec_GetEvents(BPVRlib_Rec_Handle recHandle, BPVRlib_Rec_Events *events)
367{
368        events->descEvent = recHandle->descEvent;
369        events->finishedEvent = recHandle->doneEvent;
370        return BERR_SUCCESS;
371}
372
373BERR_Code BPVRlib_Rec_Start( 
374                                BPVRlib_Rec_Handle recHandle            /* context handle */
375                                )
376{
377        BERR_Code               err = BERR_SUCCESS;
378        BPVRlib_Rec_P_DescEntry *p_descEntry;
379
380        if( recHandle->isInProgress )
381        {
382                return BERR_TRACE(BERR_UNKNOWN);
383        }
384
385        recHandle->numBytesRead                         = 0;
386        recHandle->curCompDescOffset            = 0;
387        recHandle->stats.numDescAdded           = 0;
388        recHandle->stats.numDescCompleted       = 0;
389        recHandle->stats.numOverFlows           = 0;
390        recHandle->stats.numBufferBlocks        = 0;
391        recHandle->stats.numTimeouts            = 0;
392        recHandle->stats.maxBfrDepth            = 0;
393        recHandle->stats.bfrDepth                       = 0;
394
395        for( p_descEntry = BLST_SQ_FIRST(&recHandle->compDescList); p_descEntry; p_descEntry = BLST_SQ_FIRST(&recHandle->compDescList) )
396        {
397                BLST_SQ_REMOVE_HEAD(&recHandle->compDescList, link);
398                recHandle->stats.numCompDesc--;
399                BPVRLIB_REC_P_ADD_TO_FREE_LIST( recHandle, p_descEntry );
400        }
401
402        /* Now load our minimum number of descriptors into hardware */
403        while( recHandle->stats.numInHwDesc < recHandle->minDesc )
404        {
405                BPVRLIB_REC_P_REMOVE_FROM_FREE_LIST( recHandle, p_descEntry );
406                if( p_descEntry == NULL )
407                {
408                        BDBG_WRN(("Record started with only %ld descriptors (minimum is supposed to be %ld", recHandle->stats.numInHwDesc, recHandle->minDesc));
409                        break;
410                }
411
412                BDBG_WRN(("Adding descriptor, %08X, %ld", p_descEntry->p_desc->BufferStartAddr, p_descEntry->p_desc->BufferLength));
413       
414                BPVRLIB_REC_P_ADD_TO_HARDWARE( err, recHandle, p_descEntry );
415                if( err != BERR_SUCCESS )
416                {
417                        goto done;
418                }
419        }
420
421        err = BPVRlib_Rec_P_EnableInterrupts( recHandle );
422        if( err != BERR_SUCCESS )
423        {
424                goto done;
425        }
426
427        if( recHandle->recMasterHandle->chanType == BXPT_ChanType_eRecord )
428        {
429                err = BXPT_Record_StartChannel(recHandle->xptRecHandle);
430                if( err != BERR_SUCCESS )
431                {
432                        goto done;
433                }
434        }
435        else
436        {
437                err = BXPT_Record_StartScdChannel(recHandle->xptRecHandle, BXPT_IndexTable_eStartCode4Word);
438                if( err != BERR_SUCCESS )
439                {
440                        goto done;
441                }
442        }
443
444        /*
445        It is okay to set these flags after the record hardware has started for the following reasons:
446        These flags are only touched by non-isr functions (which must be serialed with this function,
447        or when the done interrupt is set by the hardware.  The done interrupt  will never be set
448        until after the record channel is stopped.
449        */
450        recHandle->isInProgress = true;
451        recHandle->allRecordDataFound = false;
452
453done:
454        return err;
455}
456
457BERR_Code BPVRlib_Rec_P_CreateIntCallbacks( BPVRlib_Rec_Handle recHandle )
458{
459        BERR_Code err = BERR_SUCCESS;
460       
461        /* For each record channel we need to enable the record and done interrupts */
462        BINT_Id recInt;
463        BINT_Id doneInt;
464
465        if( recHandle->recMasterHandle->chanType == BXPT_ChanType_eRecord )
466        {
467                switch( recHandle->chanNum )
468                {
469                        case 0:
470                                recInt = BCHP_INT_ID_REC0_INT;
471                                doneInt = BCHP_INT_ID_REC0_DONE;
472                                break;
473                        case 1:
474                                recInt = BCHP_INT_ID_REC1_INT;
475                                doneInt = BCHP_INT_ID_REC1_DONE;
476                                break;
477                        case 2:
478                                recInt = BCHP_INT_ID_REC2_INT;
479                                doneInt = BCHP_INT_ID_REC2_DONE;
480                                break;
481                }
482        }
483        else
484        {
485                switch( recHandle->chanNum )
486                {
487                        case 0:
488                                recInt = BCHP_INT_ID_SCD0_INT;
489                                doneInt = BCHP_INT_ID_SCD0_DONE;
490                                break;
491                        case 1:
492                                recInt = BCHP_INT_ID_SCD1_INT;
493                                doneInt = BCHP_INT_ID_SCD1_DONE;
494                                break;
495                        case 2:
496                                recInt = BCHP_INT_ID_SCD2_INT;
497                                doneInt = BCHP_INT_ID_SCD2_DONE;
498                                break;
499                }
500        }
501
502        err = BINT_CreateCallback(&recHandle->hRecInt, recHandle->recMasterHandle->intHandle, recInt, BPVRlib_Rec_P_Record_isr, recHandle, 0);
503        if( err != BERR_SUCCESS )
504        {
505                goto done;
506        }
507        err = BINT_CreateCallback(&recHandle->hDoneInt, recHandle->recMasterHandle->intHandle, doneInt, BPVRlib_Rec_P_Record_isr, recHandle, 1);
508        if( err != BERR_SUCCESS )
509        {
510                goto done;
511        }
512
513done:
514        return err;
515}
516
517BERR_Code BPVRlib_Rec_P_EnableInterrupts( BPVRlib_Rec_Handle recHandle )
518{
519        BERR_Code err = BERR_SUCCESS;
520       
521        err = BINT_EnableCallback( recHandle->hDoneInt );
522        if( err != BERR_SUCCESS )
523        {
524                goto done;
525        }
526       
527        err = BINT_EnableCallback( recHandle->hRecInt );
528        if( err != BERR_SUCCESS )
529        {
530                goto done;
531        }
532
533done:
534        return err;
535}
536
537BERR_Code BPVRlib_Rec_GetData( 
538                                BPVRlib_Rec_Handle recHandle,   /* context handle */
539                                uint8_t *p_bfr,                         /* [out,sizeof(*p_bfrSize)] pointer to destination buffer */
540                                size_t *p_bfrSize,              /* [in,out] size of destination buffer (in bytes), returns number of bytes actually copied */ 
541                                bool block,                                     /* false (do not block), true (block until data is available) */
542                                bool *p_overflow                        /* [out] returns 1 if record overflow has occurred */
543                                )
544{
545        BERR_Code err = BERR_SUCCESS;
546        uint8_t *p_srcBfr;
547        size_t srcBfrSize;
548
549        *p_overflow = false;
550
551        err = BPVRlib_Rec_GetDataRequest( recHandle, &p_srcBfr, &srcBfrSize, block );
552
553        if( srcBfrSize > *p_bfrSize )
554        {
555                srcBfrSize = *p_bfrSize;
556        }
557
558        /* Make sure to init this variable before returing due to errors */
559        *p_bfrSize = 0;
560
561        if( srcBfrSize == 0 || err != BERR_SUCCESS )
562        {
563                goto done;
564        }
565
566        if( recHandle->recMasterHandle->copyMemCb )
567        {
568                (*recHandle->recMasterHandle->copyMemCb)( p_bfr, p_srcBfr, srcBfrSize );
569        }
570        else
571        {
572                err = BERR_TRACE(BERR_NOT_INITIALIZED);
573                goto done;
574        }
575
576        err = BPVRlib_Rec_UpdateReadPointer( recHandle, srcBfrSize, block, p_overflow );
577        if( err != BERR_SUCCESS )
578        {
579                BDBG_WRN(("BPVRlib_Rec_GetData(): No blocking requirement caused write pointer update to timeout"));
580                goto done;
581        }
582
583        *p_bfrSize = srcBfrSize;
584
585done:
586        return err;
587}
588
589
590BERR_Code BPVRlib_Rec_P_GetDescSize( BPVRlib_Rec_Handle recHandle, BXPT_PvrDescriptor *p_desc, size_t *p_descSize )
591{
592        BERR_Code err = BERR_SUCCESS;
593        uint32_t physHwWriteAddr;
594        uint32_t descSize;
595
596        descSize = p_desc->BufferLength;
597
598        /* If recording has ended we may have a final partial buffer on our complete list */
599        if( !recHandle->isInProgress )
600        {
601                err = BXPT_Record_GetCurrentBufferAddress(recHandle->xptRecHandle, recHandle->recMasterHandle->chanType, &physHwWriteAddr);
602                if( err != BERR_SUCCESS )
603                {
604                        goto done;
605                }
606
607                if( (p_desc->BufferStartAddr < physHwWriteAddr) && 
608                        ((p_desc->BufferStartAddr+p_desc->BufferLength) > physHwWriteAddr) )
609                {
610                        /* Recording is done, so include last bits of data that was recorded by hardware */
611                        descSize = physHwWriteAddr - p_desc->BufferStartAddr;
612                }
613        }
614
615        *p_descSize = descSize - recHandle->curCompDescOffset;
616       
617done:
618        return err;
619}
620
621BERR_Code BPVRlib_Rec_GetDataRequest( 
622                                BPVRlib_Rec_Handle recHandle,   /* context handle */
623                                uint8_t **pp_bfr,                               /* [out] returns pointer to the start of valid data */
624                                size_t *p_bfrSize,                      /* [out] returns size of the valid data (in bytes) */ 
625                                bool block                                              /* 0 (do not block), 1 (block until data is available) */
626                                )
627{
628        BERR_Code err = BERR_SUCCESS;
629        BPVRlib_Rec_P_DescEntry *p_descEntry;
630
631        *pp_bfr = NULL;
632        *p_bfrSize = 0;
633
634        if( !recHandle->isInProgress )
635        {
636                /* Do not allow blocking when the record is not actively in progress */
637                block = 0;
638        }
639
640        while( 1 )
641        {               
642                BKNI_EnterCriticalSection();
643                p_descEntry = BLST_SQ_FIRST(&recHandle->compDescList);
644                BKNI_LeaveCriticalSection();
645
646                if( p_descEntry )
647                {
648                        err = BMEM_ConvertOffsetToAddress( recHandle->recMasterHandle->memHandle,
649                                p_descEntry->p_desc->BufferStartAddr+recHandle->curCompDescOffset, 
650                                (void **)pp_bfr );
651                        if( err != BERR_SUCCESS )
652                        {
653                                break;
654                        }
655                        err = BPVRlib_Rec_P_GetDescSize( recHandle, p_descEntry->p_desc, p_bfrSize );
656                        break;
657                }
658                else if( !recHandle->isInProgress )
659                {
660                        /* Don't wait for more data, as no more will ever come in! */
661                        BDBG_MSG(("All data complete"));
662                        break;
663                }
664                else if( block )
665                {
666                        recHandle->stats.numBufferBlocks++;
667                        BDBG_MSG(("Waiting for %s desc event: Line: %ld, free: %d, hwd: %d, comp: %d", (recHandle->recMasterHandle->chanType==BXPT_ChanType_eRecord)?"Rec":"Scd", __LINE__, recHandle->recMasterHandle->numFreeDesc, recHandle->stats.numInHwDesc, recHandle->stats.numCompDesc));
668                        err = BKNI_WaitForEvent( recHandle->descEvent, recHandle->timeoutValue);
669                        if( err != BERR_SUCCESS )
670                        {
671                                if( err == BERR_TIMEOUT )
672                                {
673                                        recHandle->stats.numTimeouts++;
674                                        BDBG_WRN(("pvr_recordGetDataRequest(): Timeout waiting for descriptor to become available"));
675                                        break;
676                                }
677                                else
678                                {
679                                        BDBG_ERR(("pvr_recordGetDataRequest(): Fatal error waiting for descriptor to become available"));
680                                        break;
681                                }
682                        }
683                        else
684                        {
685                                BDBG_MSG(("Got %s desc event", (recHandle->recMasterHandle->chanType==BXPT_ChanType_eRecord)?"Rec":"Scd"));
686                        }
687                }
688                else
689                {
690                        break;
691                }
692        }
693
694        return err;
695}
696
697BERR_Code BPVRlib_Rec_UpdateReadPointer( 
698                                BPVRlib_Rec_Handle recHandle,   /* context handle */
699                                size_t bytesRead,                               /* number of bytes that have been read from ring buffer */
700                                bool block,                                             /* not currently used */
701                                bool *p_overflow                                /* [out] returns true if record overflow has occurred */
702                                )
703{       
704        BPVRlib_Rec_P_DescEntry *p_descEntry;
705        BERR_Code err = BERR_SUCCESS;
706
707        BSTD_UNUSED(block);
708
709        *p_overflow = false;
710
711        if( recHandle->isInProgress )
712        {
713                BXPT_Record_ChannelStatus status;
714               
715                err = BXPT_Record_GetChannelStatus(recHandle->xptRecHandle, recHandle->recMasterHandle->chanType, &status);
716                if( err != BERR_SUCCESS )
717                {
718                        goto done;
719                }
720
721                if( status.Finished )
722                {
723                        recHandle->stats.numOverFlows++;
724                        BDBG_WRN(("pvr_recordUpdateReadPointer(): Record channel %ld overflow detected!", recHandle->chanNum));
725                        *p_overflow = true;
726                }
727        }
728
729        BKNI_EnterCriticalSection();
730        p_descEntry = BLST_SQ_FIRST(&recHandle->compDescList);
731        BKNI_LeaveCriticalSection();
732        if( p_descEntry )
733        {
734                uint32_t bfrSize;
735                err = BPVRlib_Rec_P_GetDescSize( recHandle, p_descEntry->p_desc, &bfrSize );
736                if( err != BERR_SUCCESS )
737                {
738                        goto done;
739                }
740               
741                if( bytesRead > bfrSize )
742                {
743                        err = BERR_TRACE(BERR_INVALID_PARAMETER);
744                        goto done;
745                }
746                else if( bytesRead == bfrSize )
747                {
748                        BKNI_EnterCriticalSection();
749                        BLST_SQ_REMOVE_HEAD(&recHandle->compDescList, link);
750                        recHandle->stats.numCompDesc--;
751                        BKNI_LeaveCriticalSection();
752
753                        recHandle->curCompDescOffset = 0;
754
755                        if( *p_overflow )
756                        {
757                                /*
758                                When we overflow we want to make sure to process as much data from the
759                                record channel as possible before starting up the record process.  This
760                                should help the system settle after it hits an overflow condition
761                                (otherwise it might get into a scenario when it constantly keeps
762                                overflowing and has a hard time recovering).
763                                */
764                                if( recHandle->stats.numCompDesc > 0 )
765                                {
766                                        BPVRLIB_REC_P_ADD_TO_FREE_LIST( recHandle, p_descEntry );
767                                }
768                                else
769                                {
770                                        /*
771                                        We have now processed all data from this channel.
772                                        Add the minimum descriptors if possible to the record channel.
773                                        */
774                                        do
775                                        {
776                                                BPVRLIB_REC_P_ADD_TO_HARDWARE( err, recHandle, p_descEntry );
777                                                if( recHandle->stats.numInHwDesc < recHandle->minDesc )
778                                                {
779                                                        BPVRLIB_REC_P_REMOVE_FROM_FREE_LIST( recHandle, p_descEntry );
780                                                }
781                                                else
782                                                {
783                                                        p_descEntry = NULL;
784                                                }
785                                        } while( p_descEntry );
786                                }
787                        }
788                        else if( recHandle->stats.numInHwDesc < recHandle->minDesc && recHandle->isInProgress )
789                        {
790                                /*
791                                We want to reuse this buffer for this playback channel since we don't have
792                                our minimum number of descriptors allocated to the channel.  However, we
793                                need to protect ourselves since the interrupt routine might also be adding
794                                descriptors (thus the need for critical sections).
795                                */
796                                BPVRLIB_REC_P_ADD_TO_HARDWARE( err, recHandle, p_descEntry );
797                        }
798                        else
799                        {
800                                BPVRLIB_REC_P_ADD_TO_FREE_LIST( recHandle, p_descEntry );
801                        }
802                }
803                else
804                {
805                        recHandle->curCompDescOffset += bytesRead;
806                }
807        }
808        else
809        {
810                err = BERR_TRACE(BERR_INVALID_PARAMETER);
811                goto done;
812        }
813
814        recHandle->stats.bfrDepth -= bytesRead;
815        recHandle->numBytesRead += bytesRead;
816
817done:
818        return err;
819}
820
821void BPVRlib_Rec_P_Record_isr( void * pParm1, int parm2 )
822{
823        BERR_Code err;
824        uint32_t physHwWriteAddr;
825        uint32_t descSize;
826        bool lastDescriptorFound = false;
827        BPVRlib_Rec_P_DescEntry *p_descEntry;
828        BPVRlib_Rec_Handle recHandle = (BPVRlib_Rec_Handle)pParm1;
829
830        BDBG_MSG(("Got %s %s Interrupt", (recHandle->recMasterHandle->chanType==BXPT_ChanType_eRecord)?"Rec":"Scd", parm2?"Done":"Desc" ));
831
832        while( 1 )
833        {
834                p_descEntry = BLST_SQ_FIRST(&recHandle->hwDescList);
835                if( p_descEntry == NULL )
836                {
837                        BDBG_MSG(("No hardware descriptors left..."));
838                        break;
839                }
840
841                err = BXPT_Record_GetCurrentBufferAddress(recHandle->xptRecHandle, recHandle->recMasterHandle->chanType, &physHwWriteAddr);
842                BDBG_ASSERT(err == BERR_SUCCESS);
843
844                BDBG_MSG(("Desc Bfr Addr: %08X, Size: %ld", p_descEntry->p_desc->BufferStartAddr, p_descEntry->p_desc->BufferLength));
845                BDBG_MSG(("Cur Write Addr: %08X", physHwWriteAddr));
846
847                if( p_descEntry->p_desc->BufferStartAddr == physHwWriteAddr )
848                {
849                        /* We need to check the finished status.  If it is set, then this descriptor is complete! */
850                        BXPT_Record_ChannelStatus status;
851                       
852                        err = BXPT_Record_GetChannelStatus(recHandle->xptRecHandle, recHandle->recMasterHandle->chanType, &status);
853                        BDBG_ASSERT(err == BERR_SUCCESS);
854                       
855                        if( !status.Finished )
856                        {
857                                BDBG_MSG(("Hardware descriptor still in progress..."));
858                                break;
859                        }
860                }
861                else if( (p_descEntry->p_desc->BufferStartAddr < physHwWriteAddr) && 
862                        ((p_descEntry->p_desc->BufferStartAddr+p_descEntry->p_desc->BufferLength) > physHwWriteAddr) )
863                {
864                        /* If this is the done interrupt, this descriptor is partially complete, so don't break */
865                        if( parm2 == 0 )
866                        {
867                                BDBG_MSG(("Hardware descriptor still in progress..."));
868                                break;
869                        }
870                        else
871                        {
872                                BDBG_MSG(("Found last descriptor..."));
873                                lastDescriptorFound = true;
874                        }
875                }
876               
877                BDBG_MSG(("Hardware descriptor complete..."));
878
879                /* This descriptor is complete (or partially complete if the record channel is finished) */
880                BLST_SQ_REMOVE_HEAD(&recHandle->hwDescList, link);
881                recHandle->stats.numInHwDesc--;
882
883                BLST_SQ_INSERT_TAIL(&recHandle->compDescList, p_descEntry, link);               
884                recHandle->stats.numCompDesc++;
885
886                BPVRlib_Rec_P_GetDescSize(recHandle, p_descEntry->p_desc, &descSize);
887                recHandle->stats.bfrDepth += descSize;
888                recHandle->stats.numBytesRecorded += descSize;
889
890                if( lastDescriptorFound )
891                {
892                        break;
893                }
894        }
895
896        if( recHandle->stats.bfrDepth > recHandle->stats.maxBfrDepth )
897        {
898                recHandle->stats.maxBfrDepth = recHandle->stats.bfrDepth;
899        }
900
901        if( parm2 ) /* done interrupt */
902        {
903                recHandle->isInProgress = false;
904
905                BDBG_MSG(("Setting doneEvent for chan %d...", recHandle->chanNum));
906                BKNI_SetEvent(recHandle->doneEvent);
907        }
908        else
909        {
910                BERR_Code err;
911               
912                /* Add free descriptors to record if possible */
913                for( p_descEntry = BLST_SQ_FIRST(&recHandle->recMasterHandle->freeDescList); p_descEntry && (recHandle->stats.numInHwDesc < recHandle->minDesc); p_descEntry = BLST_SQ_FIRST(&recHandle->recMasterHandle->freeDescList) )
914                {
915                        BPVRLIB_REC_P_REMOVE_FROM_FREE_LIST_ISR(recHandle, p_descEntry);
916                        BPVRLIB_REC_P_ADD_TO_HARDWARE_ISR(err, recHandle, p_descEntry);
917                }       
918        }
919       
920        BDBG_MSG(("Setting descEvent (%#x) for chan %d...", (unsigned)recHandle->descEvent, recHandle->chanNum));
921        BKNI_SetEvent(recHandle->descEvent);
922}
923
924BERR_Code BPVRlib_Rec_Stop( 
925                                BPVRlib_Rec_Handle recHandle    /* context handle */
926                                )
927{
928        BPVRlib_Rec_P_DescEntry *p_descEntry;
929        BERR_Code err = BERR_SUCCESS;
930
931        BXPT_Record_ChannelStatus status;
932       
933        err = BXPT_Record_GetChannelStatus(recHandle->xptRecHandle, recHandle->recMasterHandle->chanType, &status);
934        if( err != BERR_SUCCESS )
935        {
936                return err;
937        }
938       
939        if( status.Finished )
940        {
941                BDBG_ERR(("BPVRlib_Rec_Stop(): Overflow must be cleared before stopping record channel!"));
942                return BERR_TRACE(BERR_UNKNOWN);
943        }
944
945        /* isInProgress is automatically cleared when the record finishes */
946        if( recHandle->recMasterHandle->chanType == BXPT_ChanType_eRecord )
947        {
948                err = BXPT_Record_StopChannel(recHandle->xptRecHandle);
949                if( err != BERR_SUCCESS )
950                {
951                        BDBG_ERR(("BPVRlib_Rec_Stop(): Timeout waiting for record to finish"));
952                }
953        }
954        else
955        {
956                err = BXPT_Record_StopScdChannel(recHandle->xptRecHandle);
957                if( err != BERR_SUCCESS )
958                {
959                        BDBG_ERR(("BPVRlib_Rec_Stop(): Timeout waiting for record to finish"));
960                }
961        }
962
963        if( recHandle->isInProgress )
964        {
965                BDBG_MSG(("Waiting for %s done event: Line: %ld, free: %d, hwd: %d, comp: %d", (recHandle->recMasterHandle->chanType==BXPT_ChanType_eRecord)?"Rec":"Scd", __LINE__, recHandle->recMasterHandle->numFreeDesc, recHandle->stats.numInHwDesc, recHandle->stats.numCompDesc));
966                err = BKNI_WaitForEvent(recHandle->doneEvent, recHandle->timeoutValue);
967                if( err != BERR_SUCCESS )
968                {
969                        if( err == BERR_TIMEOUT )
970                        {
971                                recHandle->stats.numTimeouts++;
972                                BDBG_ERR(("BPVRlib_Rec_Stop(): Timeout waiting for record to finish"));
973                        }
974                        else
975                        {
976                                BDBG_ERR(("BPVRlib_Rec_Stop(): Fatal error waiting for record to finish"));
977                        }
978                }
979                else
980                {
981                        BDBG_MSG(("Got %s done event", (recHandle->recMasterHandle->chanType==BXPT_ChanType_eRecord)?"Rec":"Scd"));
982                }
983        }
984
985        BDBG_MSG(("Disabling Interrupts"));
986
987        err = BPVRlib_Rec_P_DisableInterrupts(recHandle);
988        if( err != BERR_SUCCESS )
989        {
990                BDBG_ERR(("BPVRlib_Rec_Stop(): Error disabling interrupts"));
991        }
992
993        for( p_descEntry = BLST_SQ_FIRST(&recHandle->hwDescList); p_descEntry; p_descEntry = BLST_SQ_FIRST(&recHandle->hwDescList) )
994        {
995                /* Since record is finished we can remove any left over descriptors to the free list */
996                BLST_SQ_REMOVE_HEAD(&recHandle->hwDescList, link);
997                recHandle->stats.numInHwDesc--;
998
999                BPVRLIB_REC_P_ADD_TO_FREE_LIST( recHandle, p_descEntry );
1000        }
1001
1002        return err;
1003}
1004
1005
1006BERR_Code BPVRlib_Rec_P_DisableInterrupts( BPVRlib_Rec_Handle recHandle )
1007{
1008                BERR_Code err = BERR_SUCCESS;
1009               
1010                err = BINT_DisableCallback( recHandle->hDoneInt );
1011                if( err != BERR_SUCCESS )
1012                {
1013                        goto done;
1014                }
1015               
1016                err = BINT_DisableCallback( recHandle->hRecInt );
1017                if( err != BERR_SUCCESS )
1018                {
1019                        goto done;
1020                }
1021
1022        done:
1023                return err;
1024}
1025
1026
1027void BPVRlib_Rec_SetTimeout( 
1028                                BPVRlib_Rec_Handle recHandle,   /* context handle */
1029                                uint32_t numMsec                                /* timeout value in msec */
1030                                )
1031{
1032        recHandle->timeoutValue = numMsec;
1033}
1034
1035void BPVRlib_Rec_GetTimeout( 
1036                                BPVRlib_Rec_Handle recHandle,   /* context handle */
1037                                uint32_t *p_numMsec                     /* [out] returns current timeout value in msec */
1038                                )
1039{
1040        *p_numMsec = recHandle->timeoutValue;
1041}
1042
1043void BPVRlib_Rec_GetBufferDepth( 
1044                                BPVRlib_Rec_Handle recHandle,   /* context handle */
1045                                size_t *p_bfrDepth                      /* [out] number of valid bytes in the ring buffer */ 
1046                                )
1047{
1048        *p_bfrDepth = recHandle->stats.bfrDepth;
1049}
1050
1051BERR_Code BPVRlib_Rec_GetStats( 
1052                                BPVRlib_Rec_Handle recHandle,   /* context handle */
1053                                BPVRlib_Rec_Stats *p_stats              /* [out] this structure is filled with statistics */
1054                                )
1055{
1056        p_stats->numBytesRecorded       = recHandle->stats.numBytesRecorded;
1057        p_stats->numBytesRemoved        = recHandle->numBytesRead;
1058        p_stats->numDesc                        = recHandle->recMasterHandle->numDesc;
1059        p_stats->numFreeDesc            = recHandle->recMasterHandle->numFreeDesc;
1060        p_stats->numInHwDesc            = recHandle->stats.numInHwDesc;
1061        p_stats->numCompDesc            = recHandle->stats.numCompDesc;
1062        p_stats->numDescAdded           = recHandle->stats.numDescAdded;
1063        p_stats->numDescCompleted       = recHandle->stats.numDescCompleted;
1064        p_stats->numOverFlows           = recHandle->stats.numOverFlows;
1065        p_stats->numBufferBlocks        = recHandle->stats.numBufferBlocks;
1066        p_stats->numTimeouts            = recHandle->stats.numTimeouts;
1067        p_stats->maxBfrDepth            = recHandle->stats.maxBfrDepth;
1068        p_stats->bfrDepth                       = recHandle->stats.bfrDepth;
1069        p_stats->descSize                       = recHandle->recMasterHandle->bfrSize/recHandle->recMasterHandle->numDesc;
1070
1071        return BERR_SUCCESS;
1072}
1073
1074
Note: See TracBrowser for help on using the repository browser.