source: svn/newcon3bcm2_21bu/magnum/syslib/pvrlib/bpvrlib_rec.c @ 22

Last change on this file since 22 was 22, checked in by phkim, 11 years ago
  1. phkim
  2. newcon3sk 를 kctv 로 브랜치 함
  • Property svn:executable set to *
File size: 28.4 KB
Line 
1/***************************************************************************
2 *      Copyright (c) 2003-2006, 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: /SetTop/syslib/pvrlib/7115/pvrlib_rec.c@@Irvine_BSEAVSW_Devel/28
11 *
12 * $brcm_Workfile: bpvrlib_rec.c $
13 * $brcm_Revision: Hydra_Software_Devel/18 $
14 * $brcm_Date: 6/2/06 4:24p $
15 *
16 * Revision History:
17 *
18 * $brcm_Log: /magnum/syslib/pvrlib/bpvrlib_rec.c $
19 *
20 * Hydra_Software_Devel/18   6/2/06 4:24p dlwin
21 * PR 21903: Fixed a few compiler warnings.
22 *
23 * Hydra_Software_Devel/17   8/17/05 10:47a marcusk
24 * PR16713: Fixed memory leak.
25 *
26 * Hydra_Software_Devel/16   3/23/05 10:54a dlwin
27 * PR 14517: Resolved compiler warnings.
28 *
29 * Hydra_Software_Devel/15   1/24/05 6:09p marcusk
30 * PR13896: Added new function to support scd formats.
31 *
32 * Hydra_Software_Devel/14   8/20/04 11:29a erickson
33 * PR12349: have to update from hardware when getting status, otherwise
34 * fileio priorities will not be right
35 *
36 * Hydra_Software_Devel/13   6/17/04 9:29a erickson
37 * PR11135: destroy BINT callback when closing
38 *
39 * Hydra_Software_Devel/12   4/12/04 10:27p vsilyaev
40 * PR10546: Added function BPVRlib_Rec_GetEvents;
41 * Fixed bug with not clearing out p_overflow.
42 *
43 * Hydra_Software_Devel/11   1/21/04 4:43p marcusk
44 * PR8927: Fixed to work with latest version of XPT porting interface.
45 * Validate channel number.
46 *
47 * Hydra_Software_Devel/10   1/13/04 12:06p marcusk
48 * PR8927: Renamed the private functions to be compliant with Magnum
49 * architecture
50 *
51 * Hydra_Software_Devel/9   1/10/04 10:47a marcusk
52 * PR8927: Fixed playback isses.
53 *
54 * Hydra_Software_Devel/8   12/29/03 3:59p marcusk
55 * PR9117: Updated with changes required to support interrupt ids rather
56 * than strings.
57 *
58 * Hydra_Software_Devel/7   12/19/03 3:52p marcusk
59 * PR8927: Updated to use xpt record handle allocated by higher level
60 * software.
61 *
62 * Hydra_Software_Devel/6   12/12/03 2:03p dlwin
63 * PR 8970: Change naming convention to conform to Magnum
64 *
65 * Hydra_Software_Devel/5   12/11/03 4:00p marcusk
66 * PR8936: Updated to use new APIs.
67 *
68 * Hydra_Software_Devel/4   12/10/03 5:59p marcusk
69 * PR8918: Updated to use new API.
70 *
71 * Hydra_Software_Devel/3   12/10/03 2:25p marcusk
72 * PR8927: Record syslib now compiles.
73 *
74 * Hydra_Software_Devel/2   12/10/03 11:07a marcusk
75 * PR 8927: Initial magnum version (not compiled yet)
76 *
77 *************************************************************/
78
79#include "bstd.h"
80#include "blst_squeue.h"
81#include "bkni.h"
82#include "bpvrlib_p_ringmgr.h"
83#include "bpvrlib_rec.h"
84#include "bmem.h"
85
86#include "bint.h"
87#include "bchp_int_id_xpt_int.h"
88
89BDBG_MODULE(BPVRlib_Rec);
90
91/*
92TODO:
931. Modify transport PI to use single function for both type of record channels
942. Move open settings to a structure
953. Move enable and disable interrupts to XPT PI
96*/
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_Handle
107{
108        volatile bool           isInProgress;                   /* Record is in progress */
109        bool                            allRecordDataFound;             /* Set when last bits of record data is added to ring buffer */
110        BPVRlib_P_RingMgr_Handle                rbmgr;                                  /* Pointer to allocated ring buffer manager */
111        uint8_t                         *p_bfr;                                 /* Pointer to ring buffer */
112        bool                            bfrAllocated;                   /* false (buffer pointer passed in), true (buffer allocated internally) */
113        size_t                  bfrSize;                                /* Size of ring buffer */
114        uint8_t                         *p_descBfr;                             /* Buffer used for descriptor allocation */
115        BPVRlib_Rec_P_DescEntry         *p_descEntries; /* Buffer used to store descriptor list entries */
116        uint32_t                        numDesc;                                /* Num of descriptors used for Record */
117        BKNI_EventHandle        doneEvent;                              /* Event used to signal when the record is done */
118        BKNI_EventHandle        descEvent;                              /* Event used to signal when a descriptor is done */
119        BPVRlib_Rec_P_DescList freeDescList; /* List containing all free descriptors */
120        BPVRlib_Rec_P_DescList hwDescList;        /* List containing descriptors that are loading in hardware */
121        BPVRlib_Rec_CopyMemoryCb copyMemCb;             /* Callback used to copy data into the ring buffer */
122        uint32_t                        numBytesRead;                   /* Number of bytes that have been read, but not re-added into hardware */
123        uint32_t                        timeoutValue;                   /* Max number of msec to wait for an event to occur */
124        BPVRlib_Rec_Stats       stats;                                  /* Statistics */
125        BXPT_ChanType           chanType;                       /* Channel type */
126        unsigned                        chanNum;                                /* Channel number */
127        BMEM_Handle             memHandle;                              /* Mem handle */
128        BXPT_Handle             xptHandle;                              /* XPT handle */
129        BXPT_Record_Handle  xptRecHandle;                       /* XPT Record Handle */
130        BINT_Handle                     intHandle;                              /* BINT handle */
131        BINT_CallbackHandle hRecInt;                            /* cb Handle for rec interrupt */
132        BINT_CallbackHandle hDoneInt;                           /* cb Handle for done interrupt */
133        BXPT_IndexTable         indexType;                              /* index type to record */
134} BPVRlib_Rec_P_Handle;
135
136static void BPVRlib_Rec_P_isr( void * pParm1, int parm2 );
137static void BPVRlib_Rec_P_UpdateHwDescriptors( BPVRlib_Rec_Handle recHandle );
138static BERR_Code BPVRlib_Rec_P_CreateIntCallbacks( BPVRlib_Rec_Handle recHandle );
139static BERR_Code BPVRlib_Rec_P_EnableInterrupts( BPVRlib_Rec_Handle recHandle );
140static BERR_Code BPVRlib_Rec_P_DisableInterrupts( BPVRlib_Rec_Handle recHandle );
141
142BERR_Code BPVRlib_Rec_Open(
143        BPVRlib_Rec_Handle *pRecHandle,         /* [out] context handle */
144        BXPT_Handle xptHandle,                          /* XPT handle */
145        BXPT_Record_Handle xptRecHandle,        /* XPT Record handle */
146        BMEM_Handle memHandle,                          /* Mem handle */
147        BINT_Handle intHandle,                          /* Int handle */
148        BXPT_ChanType chanType, /* Record channel type */
149        unsigned chanNum,                                               /* record channel number */
150        uint8_t *p_bfr,                                         /* pointer to buffer that should be used for record ring buffer, 0 to allocate the buffer internally */
151        size_t bfrSize,                                 /* size of record ring buffer (in bytes) */
152        uint32_t numDesc,                                       /* number of descriptors to use  */
153        BPVRlib_Rec_CopyMemoryCb copyMemCb      /* function pointer for memory copies (optional) */
154                                )
155{
156        BERR_Code               err = BERR_SUCCESS;
157        uint32_t                i;
158        BXPT_PvrDescriptor      *p_desc;
159        BPVRlib_Rec_Handle recHandle = NULL;
160        BXPT_Capability xptCaps;
161
162        BXPT_GetCapability( xptHandle, &xptCaps );
163
164        if( chanNum >= xptCaps.MaxRecords )
165        {
166                err = BERR_TRACE(BERR_INVALID_PARAMETER);
167                goto done;
168        }
169
170        if( ((bfrSize / numDesc) % 4) || bfrSize == 0 )
171        {
172                err = BERR_TRACE(BERR_INVALID_PARAMETER) ;
173                BDBG_ERR(("pvr_recordAllocate(): (buffer size / number of descriptors) must be multiple of 32 bits!"));
174                goto done;
175        }
176
177        recHandle = BKNI_Malloc( sizeof(BPVRlib_Rec_P_Handle) );
178        if( recHandle == NULL )
179        {
180                err = BERR_TRACE(BERR_OUT_OF_SYSTEM_MEMORY);
181                goto done;
182        }
183
184        BKNI_Memset( recHandle, 0, sizeof(BPVRlib_Rec_P_Handle) );
185
186        if( p_bfr == NULL )
187        {
188                p_bfr = BMEM_Alloc( memHandle, bfrSize );
189                if( p_bfr == NULL )
190                {
191                        err = BERR_TRACE(BERR_OUT_OF_DEVICE_MEMORY);
192                        goto error;
193                }
194                recHandle->bfrAllocated = true;
195        }
196
197        /* Save parameters */
198        recHandle->p_bfr                = p_bfr;
199        recHandle->bfrSize              = bfrSize;
200        recHandle->numDesc              = numDesc;
201        recHandle->copyMemCb    = copyMemCb;
202        recHandle->timeoutValue = 0xFFFFFFFF;
203        recHandle->xptHandle    = xptHandle;
204        recHandle->xptRecHandle = xptRecHandle;
205        recHandle->memHandle    = memHandle;
206        recHandle->chanType             = chanType;
207        recHandle->chanNum              = chanNum;
208        recHandle->xptHandle    = xptHandle;
209        recHandle->intHandle    = intHandle;
210        recHandle->indexType    = BXPT_IndexTable_eStartCode4Word;
211
212        /* Init our lists */
213        BLST_SQ_INIT( &recHandle->freeDescList );
214        BLST_SQ_INIT( &recHandle->hwDescList );
215
216        /* Descriptors must be 16 byte aligned so allocate an extra 15 bytes */
217        recHandle->p_descBfr = BMEM_AllocAligned( recHandle->memHandle, (sizeof(BXPT_PvrDescriptor)*numDesc), 4 /* 16 byte aligned */, 0 );
218        p_desc = (BXPT_PvrDescriptor *)recHandle->p_descBfr;
219        if( p_desc == NULL )
220        {
221                err = BERR_TRACE(BERR_OUT_OF_DEVICE_MEMORY);
222                goto error;             
223        }
224
225        /* Allocate storage for our descriptor entries */
226        recHandle->p_descEntries = BKNI_Malloc( sizeof(BPVRlib_Rec_P_DescEntry) * numDesc );
227        if( recHandle->p_descEntries == NULL )
228        {
229                err = BERR_TRACE(BERR_OUT_OF_SYSTEM_MEMORY);
230                goto error;             
231        }
232
233        /* Assign a descriptor to each descriptor list entry and add them to the free list */
234        for( i = 0; i < numDesc; i++ )
235        {
236                recHandle->p_descEntries[i].p_desc = &p_desc[i];
237                BLST_SQ_INSERT_HEAD(&recHandle->freeDescList, &recHandle->p_descEntries[i], link);
238                recHandle->stats.numFreeDesc++;
239        }
240
241        err = BPVRlib_P_RingMgr_Open( &recHandle->rbmgr, chanNum, 0, 0, p_bfr, bfrSize );
242        if( err != BERR_SUCCESS )
243        {
244                goto error;
245        }
246        err = BKNI_CreateEvent(&recHandle->doneEvent);
247        if( err != BERR_SUCCESS )
248        {
249                goto error;
250        }
251        err = BKNI_CreateEvent(&recHandle->descEvent);
252        if( err != BERR_SUCCESS )
253        {
254                goto error;
255        }
256        err = BPVRlib_Rec_P_CreateIntCallbacks(recHandle);
257        if( err != BERR_SUCCESS )
258        {
259                goto error;
260        }
261
262done:
263        *pRecHandle = recHandle;
264        return err;
265
266error:
267        BPVRlib_Rec_Close( recHandle );
268        return err;
269}
270
271BERR_Code BPVRlib_Rec_Close(
272                                BPVRlib_Rec_Handle recHandle            /* context handle */
273                                )
274{
275        if( recHandle->isInProgress )
276        {
277                return BERR_TRACE(BERR_UNKNOWN);
278        }
279
280        if (recHandle->hRecInt) BINT_DestroyCallback(recHandle->hRecInt);
281        if (recHandle->hDoneInt) BINT_DestroyCallback(recHandle->hDoneInt);
282
283        if( recHandle->rbmgr != NULL ) BPVRlib_P_RingMgr_Close( recHandle->rbmgr );
284        if( recHandle->p_descBfr != NULL ) BMEM_Free( recHandle->memHandle, recHandle->p_descBfr );
285        if( recHandle->bfrAllocated == true ) BMEM_Free( recHandle->memHandle, recHandle->p_bfr );
286        if( recHandle->p_descEntries != NULL ) BKNI_Free( recHandle->p_descEntries );
287        if( recHandle->doneEvent != NULL ) BKNI_DestroyEvent(recHandle->doneEvent);
288        if( recHandle->descEvent != NULL ) BKNI_DestroyEvent(recHandle->descEvent);
289
290        BKNI_Free(recHandle);
291
292        return BERR_SUCCESS;
293}
294
295BERR_Code
296BPVRlib_Rec_GetEvents(BPVRlib_Rec_Handle recHandle, BPVRlib_Rec_Events *events)
297{
298        events->descEvent = recHandle->descEvent;
299        events->finishedEvent = recHandle->doneEvent;
300        return BERR_SUCCESS;
301}
302
303BERR_Code BPVRlib_Rec_Start( 
304                                BPVRlib_Rec_Handle recHandle            /* context handle */
305                                )
306{
307        BERR_Code               err = BERR_SUCCESS;
308        BPVRlib_Rec_P_DescEntry *p_descEntry;
309        size_t bfrSize;
310    uint32_t bfrOffset;
311        uint8_t *p_bfr;
312
313        if( recHandle->isInProgress )
314        {
315                return BERR_TRACE(BERR_UNKNOWN);
316        }
317
318        BPVRlib_P_RingMgr_Reset( recHandle->rbmgr );
319        recHandle->numBytesRead = 0;
320
321        recHandle->stats.numDescAdded           = 0;
322        recHandle->stats.numDescCompleted       = 0;
323        recHandle->stats.numOverFlows           = 0;
324        recHandle->stats.numBufferBlocks        = 0;
325        recHandle->stats.numTimeouts            = 0;
326        recHandle->stats.maxBfrDepth            = 0;
327
328        /* Move all of the descriptors from the hardware list to the free list */
329        while( !BLST_SQ_EMPTY(&recHandle->hwDescList) )
330        {
331                p_descEntry = BLST_SQ_FIRST(&recHandle->hwDescList);
332                BLST_SQ_REMOVE_HEAD(&recHandle->hwDescList, link);
333                recHandle->stats.numInHwDesc--;
334                BLST_SQ_INSERT_HEAD(&recHandle->freeDescList, p_descEntry, link);
335                recHandle->stats.numFreeDesc++;
336        }
337
338        bfrOffset = 0;
339
340        /* We know this divides evenly because we checked it as part of the allocate routine */
341        bfrSize = recHandle->bfrSize / recHandle->numDesc;
342
343        /* Now load all of our descriptors into hardware */
344        while( !BLST_SQ_EMPTY(&recHandle->freeDescList) )
345        {
346                BDBG_ASSERT( bfrOffset + bfrSize <= recHandle->bfrSize );
347
348                p_descEntry = BLST_SQ_FIRST(&recHandle->freeDescList);
349                BLST_SQ_REMOVE_HEAD( &recHandle->freeDescList, link );
350                recHandle->stats.numFreeDesc--;
351                if( p_descEntry == NULL )
352                {
353                        err = BERR_TRACE(BERR_UNKNOWN);
354                        goto done;
355                }
356
357                err = BXPT_Record_CreateDesc(recHandle->xptHandle, p_descEntry->p_desc, recHandle->p_bfr+bfrOffset, bfrSize, true, NULL);
358                BLST_SQ_INSERT_TAIL( &recHandle->hwDescList, p_descEntry, link );
359                recHandle->stats.numInHwDesc++;
360
361                if( err != BERR_SUCCESS )
362                {
363                        goto done;
364                }
365
366                BDBG_MSG(("Adding %s descriptor",(recHandle->chanType==BXPT_ChanType_eRecord)?"Rec":"Scd")); 
367                err = BXPT_Record_AddDescriptors(recHandle->xptRecHandle, recHandle->chanType, p_descEntry->p_desc, p_descEntry->p_desc);
368
369                if( err != BERR_SUCCESS )
370                {
371                        goto done;
372                }
373
374                bfrOffset += bfrSize;
375        }
376
377        BDBG_ASSERT( bfrOffset == recHandle->bfrSize );
378
379        /* We need to kick start the ring buffer manager */
380        err = BPVRlib_P_RingMgr_AddDataRequest( recHandle->rbmgr, &p_bfr, &bfrSize, 0, 0 );
381        if( err != BERR_SUCCESS )
382        {
383                goto done;
384        }
385
386        err = BPVRlib_Rec_P_EnableInterrupts( recHandle );
387        if( err != BERR_SUCCESS )
388        {
389                goto done;
390        }
391
392        if( recHandle->chanType == BXPT_ChanType_eRecord )
393        {
394                err = BXPT_Record_StartChannel(recHandle->xptRecHandle);
395                if( err != BERR_SUCCESS )
396                {
397                        goto done;
398                }
399        }
400        else
401        {
402                err = BXPT_Record_StartScdChannel(recHandle->xptRecHandle, recHandle->indexType);
403                if( err != BERR_SUCCESS )
404                {
405                        goto done;
406                }
407        }
408
409        /*
410        It is okay to set these flags after the record hardware has started for the following reasons:
411        These flags are only touched by non-isr functions (which must be serialed with this function,
412        or when the done interrupt is set by the hardware.  The done interrupt  will never be set
413        until after the record channel is stopped.
414        */
415        recHandle->isInProgress = true;
416        recHandle->allRecordDataFound = false;
417
418done:
419        return err;
420}
421
422BERR_Code BPVRlib_Rec_P_CreateIntCallbacks( BPVRlib_Rec_Handle recHandle )
423{
424        BERR_Code err = BERR_SUCCESS;
425
426        /* For each record channel we need to enable the record and done interrupts */
427        BINT_Id recInt = BCHP_INT_ID_REC0_INT;
428        BINT_Id doneInt = BCHP_INT_ID_REC0_DONE;
429
430        if( recHandle->chanType == BXPT_ChanType_eRecord )
431        {
432                switch( recHandle->chanNum )
433                {
434                        case 0:
435                                recInt = BCHP_INT_ID_REC0_INT;
436                                doneInt = BCHP_INT_ID_REC0_DONE;
437                                break;
438                        case 1:
439                                recInt = BCHP_INT_ID_REC1_INT;
440                                doneInt = BCHP_INT_ID_REC1_DONE;
441                                break;
442                        case 2:
443                                recInt = BCHP_INT_ID_REC2_INT;
444                                doneInt = BCHP_INT_ID_REC2_DONE;
445                                break;
446                        default:
447                                err = BERR_TRACE(BERR_UNKNOWN);
448                                goto done;
449                }
450        }
451        else
452        {
453                switch( recHandle->chanNum )
454                {
455                        case 0:
456                                recInt = BCHP_INT_ID_SCD0_INT;
457                                doneInt = BCHP_INT_ID_SCD0_DONE;
458                                break;
459                        case 1:
460                                recInt = BCHP_INT_ID_SCD1_INT;
461                                doneInt = BCHP_INT_ID_SCD1_DONE;
462                                break;
463                        case 2:
464                                recInt = BCHP_INT_ID_SCD2_INT;
465                                doneInt = BCHP_INT_ID_SCD2_DONE;
466                                break;
467                        default:
468                                err = BERR_TRACE(BERR_UNKNOWN);
469                                goto done;
470                }
471        }
472
473        err = BINT_CreateCallback(&recHandle->hRecInt, recHandle->intHandle, recInt, BPVRlib_Rec_P_isr, recHandle, 0);
474        if( err != BERR_SUCCESS )
475        {
476                goto done;
477        }
478        err = BINT_CreateCallback(&recHandle->hDoneInt, recHandle->intHandle, doneInt, BPVRlib_Rec_P_isr, recHandle, 1);
479        if( err != BERR_SUCCESS )
480        {
481                goto done;
482        }
483
484done:
485        return err;
486}
487
488BERR_Code BPVRlib_Rec_P_EnableInterrupts( BPVRlib_Rec_Handle recHandle )
489{
490        BERR_Code err = BERR_SUCCESS;
491
492        err = BINT_EnableCallback( recHandle->hDoneInt );
493        if( err != BERR_SUCCESS )
494        {
495                goto done;
496        }
497
498        err = BINT_EnableCallback( recHandle->hRecInt );
499        if( err != BERR_SUCCESS )
500        {
501                goto done;
502        }
503
504done:
505        return err;
506}
507
508BERR_Code BPVRlib_Rec_GetData(
509                                BPVRlib_Rec_Handle recHandle,   /* context handle */
510                                uint8_t *p_bfr,                         /* [out,sizeof(*p_bfrSize)] pointer to destination buffer */
511                                size_t *p_bfrSize,              /* [in,out] size of destination buffer (in bytes), returns number of bytes actually copied */
512                                bool block,                                     /* false (do not block), true (block until data is available) */
513                                bool *p_overflow                        /* [out] returns 1 if record overflow has occurred */
514                                )
515{
516        BERR_Code err = BERR_SUCCESS;
517        uint8_t *p_srcBfr;
518        size_t srcBfrSize;
519
520        *p_overflow = false;
521
522        err = BPVRlib_Rec_GetDataRequest( recHandle, &p_srcBfr, &srcBfrSize, block );
523
524        if( srcBfrSize > *p_bfrSize )
525        {
526                srcBfrSize = *p_bfrSize;
527        }
528
529        /* Make sure to init this variable before returing due to errors */
530        *p_bfrSize = 0;
531
532        if( srcBfrSize == 0 || err != BERR_SUCCESS )
533        {
534                goto done;
535        }
536
537        if( recHandle->copyMemCb )
538        {
539                (*recHandle->copyMemCb)( p_bfr, p_srcBfr, srcBfrSize );
540        }
541        else
542        {
543                err = BERR_NOT_INITIALIZED;
544                BDBG_ERR(("pvr_recordGetData(): No memory copy callback installed!  Unable to add data."));
545                goto done;
546        }
547
548        err = BPVRlib_Rec_UpdateReadPointer( recHandle, srcBfrSize, block, p_overflow );
549        if( err != BERR_SUCCESS )
550        {
551                BDBG_WRN(("BPVRlib_Rec_GetData(): No blocking requirement caused write pointer update to timeout"));
552                goto done;
553        }
554
555        *p_bfrSize = srcBfrSize;
556
557done:
558        return err;
559}
560
561BERR_Code BPVRlib_Rec_GetDataRequest( 
562                                BPVRlib_Rec_Handle recHandle,   /* context handle */
563                                uint8_t **pp_bfr,                               /* [out] returns pointer to the start of valid data */
564                                size_t *p_bfrSize,                      /* [out] returns size of the valid data (in bytes) */ 
565                                bool block                                              /* 0 (do not block), 1 (block until data is available) */
566                                )
567{
568        BERR_Code err = BERR_SUCCESS;
569
570        if( !recHandle->isInProgress )
571        {
572                /* Do not allow blocking when the record is not actively in progress */
573                block = 0;
574        }
575
576        while( 1 )
577        {
578                BPVRlib_Rec_P_UpdateHwDescriptors( recHandle );
579
580                if( (err = BPVRlib_P_RingMgr_RemoveDataRequest( recHandle->rbmgr, pp_bfr, p_bfrSize, 0, recHandle->timeoutValue )) != BERR_SUCCESS )
581                {
582                        /* A timeout isn't really an error as it will occur when we stop the record */
583                        if( recHandle->isInProgress || err != BERR_TIMEOUT )
584                        {
585                                BDBG_ERR(("BPVRlib_Rec_GetDataRequest(): Error removing data from ring buffer"));
586                        }
587                        goto done;
588                }
589
590                if( !recHandle->isInProgress )
591                {
592                        /* Don't wait for more data, as no more will ever come in! */
593                        BDBG_MSG(("BPVRlib_Rec_GetDataRequest(): Record no longer in progress"));
594                        goto done;
595                }
596
597                if( *p_bfrSize == 0 && block )
598                {
599                        recHandle->stats.numBufferBlocks++;
600                        BDBG_MSG(("Waiting for %s event: Line: %ld, fd: %d, hwd: %d", (recHandle->chanType==BXPT_ChanType_eRecord)?"Rec":"Scd", __LINE__, recHandle->stats.numFreeDesc, recHandle->stats.numInHwDesc));
601                        err = BKNI_WaitForEvent( recHandle->descEvent, recHandle->timeoutValue);
602                        if( err != BERR_SUCCESS )
603                        {
604                                if( err == BERR_TIMEOUT )
605                                {
606                                        recHandle->stats.numTimeouts++;
607                                        BDBG_WRN(("pvr_recordGetDataRequest(): Timeout waiting for descriptor to become available"));
608                                        goto done;
609                                }
610                                else
611                                {
612                                        BDBG_ERR(("pvr_recordGetDataRequest(): Fatal error waiting for descriptor to become available"));
613                                        goto done;
614                                }
615                        }
616                }
617                else
618                {
619                        break;
620                }
621        }
622
623
624done:
625        return err;
626}
627
628BERR_Code BPVRlib_Rec_UpdateReadPointer( 
629                                BPVRlib_Rec_Handle recHandle,   /* context handle */
630                                size_t bytesRead,                               /* number of bytes that have been read from ring buffer */
631                                bool block,                                             /* not currently used */
632                                bool *p_overflow                                /* [out] returns true if record overflow has occurred */
633                                )
634{       
635        BPVRlib_Rec_P_DescEntry *p_descEntry;
636        BERR_Code err = BERR_SUCCESS;
637        BXPT_Record_ChannelStatus status;
638
639        BSTD_UNUSED(block);
640
641        err = BXPT_Record_GetChannelStatus(recHandle->xptRecHandle, recHandle->chanType, &status);
642        if( err != BERR_SUCCESS )
643        {
644                goto done;
645        }
646
647        if( status.Finished )
648        {
649                recHandle->stats.numOverFlows++;
650                BDBG_WRN(("pvr_recordUpdateReadPointer(): Record channel %ld overflow detected!", recHandle->chanNum));
651                *p_overflow = true;
652        } else {
653                *p_overflow = false;
654        }
655
656        err = BPVRlib_P_RingMgr_UpdateReadPointer( recHandle->rbmgr, bytesRead );
657        if( err != BERR_SUCCESS )
658        {
659                goto done;
660        }
661
662        recHandle->numBytesRead += bytesRead;
663
664        if( !recHandle->isInProgress )
665        {
666                /* Since we are not actively recording, simply return as we don't need to load any buffers into the hardware */
667                goto done;
668        }
669
670        /* Check if we've removed enough data to allow us to reload a descriptor (or two) */
671        while( recHandle->numBytesRead >= recHandle->bfrSize/recHandle->numDesc )
672        {
673                /* By definition a descriptor should be on the free list */
674                BDBG_ASSERT( !BLST_SQ_EMPTY(&recHandle->freeDescList) );
675
676                /* Remove the first free descriptor */
677                p_descEntry = BLST_SQ_FIRST(&recHandle->freeDescList);
678                BLST_SQ_REMOVE_HEAD( &recHandle->freeDescList, link );
679                recHandle->stats.numFreeDesc--;
680
681                /* We need to remove the next descriptor pointer before reloading it! */
682                BXPT_SetLastDescriptorFlag(p_descEntry->p_desc);
683
684                /* Add our descriptor entry to the hardware list */
685                BLST_SQ_INSERT_TAIL( &recHandle->hwDescList, p_descEntry, link );
686                recHandle->stats.numInHwDesc++;
687
688                /* Add this buffer into the hardware */
689                BDBG_MSG(("Adding %s descriptor",(recHandle->chanType==BXPT_ChanType_eRecord)?"Rec":"Scd"));
690                BDBG_MSG(("0x%08X 0x%08X 0x%08X 0x%08X",((uint32_t*)(p_descEntry->p_desc))[0], ((uint32_t*)(p_descEntry->p_desc))[1], ((uint32_t*)(p_descEntry->p_desc))[2], ((uint32_t*)(p_descEntry->p_desc))[3]));
691                BXPT_Record_AddDescriptors(recHandle->xptRecHandle, recHandle->chanType, p_descEntry->p_desc, p_descEntry->p_desc);
692
693                recHandle->stats.numDescAdded++;
694                recHandle->numBytesRead -= recHandle->bfrSize/recHandle->numDesc;
695        }
696
697done:
698        return err;
699}
700
701void BPVRlib_Rec_P_isr( void * pParm1, int parm2 )
702{
703        BPVRlib_Rec_Handle recHandle = (BPVRlib_Rec_Handle)pParm1;
704
705        BDBG_MSG(("Got %s %s Interrupt", (recHandle->chanType==BXPT_ChanType_eRecord)?"Rec":"Scd", parm2?"Done":"Desc" ));
706
707        BKNI_SetEvent(recHandle->descEvent);
708
709        if( parm2 ) /* done interrupt */
710        {
711                recHandle->isInProgress = false;
712                BKNI_SetEvent(recHandle->doneEvent);
713        }
714}
715
716/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
717+ INPUTS:       chanType - ePvrRecord or ePvrScd channel
718+                       chanNum - record channel number
719+ OUTPUTS:      None
720+ RETURNS:      None
721+ FUNCTION: This function updates the ring buffer write pointer with
722+                       the amount of data completed in the descriptor.  It also
723+                       searches the descriptor list for all completed descriptors
724+                       in case more than one has completed since the last interrupt.
725+                       This function is also called after the record done interrupt occurs
726+                       to update the ring buffer with the last partial amount
727+                       of data that was recorded though a single recursion
728+                       call.
729+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
730void BPVRlib_Rec_P_UpdateHwDescriptors( BPVRlib_Rec_Handle recHandle )
731{
732        bool    descIsComplete = true;
733        BPVRlib_Rec_P_DescEntry *p_descEntry;
734        uint8_t *p_bfr;
735        size_t bfrSize;
736        uint32_t descSize;
737        uint32_t physHwWriteAddr;
738        size_t bufferDepth;
739
740        while( descIsComplete )
741        {
742                if( recHandle->allRecordDataFound )
743                {
744                        descIsComplete = false; /* exit the while loop */
745                        continue;
746                }
747
748                /* Make sure we have entries in the hardware list */
749                if( BLST_SQ_EMPTY(&recHandle->hwDescList) )
750                {
751                        BDBG_MSG(("BPVRlib_Rec_P_UpdateHwDescriptors(): Hardware descriptor list is empty"));
752                        descIsComplete = false; /* exit the while loop */
753                        continue;
754                }
755
756                BXPT_Record_GetCurrentBufferAddress(recHandle->xptRecHandle, recHandle->chanType, &physHwWriteAddr);
757
758                /* Check if the head descriptor is complete */
759                p_descEntry = BLST_SQ_FIRST(&recHandle->hwDescList);
760
761                descSize = p_descEntry->p_desc->BufferLength;
762
763                if( (p_descEntry->p_desc->BufferStartAddr <= physHwWriteAddr)
764                        && ((p_descEntry->p_desc->BufferStartAddr+p_descEntry->p_desc->BufferLength) > physHwWriteAddr) )
765                {
766                        BXPT_Record_ChannelStatus status;
767                       
768                        BXPT_Record_GetChannelStatus(recHandle->xptRecHandle, recHandle->chanType, &status);
769                       
770                        if( status.Finished && p_descEntry->p_desc->BufferStartAddr == physHwWriteAddr )
771                        {
772                                /* We are completely full and in an overflow condition */
773                                descIsComplete = true;
774                        }
775                        else if( recHandle->isInProgress )
776                        {
777                                /* Hardware is currently processing this descriptor */
778                                descIsComplete = false;
779                        }
780                        else
781                        {
782                                BDBG_MSG(("BPVRlib_Rec_P_UpdateHwDescriptors(): All record data has been stored"));
783                                /* Recording is done, so include last bits of data that was recorded by hardware */
784                                descSize = physHwWriteAddr - p_descEntry->p_desc->BufferStartAddr;
785                                recHandle->allRecordDataFound = true;
786                        }
787                }
788
789                if( !descIsComplete )
790                {
791                        /* exit the while loop because there are no more complete descriptors */
792                        continue;
793                }
794
795                /* Remove the first descriptor from the hardware list */
796                p_descEntry = BLST_SQ_FIRST(&recHandle->hwDescList);
797                BLST_SQ_REMOVE_HEAD( &recHandle->hwDescList, link );
798                recHandle->stats.numInHwDesc--;
799
800                recHandle->stats.numDescCompleted++;
801
802                /* Place the descriptor back on the free list */
803                BLST_SQ_INSERT_TAIL( &recHandle->freeDescList, p_descEntry, link );
804                recHandle->stats.numFreeDesc++;
805
806                BPVRlib_P_RingMgr_AddDataRequest( recHandle->rbmgr, &p_bfr, &bfrSize, 0, 0 );
807
808                /* Sanity check */
809                BDBG_ASSERT( bfrSize >= descSize );
810                BDBG_ASSERT( (BMEM_ConvertAddressToOffset( recHandle->memHandle, p_bfr, &physHwWriteAddr ), physHwWriteAddr == p_descEntry->p_desc->BufferStartAddr) );
811
812                BPVRlib_P_RingMgr_UpdateWritePointer( recHandle->rbmgr, descSize );
813        }
814       
815        /* Store our max buffer depth size */
816        BPVRlib_Rec_GetBufferDepth(recHandle, &bufferDepth);
817        if( bufferDepth > recHandle->stats.maxBfrDepth )
818        {
819                recHandle->stats.maxBfrDepth = bufferDepth;
820        }
821}
822
823BERR_Code BPVRlib_Rec_Stop( 
824                                BPVRlib_Rec_Handle recHandle    /* context handle */
825                                )
826{
827        BERR_Code err = BERR_SUCCESS;
828
829        /* isInProgress is automatically cleared when the record finishes */
830        if( recHandle->chanType == BXPT_ChanType_eRecord )
831        {
832                err = BXPT_Record_StopChannel(recHandle->xptRecHandle);
833                if( err != BERR_SUCCESS )
834                {
835                        BDBG_ERR(("BPVRlib_Rec_Stop(): Timeout waiting for record to finish"));
836                }
837        }
838        else
839        {
840                err = BXPT_Record_StopScdChannel(recHandle->xptRecHandle);
841                if( err != BERR_SUCCESS )
842                {
843                        BDBG_ERR(("BPVRlib_Rec_Stop(): Timeout waiting for record to finish"));
844                }
845        }
846
847        if( recHandle->isInProgress )
848        {
849                BDBG_MSG(("Waiting for %s event: Line: %ld, fd: %d, hwd: %d", (recHandle->chanType==BXPT_ChanType_eRecord)?"Rec":"Scd", __LINE__, recHandle->stats.numFreeDesc, recHandle->stats.numInHwDesc));
850                err = BKNI_WaitForEvent(recHandle->doneEvent, recHandle->timeoutValue);
851                if( err != BERR_SUCCESS )
852                {
853                        if( err == BERR_TIMEOUT )
854                        {
855                                recHandle->stats.numTimeouts++;
856                                BDBG_ERR(("BPVRlib_Rec_Stop(): Timeout waiting for record to finish"));
857                        }
858                        else
859                        {
860                                BDBG_ERR(("BPVRlib_Rec_Stop(): Fatal error waiting for record to finish"));
861                        }
862                }
863        }
864
865        err = BPVRlib_Rec_P_DisableInterrupts(recHandle);
866        if( err != BERR_SUCCESS )
867        {
868                BDBG_ERR(("BPVRlib_Rec_Stop(): Error disabling interrupts"));
869        }
870
871        /* Wake up a task that might be waiting for record data! */
872        BKNI_SetEvent(recHandle->descEvent);
873
874        return err;
875}
876
877
878BERR_Code BPVRlib_Rec_P_DisableInterrupts( BPVRlib_Rec_Handle recHandle )
879{
880                BERR_Code err = BERR_SUCCESS;
881               
882                err = BINT_DisableCallback( recHandle->hDoneInt );
883                if( err != BERR_SUCCESS )
884                {
885                        goto done;
886                }
887
888                err = BINT_DisableCallback( recHandle->hRecInt );
889                if( err != BERR_SUCCESS )
890                {
891                        goto done;
892                }
893       
894        done:
895                return err;
896}
897
898
899void BPVRlib_Rec_SetTimeout( 
900                                BPVRlib_Rec_Handle recHandle,   /* context handle */
901                                uint32_t numMsec                                /* timeout value in msec */
902                                )
903{
904        recHandle->timeoutValue = numMsec;
905}
906
907void BPVRlib_Rec_GetTimeout( 
908                                BPVRlib_Rec_Handle recHandle,   /* context handle */
909                                uint32_t *p_numMsec                     /* [out] returns current timeout value in msec */
910                                )
911{
912        *p_numMsec = recHandle->timeoutValue;
913}
914
915void BPVRlib_Rec_GetBufferDepth( 
916                                BPVRlib_Rec_Handle recHandle,   /* context handle */
917                                size_t *p_bfrDepth                      /* [out] number of valid bytes in the ring buffer */ 
918                                )
919{
920        BPVRlib_P_RingMgr_GetNumFreeBytes( recHandle->rbmgr, p_bfrDepth );
921        *p_bfrDepth = recHandle->bfrSize - *p_bfrDepth;
922}
923
924BERR_Code BPVRlib_Rec_GetStats(
925                                BPVRlib_Rec_Handle recHandle,   /* context handle */
926                                BPVRlib_Rec_Stats *p_stats              /* [out] this structure is filled with statistics */
927                                )
928{
929        BPVRlib_Rec_P_UpdateHwDescriptors( recHandle );
930       
931        p_stats->numBytesRecorded       = (recHandle->rbmgr->bufferSize * recHandle->rbmgr->writeWrapCount) + recHandle->rbmgr->writeOffset;
932        p_stats->numBytesRemoved        = (recHandle->rbmgr->bufferSize * recHandle->rbmgr->readWrapCount) + recHandle->rbmgr->readOffset;
933        p_stats->bfrSize                        = recHandle->rbmgr->bufferSize;
934        p_stats->readOffset             = recHandle->rbmgr->readOffset;
935        p_stats->writeOffset            = recHandle->rbmgr->hwWriteOffset;
936        p_stats->numDesc                        = recHandle->numDesc;
937        p_stats->numFreeDesc            = recHandle->stats.numFreeDesc;
938        p_stats->numInHwDesc            = recHandle->stats.numInHwDesc;
939        p_stats->numDescAdded           = recHandle->stats.numDescAdded;
940        p_stats->numDescCompleted       = recHandle->stats.numDescCompleted;
941        p_stats->numOverFlows           = recHandle->stats.numOverFlows;
942        p_stats->numBufferBlocks        = recHandle->stats.numBufferBlocks;
943        p_stats->numTimeouts            = recHandle->stats.numTimeouts;
944        p_stats->maxBfrDepth            = recHandle->stats.maxBfrDepth;
945
946        return BERR_SUCCESS;
947}
948
949void BPVRlib_Rec_SetIndexType( 
950        BPVRlib_Rec_Handle recHandle,   /* context handle */
951        BXPT_IndexTable indexType               /* type of index data to record (default is BXPT_IndexTable_eStartCode4Word) */
952        )
953{
954        recHandle->indexType    = indexType;
955}
956
Note: See TracBrowser for help on using the repository browser.