source: svn/newcon3bcm2_21bu/nexus/modules/transport/7552/src/nexus_recpump.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: 93.5 KB
Line 
1/***************************************************************************
2 *     (c)2007-2011 Broadcom Corporation
3 *
4 *  This program is the proprietary software of Broadcom Corporation and/or its licensors,
5 *  and may only be used, duplicated, modified or distributed pursuant to the terms and
6 *  conditions of a separate, written license agreement executed between you and Broadcom
7 *  (an "Authorized License").  Except as set forth in an Authorized License, Broadcom grants
8 *  no license (express or implied), right to use, or waiver of any kind with respect to the
9 *  Software, and Broadcom expressly reserves all rights in and to the Software and all
10 *  intellectual property rights therein.  IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU
11 *  HAVE NO RIGHT TO USE THIS SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY
12 *  NOTIFY BROADCOM AND DISCONTINUE ALL USE OF THE SOFTWARE.
13 *
14 *  Except as expressly set forth in the Authorized License,
15 *
16 *  1.     This program, including its structure, sequence and organization, constitutes the valuable trade
17 *  secrets of Broadcom, and you shall use all reasonable efforts to protect the confidentiality thereof,
18 *  and to use this information only in connection with your use of Broadcom integrated circuit products.
19 *
20 *  2.     TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
21 *  AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES, REPRESENTATIONS OR
22 *  WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
23 *  THE SOFTWARE.  BROADCOM SPECIFICALLY DISCLAIMS ANY AND ALL IMPLIED WARRANTIES
24 *  OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE,
25 *  LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION
26 *  OR CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT OF
27 *  USE OR PERFORMANCE OF THE SOFTWARE.
28 *
29 *  3.     TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR ITS
30 *  LICENSORS BE LIABLE FOR (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR
31 *  EXEMPLARY DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO YOUR
32 *  USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM HAS BEEN ADVISED OF
33 *  THE POSSIBILITY OF SUCH DAMAGES; OR (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT
34 *  ACTUALLY PAID FOR THE SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
35 *  LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF ESSENTIAL PURPOSE OF
36 *  ANY LIMITED REMEDY.
37 *
38 * $brcm_Workfile: nexus_recpump.c $
39 * $brcm_Revision: 115 $
40 * $brcm_Date: 11/17/11 10:25a $
41 *
42 * Module Description:
43 *
44 * Revision History:
45 *
46 * $brcm_Log: /nexus/modules/transport/7400/src/nexus_recpump.c $
47 *
48 * 115   11/17/11 10:25a erickson
49 * SW7420-2076: set NEXUS_RecpumpStatus.hasIndex
50 *
51 * 114   11/4/11 4:56p erickson
52 * SW7346-523: fix NEXUS_TransportTimestampType_e32_Mod300
53 *
54 * 113   10/31/11 7:48p bandrews
55 * SW7231-391: merge to main
56 *
57 * SW7420-2078/2   10/28/11 6:52p bandrews
58 * SW7231-391: merge from main
59 *
60 * 112   10/28/11 1:27p erickson
61 * SW7346-523: extend NEXUS_TransportTimestamp to handle 32 bit timestamps
62 *  and to be more explicit about 28/30 bit timestamps
63 *
64 * SW7420-2078/1   10/25/11 5:22p bandrews
65 * SW7231-391: update parser band and timebase implementations to use
66 *  handles everywhere, even for legacy enum usage
67 *
68 * 111   10/6/11 6:05p jtna
69 * SW7425-1218: use new BXPT_Rave_AllocCx() to alloc rave contexts
70 *
71 * 110   9/8/11 12:17p jtna
72 * SW7425-1218: add NEXUS_RecpumpOpenSettings.data/index.heap
73 *
74 * 109   8/25/11 3:29p erickson
75 * SW7346-454: add NEXUS_RecpumpStatus.rave.index
76 *
77 * 108   7/7/11 4:45p erickson
78 * SW7346-275: add NEXUS_RecpumpSettings.timestamp.parityCheckDisable
79 *
80 * 107   6/16/11 2:22p erickson
81 * SW7420-1148: cannot auto-cleanup pid channels in recpump because of
82 *  object database auto-cleanup
83 *
84 * 106   5/27/11 2:58p erickson
85 * SW7346-203: allow configuration of 4 start code ranges for
86 *  NEXUS_PidType_eOther indexing
87 *
88 * 105   5/13/11 2:06p erickson
89 * SW7335-957: add API for BXPT_Rave_SetTpitEcms
90 *
91 * 104   5/12/11 3:42p jtna
92 * SW7550-739: replace all instances of 'NEXUS_HAS_DMA &&
93 *  NEXUS_HAS_SECURITY' with 'NEXUS_ENCRYPTED_DVR_WITH_M2M'. replace some
94 *  instances of 'NEXUS_HAS_DMA' with 'NEXUS_NUM_DMA_CHANNELS'
95 *
96 * 103   3/17/11 1:17p erickson
97 * SW7422-333: rely on #define NEXUS_SVC_MVC_SUPPORT in
98 *  nexus_platform_features.h
99 *
100 * 102   2/7/11 3:36p erickson
101 * SW7335-1036: fix platforms w/o crypto
102 *
103 * 101   2/7/11 2:23p erickson
104 * SW7335-1036: add
105 *  NEXUS_Recpump_GetDataBufferWithWrap/NEXUS_Recpump_GetIndexBufferWithWr
106 *  ap
107 *
108 * 100   2/7/11 10:42a erickson
109 * SW7342-333: add NEXUS_NUM_TPIT_PIDS
110 *
111 * 99   1/20/11 2:15p erickson
112 * SW7420-1392: add NEXUS_RecpumpOpenSettings.useSecureHeap
113 *
114 * 98   1/18/11 5:25p vsilyaev
115 * SW7420-1113: Improved handling of NEXUS_RecpumpFlowControl
116 *
117 * 97   1/18/11 3:47p vsilyaev
118 * SW7422-115: Used BXPT_Rave_IndexerSettings.SvcMvcEn
119 *
120 * 96   1/10/11 6:45p randyjew
121 * SW7420-1113: for NEXUS_RecpumpFlowControl_eAuto , change true to false.
122 *  that should restore behavior.
123 *
124 * 95   1/5/11 1:43p vsilyaev
125 * SW7420-1113: Added 'Auto' option for bandHoldEn, enables flow control
126 *  if recpump is sourced by a playpump
127 *
128 * 94   1/5/11 12:33p vsilyaev
129 * SW7422-115: Enable 12 byte record for H.264 SVC/MVC video
130 *
131 * 93   12/28/10 5:42p vsilyaev
132 * SW7425-39: Expect that PidChannel's is internally packetized to MPEG-2
133 *  TS
134 *
135 * 92   12/16/10 5:13p erickson
136 * SW7422-151: add NEXUS_RecpumpAddPidChannelSettings.useRPipe
137 *
138 * 91   12/9/10 3:32p erickson
139 * SW7420-1308: use unconditional nexus_dma_types.h in the public API
140 *
141 * 90   11/16/10 4:56p vsilyaev
142 * SW7422-14: Fixed startcode detection for multiple pids
143 *
144 * 89   11/15/10 11:37a erickson
145 * SW7335-936: I've eliminated the BDBG_ERR. it is normal behavior. I also
146 *  eliminated the BDBG_MSG which made it look as if something was
147 *  partially wrong. there is a simple and harmless race between XPT
148 *  hitting the threshold and Nexus completing data.
149 *
150 * 88   11/2/10 11:31a erickson
151 * SW7405-4982: fix dataReadyThreshold comparison. improve debug
152 *  throughout.
153 *
154 * 87   10/28/10 5:17p erickson
155 * SW7125-667: only request 9 bytes of payload if
156 *  BXPT_HAS_STARTCODE_BUFFER_WORKAROUND is defined
157 *
158 * 86   10/28/10 5:09p erickson
159 * SW7422-20: adapt to new XPT PI (backward compat using magnum and nexus
160 *  macros)
161 *
162 * 85   10/11/10 5:03p erickson
163 * SW7420-1113: added NEXUS_RecpumpSettings.bandHold
164 *
165 * 84   10/5/10 5:24p erickson
166 * SW7420-1113: set lower thresholds to non-zero if rec_cfg.BandHoldEn set
167 *
168 * 83   10/1/10 9:51a erickson
169 * SW7420-1009: support NEXUS_ANY_ID
170 *
171 * 82   9/24/10 1:23p erickson
172 * SW7420-1113: check that all pid channels are or aren't playback. add
173 *  band hold logic, but leave it disabled with a usage comment.
174 *
175 * 81   9/13/10 5:11p erickson
176 * SW7125-632: add SCD 0x00 for MPEG if BXPT_HAS_AVS system
177 *
178 * 80   8/10/10 4:08p erickson
179 * SW7420-934: rename NEXUS_Recpump_DataWriteComplete/IndexWriteComplete
180 *  to NEXUS_Recpump_DataReadComplete/IndexReadComplete
181 *
182 * 79   8/6/10 9:58a erickson
183 * SW7400-2858: added NEXUS_RecpumpSettings.data.useBufferSize
184 *
185 * 78   7/27/10 10:24a erickson
186 * SW7342-234: fix NEXUS_HAS_DMA && NEXUS_HAS_SECURITY
187 *
188 * 77   6/21/10 4:32p erickson
189 * SW7405-4249: added index option for NEXUS_PidType_eOther for indexing
190 *  audio-only or scrambled streams
191 *
192 * 76   6/10/10 10:55p erickson
193 * SW7550-398: fix warning
194 *
195 * 75   6/7/10 6:23p mphillip
196 * SW7550-398: Update examples and transport code to support non-DMA
197 *  encrypted PVR
198 *
199 * 74   6/3/10 1:55p erickson
200 * SW3548-2939: fix warning if no security
201 *
202 * 73   5/28/10 2:06p vishk
203 * SW7405-3896: re-code nexus_recpump.c to use internal linked list
204 *  instead of an array of size NEXUS_TOTAL_RECPUMP_PIDCHANNELS
205 *
206 * 72   5/27/10 6:22p VISHK
207 * SW7405-3896: re-code nexus_recpump.c to use internal linked list
208 *  instead of an array of size NEXUS_TOTAL_RECPUMP_PIDCHANNELS
209 *
210 * 71   5/27/10 6:20p VISHK
211 * SW7405-3896: re-code nexus_recpump.c to use internal linked list
212 *  instead of an array of size NEXUS_TOTAL_RECPUMP_PIDCHANNELS
213 *
214 * 70   5/27/10 3:09p VISHK
215 * SW7405-3896: re-code nexus_recpump.c to use internal linked list
216 *  instead of an array of size NEXUS_TOTAL_RECPUMP_PIDCHANNELS
217 *
218 * 69   5/26/10 4:10p VISHK
219 * SW7405-3896: re-code nexus_recpump.c to use internal linked list
220 *  instead of an array of size NEXUS_TOTAL_RECPUMP_PIDCHANNELS
221 *
222 * 68   5/18/10 3:39p mphillip
223 * SW7550-398: Allow ES data to be read back as TS data
224 *
225 * 67   5/13/10 3:05p vishk
226 * SW7405-3896: re-code nexus_recpump.c to use internal linked list
227 *  instead of an array of size NEXUS_TOTAL_RECPUMP_PIDCHANNELS
228 *
229 * 66   4/30/10 11:46a erickson
230 * SW7405-4105: RAVE can now deliver all 8 bytes of payload following SC.
231 *  Set EsCount appropriately.
232 *
233 * 65   4/16/10 11:30a erickson
234 * SW3548-2891: fix NEXUS_Recpump_Close logic
235 *
236 * 64   4/14/10 12:30p erickson
237 * SW7550-372: if NEXUS_RAVE_MEMC_BLOCK_SIZE is large, we may need to
238 *  decrement by more than one atomSize or packetSize to fit within bounds
239 *
240 * 63   2/15/10 1:19p rjain
241 * SW7550-243: Increasing NEXUS_TOTAL_RECPUMP_PIDCHANNELS to 64
242 *
243 * 62   2/10/10 10:51a erickson
244 * SW7335-671: use BXPT_RAVE_WRAP_THRESH
245 *
246 * 61   1/27/10 4:02p erickson
247 * SW7400-2664: added NEXUS_RecpumpSettings.tpit options
248 *
249 * 60   1/20/10 5:15p erickson
250 * SW7550-159: distinguish between NEXUS_RAVE_MEMC_BLOCK_SIZE of 256 bytes
251 *  and NEXUS_RAVE_THRESHOLD_UNITS which may not be 256 bytes. neither are
252 *  related to XC packet size (which is 200). allow a dataReadyThreshold
253 *  below 512 bytes. this allows apps to get interrupts for one packet.
254 *  temporarily force CdbUpperThreshold and ItbUpperThreshold to be at
255 *  least 1. 0 should work.
256 *
257 * 59   1/8/10 10:11a erickson
258 * SW7400-2645: refactored TPIT filter api for greater flexibility and
259 *  better use of HW. one TPIT indexer used per recpump. filters can be
260 *  set/reset to pid channels, whether recpump is started or stopped.
261 *
262 * 58   12/29/09 12:51p erickson
263 * SW7550-146: allow security module to be initialized after the transport
264 *  module if HW requires it
265 *
266 * 57   12/2/09 2:28p erickson
267 * SW7400-2625: moved tpit indexer code to handle non-ts transport types
268 *
269 * 56   11/16/09 1:53p erickson
270 * CDSTRMANA-294: allow capture of start codes that are not slices for
271 *  MPEG streams
272 *
273 * 55   11/9/09 5:07p erickson
274 * SW7405-3354: added NEXUS_RecpumpSettings.securityDmaDataFormat, default
275 *  to NEXUS_DmaDataFormat_eMpeg
276 *
277 * 54   11/6/09 9:54a erickson
278 * SW7550-60: fix logic for MpegMode and DSS
279 *
280 * 53   11/3/09 10:59a erickson
281 * SW7550-60: add NEXUS_RecpumpSettings.outputTransportType for PES and ES
282 *  record support
283 *
284 * 52   10/12/09 3:13p erickson
285 * SW7335-587: allow NEXUS_Recpump_GetStatus to return all status fields,
286 *  even if not started or no index
287 *
288 * 51   8/17/09 10:54a erickson
289 * PR56657: move BXPT_Rave_NullifyVCT. fix no-index records.
290 *
291 * 50   7/16/09 12:43p erickson
292 * PR56657: added NEXUS_RecpumpOpenSettings.nullifyVct
293 *
294 * 49   6/24/09 5:48p katrep
295 * PR56058: Compiler warning
296 *
297 * 48   6/23/09 8:49a erickson
298 * PR56058: test dataReadyThreshold before firing dataReady callback, with
299 *  an exception for wrap-around.
300 *
301 * 47   6/9/09 3:09p jtna
302 * PR55767: refactor timestamp record
303 *
304 * 46   6/9/09 10:54a erickson
305 * PR55843: added NEXUS_RecpumpStatus.data.bufferBase and
306 *  .index.bufferBase
307 *
308 * 45   5/29/09 3:05p erickson
309 * PR54002: rework TPIT api to support simultaneous SCD indexing and TPIT
310 *  filtering on the same pid
311 *
312 * 44   5/4/09 4:36p erickson
313 * PR54770: fix warnings
314 *
315 * 43   4/14/09 2:30p erickson
316 * PR54002: added tpit filtering mode
317 *
318 * 42   3/30/09 10:35a erickson
319 * PR50748: support the secure heap using module settings handle
320 *
321 * 41   3/20/09 1:35p erickson
322 * PR53466: add proper checks in NEXUS_Recpump_Close for possible failed
323 *  NEXUS_Recpump_Open
324 *
325 * 40   2/23/09 10:41a erickson
326 * PR52366: set NEXUS_RecpumpStatus.index.bytesRecorded
327 *
328 * 39   1/16/09 4:58p erickson
329 * PR50099: backing out incorrect workaround
330 *
331 * 38   1/12/09 2:39p erickson
332 * PR50099: re-enable the index upper thres isr as a workaround
333 *
334 * 37   1/8/09 12:48a erickson
335 * PR50882: r->indexing must be set to true or false for each call to
336 *  Start
337 *
338 * 36   12/18/08 3:05p jtna
339 * PR50083: remove unnecessary code
340 *
341 * 35   12/18/08 2:44a erickson
342 * PR50347: index-only record uses BXPT_RaveSoftMode_eIndexOnlyRecord mode
343 *
344 * 34   12/17/08 2:34p erickson
345 * PR50461: modify atomSize restriction on the last GetBuffer
346 *
347 * 33   12/17/08 1:39p erickson
348 * PR50461: lift atomSize restriction on the last GetBuffer. this allows
349 *  all data to be recorded.
350 *
351 * 32   12/17/08 12:04a erickson
352 * PR50347: added NEXUS_RecpumpOpenSettings.dummyRecpump for conserving
353 *  memory on index-only record
354 *
355 * 31   12/1/08 12:48p erickson
356 * PR49676: retrieve transportType and timestampType correctly for
357 *  playback pid channels
358 *
359 * 30   10/29/08 11:59a erickson
360 * PR48471: fix AVS ScRange assignment
361 *
362 * 29   10/22/08 11:39a erickson
363 * PR48216: allow transport to run with no dma or security modules
364 *
365 * 28   10/17/08 3:23p katrep
366 * PR48011: Add support to generate index using pid value during all pass
367 *  record.
368 *
369 * 27   10/13/08 11:55a erickson
370 * PR47572: ensure that CDB and ITB depth is always <= size. if not,
371 *  assert on GetBuffer and cause GetStatus to fail.
372 *
373 * 26   8/27/08 11:55a katrep
374 * PR45674: Fixed compile error
375 *
376 * 25   8/27/08 11:46a katrep
377 * PR45674: Fixed the compiler error in 64MB mode.
378 *
379 * 24   8/14/08 5:25p katrep
380 * PR45674: Fix compiiler warning in kernel mode non debug builds
381 *
382 * 23   7/18/08 10:20a erickson
383 * PR44919: fix warnings
384 *
385 * 22   7/17/08 4:17p erickson
386 * PR44919: allow NEXUS_NUM_RECPUMPS == 0
387 *
388 * 21   7/2/08 2:54p erickson
389 * PR41619: NEXUS_Recpump_GetBuffer should limit reported size based on
390 *  atomSize, not dataReadyThreshold
391 *
392 * 20   7/1/08 8:02p katrep
393 * PR44478: Improper adjustment of data ready threshold caused the DSS
394 *  recording to get stuck.
395 *
396 * 19   6/26/08 9:18p vsilyaev
397 * PR 41869: Fixed data-flow for the PVR encryption
398 *
399 * 18   6/26/08 3:18p vsilyaev
400 * PR 41869: Added encryption for DMA
401 *
402 * 17   6/25/08 5:50p vsilyaev
403 * PR 41869: Use keySlotHandle instead of keySlot[Number]
404 *
405 * 16   5/28/08 11:00a erickson
406 * PR34925: fix warning
407 *
408 * 15   5/16/08 11:24a vsilyaev
409 * PR 41869: Removed unnecessary debug output
410 *
411 * 14   5/14/08 5:17p vsilyaev
412 * PR 41869: Added DMA to support stream encryption
413 *
414 * 13   4/18/08 4:03p vsilyaev
415 * PR 41868: Added security API to playpump and recpump
416 *
417 * 12   4/16/08 10:03a erickson
418 * PR41865: allow NEXUS_RecpumpOpenSettings.data.atomSize of 0. explain
419 *  +68 more in default bufferSize.
420 *
421 * 11   4/11/08 9:53a erickson
422 * PR41246: convert BDBG_OBJECT_UNSET to BDBG_OBJECT_DESTROY if freeing
423 *  memory
424 *
425 * 10   4/7/08 11:35a jgarrett
426 * PR 41362: Resolving stop with no pid channels added
427 *
428 * 9   3/31/08 1:12p erickson
429 * PR41075: added BDBG_OBJECT
430 *
431 * 8   3/12/08 2:31p katrep
432 * PR40514:Add support for AVS record
433 *
434 * 7   3/6/08 3:08p erickson
435 * PR40103: convert to NEXUS_TaskCallback
436 *
437 * 6   2/25/08 11:31a erickson
438 * PR39750: remove bad assert
439 *
440 * 5   2/22/08 10:51a erickson
441 * PR39862: add timestamp for buffer calc
442 *
443 * 4   2/8/08 12:02p vsilyaev
444 * PR 38682: Fixed warning
445 *
446 * 3   2/7/08 10:20a erickson
447 * PR39384: added recpump dataReadyThreshold and atomSize. clarified
448 *  dataReadyCallback behavior.
449 *
450 * 2   1/22/08 9:49a erickson
451 * PR34925: remove numDescriptors. re-add code to flush ITB on ITB
452 * overflow.
453 *
454 * 1   1/18/08 2:20p jgarrett
455 * PR 38808: Merging to main branch
456 *
457 **************************************************************************/
458#include "nexus_transport_module.h"
459#include "priv/nexus_core.h"
460#if NEXUS_ENCRYPTED_DVR_WITH_M2M
461#include "nexus_dma.h"
462#include "priv/nexus_dma_priv.h"
463#endif
464#if NEXUS_HAS_SECURITY
465#include "nexus_security.h"
466#endif
467
468/*
469security & dma options
4701) NEXUS_ENCRYPTED_DVR_WITH_M2M - nexus uses M2M DMA to decrypt
4712) otherwise - nexus uses keyslots to decrypt
472There is no current option for NEXUS_HAS_DMA-only or internal hooks for SW-based decrypt (ala playpump external crypto)
473*/
474
475BDBG_MODULE(nexus_recpump);
476
477#define BDBG_MSG_TRACE(x)   /* BDBG_MSG(x) */
478
479struct NEXUS_RecpumpFlow {
480    bool pending; /* if true, then a callback has been sent and a complete is pending */
481    NEXUS_RecpumpHandle recpump; /* link back to parent */
482    BINT_CallbackHandle irq;
483    BKNI_EventHandle event;
484    NEXUS_EventCallbackHandle eventHandle;
485    NEXUS_TaskCallbackHandle dataReadyCallback, overflowCallback;
486    size_t bufferSize;
487    void *bufferBase;
488    unsigned lastGetBuffer; /* remember total size (size + size2) returned by last GetBuffer. this validates the WriteComplete call. */
489    unsigned dataReadyThreshold; /* copy from Settings for use in flow */
490    unsigned atomSize; /* copy from Settings for use in flow */
491    uint64_t bytesRecorded;
492};
493
494#define NEXUS_P_FLOW_NAME(flow) ((flow)==&(flow)->recpump->data ? "CDB" : "ITB")
495#define NEXUS_TOTAL_RECPUMP_PIDCHANNELS 64
496
497/* XPT RAVE is configured with a fixed size for wrapping */
498#define NEXUS_RAVE_MEMC_BLOCK_SIZE BXPT_RAVE_WRAP_THRESH
499
500BDBG_OBJECT_ID(NEXUS_Recpump);
501
502typedef struct NEXUS_Recpump_P_PidChannel {
503    struct {
504        bool enabled;
505        NEXUS_RecpumpTpitFilter filter;
506        unsigned index;
507    } tpit;
508    NEXUS_RecpumpAddPidChannelSettings settings;
509    NEXUS_PidChannelHandle  pidChn;
510    BLST_S_ENTRY(NEXUS_Recpump_P_PidChannel) link;
511    unsigned playback;
512} NEXUS_Recpump_P_PidChannel;
513
514struct NEXUS_Recpump {
515    BDBG_OBJECT(NEXUS_Recpump)
516    unsigned tindex; /* index of pTransport->recpump[] */
517    NEXUS_RecpumpOpenSettings openSettings;
518    NEXUS_RecpumpSettings settings;
519    BLST_S_HEAD(NEXUS_Recpump_P_PidChannels, NEXUS_Recpump_P_PidChannel) pid_list;
520    bool indexing; /* was indexing started? */
521    unsigned pidChannelCnt; /* total number of pid channels added */
522    BXPT_RaveIdx_Handle tpitIdx;
523    unsigned tpitCount;
524    BXPT_RaveIdx_Handle scdIdx;
525    unsigned scdPidCount;
526    bool playback;
527
528    NEXUS_TransportType inputTransportType;
529
530    BXPT_RaveCx_Handle rave_rec;
531    unsigned rave_rec_index;
532    BXPT_RaveCx_Handle extra_rave_rec;
533    struct { /* buffer pointers if recpump does its own alloc */
534        void *data;
535        void *index;
536    } rave_rec_mem, extra_rave_rec_mem;
537   
538    struct NEXUS_RecpumpFlow data, index;
539    enum {
540        Ready,
541        Done,   /* besttop_recpump_stop has been recognized and we're exiting */
542        Terminated  /* abnormal termination */
543    } rave_state;
544    bool started; /* true if Start was called */
545    bool actuallyStarted; /* true if actually started - which requires Start to be called and at least one pid channel */
546    bool dataStopped; /* true if StopData was called. sets to false on start */
547#if NEXUS_ENCRYPTED_DVR_WITH_M2M
548    bool cryptoActive; /* true if data encryption is required */
549    /*
550     * if crypto active there is also stagging area in the FIFO - area where data is recored but not yet encrypted
551     *      |---------|++++++++|==========|~~~~~~~~~~~~|-------------|
552     *   FifoStart  CdbRead  CryptoTail CryptoHead CdbWrite    FifoEnd(Wrap)
553     *   Legend:
554     *     '-' - no data
555     *     '+' - recorded and encrypted data (could be consumed by an application)
556     *     '=' - recorded that currently being encrypted
557     *     '~' - recorded that is not yet encrypted
558     *
559     *      Wrap of encrypted data
560     *      |++++++++|==========|~~~~~~~~~~~~|-------------|+++++++++++++++|
561     *   FifoStart CryptoTail CryptoHead CdbWrite        CdbRead      FifoEnd(Wrap)
562     *
563     *      Wrap of data to encrypt
564     *      |========|~~~~~~~~~~~~|-------------|++++++++++++++|===========|
565     *   FifoStart CryptoHead CdbWrite        CdbRead      CryptoTail   FifoEnd(Wrap)
566     */
567    struct {
568        void *head, *tail; /* tail ... head -> distance of currently outstanding DMA transcaction, it could wrap over the buffer boundary, tail==head  means no DMA outstanding */
569        NEXUS_DmaJobBlockSettings blocks[2];
570        NEXUS_DmaJobHandle job; /* job is only created when crypto started */
571        size_t packetSize;
572        BKNI_EventHandle event;
573        NEXUS_EventCallbackHandle callback;
574    } crypto;
575#endif
576};
577
578
579static NEXUS_Error NEXUS_Recpump_P_Start(NEXUS_RecpumpHandle r);
580static NEXUS_Error NEXUS_Recpump_P_StartFlow(struct NEXUS_RecpumpFlow *flow);
581static void        NEXUS_Recpump_P_StopFlow(struct NEXUS_RecpumpFlow *flow);
582static bool        NEXUS_Recpump_P_TestDataReadyCallback(struct NEXUS_RecpumpFlow *flow);
583
584#define NEXUS_RECPUMP_PID_IS_INDEX(PSETTINGS) \
585    ( (((PSETTINGS)->pidType == NEXUS_PidType_eVideo) && ((PSETTINGS)->pidTypeSettings.video.index)) || \
586      (((PSETTINGS)->pidType == NEXUS_PidType_eOther) && ((PSETTINGS)->pidTypeSettings.other.index)) \
587    )
588
589#define B_MAX(x,y) (((x)>=(y))?(x):(y))
590
591void NEXUS_Recpump_GetDefaultOpenSettings(NEXUS_RecpumpOpenSettings *pSettings)
592{
593    BKNI_Memset(pSettings, 0, sizeof(*pSettings));
594
595    /* The default bufferSize is based on the least common mulitple of a 188 byte transport packet and 4096 atomSize (for O_DIRECT file i/o).
596    Then, multiply by 12 to get 12 of these LCM's. That's the default buffer.
597    Finally, add 68 in order to anticipate the NEXUS_RAVE_MEMC_BLOCK_SIZE replacement logic in NEXUS_Recpump_P_Start. 256-188 = 68. This is not a crucial step. We could have chosen
598    to not add it, but it would have meant that the final buffer would be less than 12 LCM's after the NEXUS_RAVE_MEMC_BLOCK_SIZE replacement logic. */
599    pSettings->data.bufferSize = ((188/4)*4096*12) + 68;
600    pSettings->data.alignment = 12; /* 4K alignment */
601    pSettings->data.dataReadyThreshold = (188/4)*4096; /* threshold is the least common mulitple of a 188 byte transport packet and 4096 atomSize */
602    pSettings->data.atomSize = 4096; /* typical value for disk direct I/O */
603
604    /* 6*4 is a size of the single 6-word SCT entry. 16 SCT's per atom. index.bufferSize must be multiple of this. */
605    pSettings->index.bufferSize = 6*4*16*48;
606    pSettings->index.alignment = 7; /* 128-Byte alignment */
607    pSettings->index.dataReadyThreshold = 1024;
608    pSettings->index.atomSize = 0; /* typically not needed. index write benefits from stdio buffering. */
609}
610
611void NEXUS_Recpump_GetDefaultSettings( NEXUS_RecpumpSettings *pSettings)
612{
613    BKNI_Memset(pSettings, 0, sizeof(*pSettings));
614    NEXUS_CallbackDesc_Init(&pSettings->data.dataReady);
615    NEXUS_CallbackDesc_Init(&pSettings->data.overflow);
616    NEXUS_CallbackDesc_Init(&pSettings->index.dataReady);
617    NEXUS_CallbackDesc_Init(&pSettings->index.overflow);
618#if NEXUS_ENCRYPTED_DVR_WITH_M2M
619    pSettings->securityDmaDataFormat = NEXUS_DmaDataFormat_eMpeg;
620#endif
621    pSettings->outputTransportType = NEXUS_TransportType_eTs;
622    pSettings->bandHold = NEXUS_RecpumpFlowControl_eAuto;
623    return;
624}
625
626#if NEXUS_NUM_RECPUMPS
627#if NEXUS_ENCRYPTED_DVR_WITH_M2M
628static void
629NEXUS_Recpump_P_DmaCallback(void *context)
630{
631    NEXUS_RecpumpHandle pump=context;
632    BDBG_OBJECT_ASSERT(pump, NEXUS_Recpump);
633    if(pump->crypto.tail != pump->crypto.head) { /*  DMA was pending */
634        bool pending = pump->data.pending;
635        BDBG_MSG(("NEXUS_Recpump_P_DmaCallback:%#lx DMA completed (%#lx:%#lx) %s", (unsigned long)pump, (unsigned long)pump->crypto.tail, (unsigned long)pump->crypto.head, pending?"":"Waiting For Data"));
636        pump->crypto.tail = pump->crypto.head;
637        if(!NEXUS_Recpump_P_TestDataReadyCallback(&pump->data) && !pending ) {
638            BDBG_MSG(("dma complete but there is no data in the record buffer"));
639        }
640    }
641    return;
642}
643#endif
644
645static void
646NEXUS_Recpump_isr(void *flow_, int parm2 )
647{
648    struct NEXUS_RecpumpFlow *flow = flow_;
649    BSTD_UNUSED(parm2);
650    BKNI_SetEvent(flow->event);
651}
652#endif
653
654/* if the app specifies a heap, then nexus does the alloc. if not, xpt does the alloc */
655static NEXUS_Error
656NEXUS_Recpump_P_AllocContextMem(BXPT_Rave_AllocCxSettings *allocSettings, const NEXUS_RecpumpOpenSettings *pSettings)
657{
658    NEXUS_Error rc;
659    BMEM_Heap_Handle mem_heap;
660 
661    if (pSettings->data.heap && pSettings->data.bufferSize) {
662        if (pSettings->useSecureHeap) { return BERR_TRACE(NEXUS_INVALID_PARAMETER); }
663       
664        mem_heap = NEXUS_Heap_GetMemHandle(pSettings->data.heap);
665        allocSettings->CdbBuffer = BMEM_Heap_AllocAligned(mem_heap, pSettings->data.bufferSize, pSettings->data.alignment, 0);
666        if (!allocSettings->CdbBuffer) { rc=BERR_TRACE(BERR_OUT_OF_DEVICE_MEMORY); return rc; }
667        BDBG_MSG(("alloc cdb buffer %p", allocSettings->CdbBuffer));
668    }
669    if (pSettings->index.heap && pSettings->index.bufferSize) {
670        if (pSettings->useSecureHeap) { return BERR_TRACE(NEXUS_INVALID_PARAMETER); }
671
672        mem_heap = NEXUS_Heap_GetMemHandle(pSettings->index.heap);
673        allocSettings->ItbBuffer = BMEM_Heap_AllocAligned(mem_heap, pSettings->index.bufferSize, pSettings->index.alignment, 0);
674        if (!allocSettings->ItbBuffer) { rc=BERR_TRACE(BERR_OUT_OF_DEVICE_MEMORY); return rc; }
675        BDBG_MSG(("alloc itb buffer %p", allocSettings->ItbBuffer));
676    }
677
678    return NEXUS_SUCCESS;
679}
680
681NEXUS_RecpumpHandle NEXUS_Recpump_Open(unsigned index, const NEXUS_RecpumpOpenSettings *pSettings)
682{
683#if NEXUS_NUM_RECPUMPS
684    NEXUS_Error rc = 0;
685    BXPT_Rave_AllocCxSettings allocSettings;
686    BINT_Id int_id;
687    NEXUS_RecpumpHandle r;
688    NEXUS_RecpumpOpenSettings settings;
689
690    if (index == NEXUS_ANY_ID) {
691        unsigned i;
692        for (i=0;i<NEXUS_NUM_RECPUMPS;i++) {
693            if (!pTransport->recpump[i]) {
694                index = i;
695                break;
696            }
697        }
698        if (i == NEXUS_NUM_RECPUMPS) {
699            rc = BERR_TRACE(NEXUS_NOT_AVAILABLE);
700            BDBG_ERR(("no recpump not available"));
701            return NULL;
702        }
703    }
704
705    if (index >= NEXUS_NUM_RECPUMPS) {
706        BDBG_ERR(("recpump %d not supported", index));
707        return NULL;
708    }
709    if (pTransport->recpump[index]) {
710        BDBG_ERR(("recpump %d already open", index));
711        return NULL;
712    }
713
714    if (!pSettings) {
715        NEXUS_Recpump_GetDefaultOpenSettings(&settings);
716        pSettings = &settings;
717    }
718
719    BDBG_MSG(("NEXUS_Recpump_Open %d: cdb=%d (%d threshold), itb=%d (%d threshold)",
720        index,
721        pSettings->data.bufferSize, pSettings->data.dataReadyThreshold,
722        pSettings->index.bufferSize, pSettings->index.dataReadyThreshold));
723
724    /* Ensure required numbers */
725    if (pSettings->data.bufferSize < NEXUS_RAVE_MEMC_BLOCK_SIZE*2) {
726        BDBG_ERR(("data.bufferSize %d invalid", pSettings->data.bufferSize));
727        return NULL;
728    }
729    if (pSettings->data.dataReadyThreshold > pSettings->data.bufferSize) {
730        BDBG_ERR(("data.dataReadyThreshold %d invalid", pSettings->data.dataReadyThreshold));
731        return NULL;
732    }
733    /* index.bufferSize can be 0. Otherwise, it must be valid. */
734    if (pSettings->index.bufferSize) {
735        if (pSettings->index.bufferSize < NEXUS_RAVE_MEMC_BLOCK_SIZE*2) {
736            BDBG_ERR(("index.bufferSize %d invalid", pSettings->index.bufferSize));
737            return NULL;
738        }
739        if (pSettings->index.dataReadyThreshold > pSettings->index.bufferSize) {
740            BDBG_ERR(("index.dataReadyThreshold %d invalid", pSettings->index.dataReadyThreshold));
741            return NULL;
742        }
743    }
744
745    /* Warn on dangerous numbers */
746    if (pSettings->data.dataReadyThreshold * 100 / pSettings->data.bufferSize > 50) {
747        BDBG_WRN(("data.dataReadyThreshold is very large. Overflow likely."));
748    }
749    if (pSettings->index.bufferSize && pSettings->index.dataReadyThreshold * 100 / pSettings->index.bufferSize > 50) {
750        BDBG_WRN(("index.dataReadyThreshold is very large. Overflow likely."));
751    }
752
753    r = (NEXUS_RecpumpHandle)BKNI_Malloc(sizeof(*r));
754    if (!r) {
755        rc=BERR_TRACE(NEXUS_OUT_OF_SYSTEM_MEMORY);
756        return NULL;
757    }
758    pTransport->recpump[index] = r;
759    BKNI_Memset(r, 0, sizeof(*r));
760    BDBG_OBJECT_SET(r, NEXUS_Recpump);
761    r->tindex = index;
762    r->openSettings = *pSettings;
763    r->inputTransportType = NEXUS_TransportType_eTs;
764    r->scdIdx = NULL;
765    r->scdPidCount = 0;
766    NEXUS_Recpump_GetDefaultSettings(&r->settings);
767
768    BXPT_Rave_GetDefaultAllocCxSettings(&allocSettings);
769    allocSettings.CdbBuffer = NULL;
770    allocSettings.ItbBuffer = NULL;
771    allocSettings.BufferCfg.Cdb.Length = pSettings->data.bufferSize;
772    allocSettings.BufferCfg.Itb.Length = pSettings->index.bufferSize;
773    allocSettings.BufferCfg.Cdb.Alignment = pSettings->data.alignment;
774    allocSettings.BufferCfg.Itb.Alignment = pSettings->index.alignment;
775
776    /* Program ITB to big endian, CDB to host endianness.
777    When reading from memory, either DMA or CPU, the memory controller will swap on a little endian system. So, on a little
778    endian system, the end result will be ITB little, CDB big. On a big endian system, there is no memory controller swap,
779    therefore the end result will be ITB big, CDB big. Therefore, the end result is: ITB host, CDB big.
780    This is exactly what we want. It's just a little counter intuititive when programming transport here. */
781    allocSettings.BufferCfg.Itb.LittleEndian = false;
782#if (BSTD_CPU_ENDIAN == BSTD_ENDIAN_LITTLE)
783    allocSettings.BufferCfg.Cdb.LittleEndian = true;
784#else
785    allocSettings.BufferCfg.Cdb.LittleEndian = false;
786#endif
787
788    if (pSettings->dummyRecpump) {
789        /* alloc soft context for ITB-only record. CDB of dummyRecpump will be used as bit bucket. */
790        allocSettings.SoftRaveMode = BXPT_RaveSoftMode_eIndexOnlyRecord;
791        allocSettings.SoftRaveSrcCx = pSettings->dummyRecpump->rave_rec;
792        if (pSettings->data.heap && pSettings->data.bufferSize != 0) {
793            /* if CDB is bit bucket, user should not be allocating memory for it. */
794            rc = BERR_TRACE(NEXUS_INVALID_PARAMETER); goto error;
795        }
796        rc = NEXUS_Recpump_P_AllocContextMem(&allocSettings, pSettings);
797        if (rc) { goto error; }
798
799        r->rave_rec_mem.data = allocSettings.CdbBuffer;
800        r->rave_rec_mem.index = allocSettings.ItbBuffer;
801       
802        rc = BXPT_Rave_AllocCx(pTransport->rave[0].channel, &allocSettings, &r->rave_rec);
803        if (rc) { rc=BERR_TRACE(rc); goto error; }
804    }
805    else {
806        allocSettings.RequestedType = pSettings->useSecureHeap?BXPT_RaveCx_eRecordR:BXPT_RaveCx_eRecord;
807        allocSettings.SoftRaveSrcCx = NULL;
808        rc = NEXUS_Recpump_P_AllocContextMem(&allocSettings, pSettings);
809        if (rc) { goto error; }
810
811        r->rave_rec_mem.data = allocSettings.CdbBuffer;
812        r->rave_rec_mem.index = allocSettings.ItbBuffer;
813       
814        rc = BXPT_Rave_AllocCx(pTransport->rave[0].channel, &allocSettings, &r->rave_rec);
815        if (rc) { rc=BERR_TRACE(rc); goto error; }
816    }
817
818    /* nullifyVct is only needed in limited uses. please ask for FAE for more usage information.
819    at build time, you must export BXPT_VCT_SUPPORT=y.
820    set nullifyVct = 0 to disable the feature.
821    set nullifyVct = 1 for TVCT mode.
822    set nullifyVct = 2 for CVCT mode. */
823    if (pSettings->nullifyVct) {
824#ifdef BXPT_VCT_SUPPORT
825        /* an extra, unused RAVE context is allocated immediately after rave_rec so that RAVE FW has extra CXMEM to work with */
826        allocSettings.RequestedType = BXPT_RaveCx_eRecord;
827        allocSettings.SoftRaveSrcCx = NULL;
828        rc = NEXUS_Recpump_P_AllocContextMem(&allocSettings, pSettings);
829        if (rc) { goto error; }
830
831        r->extra_rave_rec_mem.data = allocSettings.CdbBuffer;
832        r->extra_rave_rec_mem.index = allocSettings.ItbBuffer;
833
834        rc = BXPT_Rave_AllocCx(pTransport->rave[0].channel, &allocSettings, &r->rave_rec_extra);
835        if (rc) { rc=BERR_TRACE(rc); goto error; }
836#else
837        rc = BERR_TRACE(NEXUS_INVALID_PARAMETER);
838        goto error;
839#endif
840    }
841
842    /* get bufferBase for data and index buffers */
843    {
844    BAVC_XptContextMap context;
845    unsigned offset;
846    void *temp;
847    rc = BXPT_Rave_GetContextRegisters(r->rave_rec, &context);
848    if (rc) { rc=BERR_TRACE(rc); goto error; }
849   
850    r->rave_rec_index = NEXUS_RAVE_INDEX(context.CDB_Read);
851
852    offset = BREG_Read32(g_pCoreHandles->reg, context.CDB_Base);
853    rc = BMEM_Heap_ConvertOffsetToAddress(g_pCoreHandles->heap[0], offset, &temp);
854    if (rc) { rc=BERR_TRACE(rc); goto error; }
855    rc = BMEM_Heap_ConvertAddressToCached(g_pCoreHandles->heap[0], temp, (void **)&r->data.bufferBase);
856    if (rc) { rc=BERR_TRACE(rc); goto error; }
857
858    if (r->openSettings.index.bufferSize) {
859        offset = BREG_Read32(g_pCoreHandles->reg, context.ITB_Base);
860        rc = BMEM_Heap_ConvertOffsetToAddress(g_pCoreHandles->heap[0], offset, &temp);
861        if (rc) { rc=BERR_TRACE(rc); goto error; }
862        rc = BMEM_Heap_ConvertAddressToCached(g_pCoreHandles->heap[0], temp, (void **)&r->index.bufferBase);
863        if (rc) { rc=BERR_TRACE(rc); goto error; }
864    }
865    }
866
867    rc = BXPT_Rave_GetIntId(r->rave_rec, BXPT_RaveIntName_eCdbUpperThresh, &int_id);
868    if (rc) { rc=BERR_TRACE(rc); goto error; }
869
870    rc = BKNI_CreateEvent(&r->data.event);
871    if (rc) { rc=BERR_TRACE(rc); goto error; }
872
873    rc = BINT_CreateCallback(&r->data.irq, g_pCoreHandles->bint, int_id, NEXUS_Recpump_isr, &r->data, 0);
874    if (rc) { rc=BERR_TRACE(rc); goto error; }
875
876    rc = BINT_EnableCallback(r->data.irq);
877    if (rc) { rc=BERR_TRACE(rc); goto error; }
878
879    rc = BXPT_Rave_GetIntId(r->rave_rec, BXPT_RaveIntName_eItbUpperThresh, &int_id);
880    if (rc) { rc=BERR_TRACE(rc); goto error; }
881
882    rc = BKNI_CreateEvent(&r->index.event);
883    if (rc) { rc=BERR_TRACE(rc); goto error; }
884
885    rc = BINT_CreateCallback(&r->index.irq, g_pCoreHandles->bint, int_id, NEXUS_Recpump_isr, &r->index, 0);
886    if (rc) { rc=BERR_TRACE(rc); goto error; }
887
888    rc = BINT_EnableCallback(r->index.irq);
889    if (rc) { rc=BERR_TRACE(rc); goto error; }
890
891#if NEXUS_ENCRYPTED_DVR_WITH_M2M
892    rc = BKNI_CreateEvent(&r->crypto.event);
893    if(rc!=BERR_SUCCESS) {rc=BERR_TRACE(rc); goto error;}
894
895    r->crypto.callback = NEXUS_RegisterEvent(r->crypto.event, NEXUS_Recpump_P_DmaCallback, r);
896    if(!r->crypto.callback) {rc=BERR_TRACE(BERR_OUT_OF_SYSTEM_MEMORY);goto error;}
897#endif
898
899    r->data.bufferSize = pSettings->data.bufferSize;
900    r->data.dataReadyThreshold = pSettings->data.dataReadyThreshold;
901    r->data.atomSize = pSettings->data.atomSize;
902    /* r->data.atomSize = 0; */
903    r->data.overflowCallback = NEXUS_TaskCallback_Create(r, NULL);
904    r->data.dataReadyCallback = NEXUS_TaskCallback_Create(r, NULL);
905
906    r->index.bufferSize = pSettings->index.bufferSize;
907    r->index.dataReadyThreshold = pSettings->index.dataReadyThreshold;
908    r->index.atomSize = pSettings->index.atomSize;
909    r->index.overflowCallback = NEXUS_TaskCallback_Create(r, NULL);
910    r->index.dataReadyCallback = NEXUS_TaskCallback_Create(r, NULL);
911
912    /* init the callbacks */
913    NEXUS_Recpump_SetSettings(r, &r->settings);
914
915    r->dataStopped = false;
916    r->data.recpump = r;
917    r->index.recpump = r;
918
919    BLST_S_INIT(&r->pid_list);
920    return r;
921
922error:
923    NEXUS_Recpump_Close(r);
924    return NULL;
925#else
926    BSTD_UNUSED(index);
927    BSTD_UNUSED(pSettings);
928    BERR_TRACE(NEXUS_NOT_SUPPORTED);
929    return NULL;
930#endif
931}
932
933void NEXUS_Recpump_Close(NEXUS_RecpumpHandle r)
934{
935#if NEXUS_NUM_RECPUMPS
936    BDBG_OBJECT_ASSERT(r, NEXUS_Recpump);
937    if (r->started) {
938        BDBG_WRN(("Recpump %d not stopped before NEXUS_Recpump_Close", r->tindex));
939        NEXUS_Recpump_Stop(r);
940    }
941    BDBG_ASSERT(!r->started);
942    BDBG_ASSERT(!r->actuallyStarted);
943    if (r->pidChannelCnt)  {
944        BDBG_WRN(("PidChannels not removed before NEXUS_Recpump_Close"));
945        /* cannot call NEXUS_Recpump_RemoveAllPidChannels because objdb auto-cleanup may have closed handles */
946    }
947
948    if (r->rave_rec_mem.data) {
949        BDBG_ASSERT(r->openSettings.data.heap);
950        BMEM_Heap_Free(NEXUS_Heap_GetMemHandle(r->openSettings.data.heap), r->rave_rec_mem.data);
951    }
952    if (r->rave_rec_mem.index) {
953        BDBG_ASSERT(r->openSettings.index.heap);
954        BMEM_Heap_Free(NEXUS_Heap_GetMemHandle(r->openSettings.index.heap), r->rave_rec_mem.index);
955    }
956    if (r->extra_rave_rec_mem.data) {
957        BDBG_ASSERT(r->openSettings.data.heap);
958        BMEM_Heap_Free(NEXUS_Heap_GetMemHandle(r->openSettings.data.heap), r->extra_rave_rec_mem.data);
959    }
960    if (r->extra_rave_rec_mem.index) {
961        BDBG_ASSERT(r->openSettings.index.heap);
962        BMEM_Heap_Free(NEXUS_Heap_GetMemHandle(r->openSettings.index.heap), r->extra_rave_rec_mem.index);
963    }
964
965#if NEXUS_ENCRYPTED_DVR_WITH_M2M
966    if(r->crypto.callback) {
967        NEXUS_UnregisterEvent(r->crypto.callback);
968    }
969    if(r->crypto.event) {
970        BKNI_DestroyEvent(r->crypto.event);
971    }
972#endif
973    if (r->index.irq) {
974        BINT_DestroyCallback(r->index.irq);
975    }
976    if (r->index.event) {
977        BKNI_DestroyEvent(r->index.event);
978    }
979    if (r->data.irq) {
980        BINT_DestroyCallback(r->data.irq);
981    }
982    if (r->data.event) {
983        BKNI_DestroyEvent(r->data.event);
984    }
985    if (r->tpitIdx) {
986        BXPT_Rave_FreeIndexer(r->tpitIdx);
987    }
988    if (r->scdIdx) {
989        BXPT_Rave_FreeIndexer(r->scdIdx);
990    }
991
992    if (r->extra_rave_rec) {
993        BXPT_Rave_FreeContext(r->extra_rave_rec);
994    }
995    if (r->rave_rec) {
996        BXPT_Rave_FreeContext(r->rave_rec);
997    }
998
999    if (r->data.overflowCallback) {
1000        NEXUS_TaskCallback_Destroy(r->data.overflowCallback);
1001    }
1002    if (r->data.dataReadyCallback) {
1003        NEXUS_TaskCallback_Destroy(r->data.dataReadyCallback);
1004    }
1005    if (r->index.overflowCallback) {
1006        NEXUS_TaskCallback_Destroy(r->index.overflowCallback);
1007    }
1008    if (r->index.dataReadyCallback) {
1009        NEXUS_TaskCallback_Destroy(r->index.dataReadyCallback);
1010    }
1011
1012    r->rave_rec = NULL;
1013    pTransport->recpump[r->tindex] = NULL;
1014    BDBG_OBJECT_DESTROY(r, NEXUS_Recpump);
1015    BKNI_Free(r);
1016#else
1017    BSTD_UNUSED(r);
1018#endif
1019}
1020
1021void NEXUS_Recpump_GetSettings(NEXUS_RecpumpHandle r, NEXUS_RecpumpSettings *pSettings)
1022{
1023    BDBG_OBJECT_ASSERT(r, NEXUS_Recpump);
1024    *pSettings = r->settings;
1025}
1026
1027NEXUS_Error NEXUS_Recpump_SetSettings(NEXUS_RecpumpHandle r, const NEXUS_RecpumpSettings *pSettings)
1028{
1029    BDBG_OBJECT_ASSERT(r, NEXUS_Recpump);
1030
1031#if NEXUS_ENCRYPTED_DVR_WITH_M2M
1032    if(r->started &&
1033        (r->settings.securityDma != pSettings->securityDma ||
1034        r->settings.securityContext != pSettings->securityContext)) {
1035        return BERR_TRACE(BERR_NOT_SUPPORTED);
1036    }
1037    if(pSettings->securityContext && !pSettings->securityDma) {
1038        return BERR_TRACE(BERR_INVALID_PARAMETER);
1039    }
1040    if (pSettings->securityContext || pSettings->securityDma) {
1041        if (!pTransport->settings.dma || !pTransport->settings.security) {
1042            BDBG_ERR(("Transport module does not have security and dma module handles."));
1043            return BERR_TRACE(BERR_NOT_SUPPORTED);
1044        }
1045    }
1046#elif NEXUS_HAS_SECURITY
1047    if(r->started &&
1048        (r->settings.securityContext != pSettings->securityContext)) {
1049        return BERR_TRACE(BERR_NOT_SUPPORTED);
1050    }
1051#endif
1052    r->settings = *pSettings;
1053    NEXUS_TaskCallback_Set(r->data.overflowCallback, &r->settings.data.overflow);
1054    NEXUS_TaskCallback_Set(r->data.dataReadyCallback, &r->settings.data.dataReady);
1055    NEXUS_TaskCallback_Set(r->index.overflowCallback, &r->settings.index.overflow);
1056    NEXUS_TaskCallback_Set(r->index.dataReadyCallback, &r->settings.index.dataReady);
1057    return NEXUS_SUCCESS;
1058}
1059
1060static NEXUS_Error NEXUS_Recpump_P_StartPid(NEXUS_RecpumpHandle r, NEXUS_Recpump_P_PidChannel *pid)
1061{
1062    NEXUS_Error rc = 0;
1063
1064    NEXUS_PidChannel_ConsumerStarted(pid->pidChn);
1065
1066#if NEXUS_HAS_SECURITY && (NEXUS_NUM_DMA_CHANNELS==0)
1067    if (r->settings.securityContext) {
1068        /* This applies the same keyslot to all pid channels. If you want per-pid keyslots, app should call NEXUS_Security_AddPidChannelToKeySlot itself. */
1069        rc = NEXUS_Security_AddPidChannelToKeySlot(r->settings.securityContext, pid->pidChn->status.pidChannelIndex);
1070        if (rc) { rc = BERR_TRACE(rc); } /* fall through */
1071    }
1072#else
1073    BSTD_UNUSED(r);
1074#endif
1075    return rc;
1076}
1077
1078static void NEXUS_Recpump_P_StopPid(NEXUS_RecpumpHandle r, NEXUS_Recpump_P_PidChannel *pid)
1079{
1080#if NEXUS_HAS_SECURITY && (NEXUS_NUM_DMA_CHANNELS==0)
1081    if (r->settings.securityContext) {
1082        NEXUS_Error rc;
1083        rc = NEXUS_Security_RemovePidChannelFromKeySlot(r->settings.securityContext, pid->pidChn->status.pidChannelIndex);
1084        if (rc) { rc = BERR_TRACE(rc); } /* fall through */
1085    }
1086#else
1087    BSTD_UNUSED(r);
1088    BSTD_UNUSED(pid);
1089#endif
1090}
1091
1092static unsigned NEXUS_Recpump_P_GetLowThreshold(bool bandHold, unsigned upperThreshold, unsigned atomSize)
1093{
1094    unsigned lowThreshold;
1095    if(bandHold) {
1096        lowThreshold = upperThreshold/2;
1097        atomSize /= NEXUS_RAVE_THRESHOLD_UNITS;
1098        if(lowThreshold<atomSize) {
1099            lowThreshold = atomSize;
1100        }
1101        if(lowThreshold==0) {
1102            lowThreshold = 1;
1103        }
1104    } else {
1105        lowThreshold = 0;
1106    }
1107    BDBG_MSG_TRACE(("upperThreshold %u lowThreshold %u", upperThreshold, lowThreshold));
1108    return lowThreshold;
1109}
1110
1111static NEXUS_Error NEXUS_Recpump_P_Start(NEXUS_RecpumpHandle r)
1112{
1113    BERR_Code rc;
1114    BXPT_Rave_RecordSettings rec_cfg;
1115    const NEXUS_RecpumpSettings *pSettings = &r->settings;
1116    unsigned packetSize, atom;
1117    bool startIndex = false;
1118    bool svcVideo = false;
1119    NEXUS_Recpump_P_PidChannel *pid;
1120    unsigned scdNo;
1121    bool bandHold;
1122
1123    BDBG_OBJECT_ASSERT(r, NEXUS_Recpump);
1124    BDBG_ASSERT(r->started && !r->actuallyStarted);
1125
1126    if (!pSettings->data.dataReady.callback) {
1127        BDBG_ERR(("dataReady.callback is required"));
1128        return BERR_TRACE(NEXUS_INVALID_PARAMETER);
1129    }
1130
1131    r->rave_state = Ready;
1132
1133    /* switching between 188 and 130 requires a Reset, not Flush */
1134    rc = BXPT_Rave_ResetContext(r->rave_rec);
1135    if (rc) {return BERR_TRACE(rc);}
1136
1137#ifdef BXPT_VCT_SUPPORT
1138    if (r->openSettings.nullifyVct) {
1139        rc = BXPT_Rave_NullifyVCT(r->rave_rec, true, r->openSettings.nullifyVct == 1 ? BXPT_RaveVct_Tvct : BXPT_RaveVct_Cvct);
1140        if (rc) {return BERR_TRACE(rc);}
1141    }
1142#endif
1143
1144    rc = BXPT_Rave_GetRecordConfig(r->rave_rec, &rec_cfg);
1145    if (rc) {return BERR_TRACE(rc);}
1146
1147    switch (r->inputTransportType) {
1148    case NEXUS_TransportType_eTs:
1149    case NEXUS_TransportType_eDssEs:
1150    case NEXUS_TransportType_eDssPes:
1151        /* all outputs possible */
1152        break;
1153    case NEXUS_TransportType_eMpeg2Pes:
1154        if (r->settings.outputTransportType != NEXUS_TransportType_eMpeg2Pes &&
1155            r->settings.outputTransportType != NEXUS_TransportType_eEs)
1156        {
1157            BDBG_ERR(("cannot convert from transportType %d to %d", r->inputTransportType, r->settings.outputTransportType));
1158            return BERR_TRACE(NEXUS_NOT_SUPPORTED);
1159        }
1160        break;
1161    case NEXUS_TransportType_eEs:
1162        if (r->settings.outputTransportType != NEXUS_TransportType_eEs &&
1163            r->settings.outputTransportType != NEXUS_TransportType_eTs )
1164        {
1165            BDBG_ERR(("cannot convert from transportType %d to %d", r->inputTransportType, r->settings.outputTransportType));
1166            return BERR_TRACE(NEXUS_NOT_SUPPORTED);
1167        }
1168        break;
1169    default:
1170        BDBG_ERR(("transport input format %d not supported", r->inputTransportType));
1171        return BERR_TRACE(NEXUS_NOT_SUPPORTED);
1172    }
1173
1174    rec_cfg.MpegMode = !NEXUS_IS_DSS_MODE(r->inputTransportType);
1175    rec_cfg.CountRecordedPackets = pSettings->tpit.countRecordedPackets;
1176
1177    /* if you turn on band hold based on playback, then the CDB_UPPER_THRESHOLD interrupt will hold playback.
1178    however, recpump already uses CDB_UPPER_THRESHOLD for the dataready interrupt. you cannot have the band hold and
1179    dataready on the same condition, otherwise you can't establish an I/O pipeline (i.e. new data coming in while you are
1180    writing out previous data) . what's needed is a second upper threshold interrupt: one for data ready and another
1181    for band hold. that said, if you want to set band hold, enable this code, set the dataReadyThreshold to be a much higher
1182    percentage (like 80%), then have your app poll recpump so that you can have an I/O pipeline. */
1183    switch(pSettings->bandHold) {
1184    case NEXUS_RecpumpFlowControl_eEnable:
1185        bandHold = true;
1186        break;
1187    case NEXUS_RecpumpFlowControl_eDisable:
1188        bandHold = false;
1189        break;
1190    case NEXUS_RecpumpFlowControl_eAuto:
1191        bandHold = false;
1192        for(pid=BLST_S_FIRST(&r->pid_list);pid;pid=BLST_S_NEXT(pid, link)) {
1193            BDBG_ASSERT(pid->pidChn);
1194            if (pid->pidChn->status.playback) {
1195                bandHold = true;
1196                break;
1197            }
1198        }
1199        bandHold = false; /* Can't use band hold, revert it back */
1200        break;
1201    default:
1202        return BERR_TRACE(NEXUS_INVALID_PARAMETER);
1203    }
1204    rec_cfg.BandHoldEn = bandHold;
1205
1206    switch (r->settings.outputTransportType) {
1207    case NEXUS_TransportType_eTs:
1208    case NEXUS_TransportType_eDssEs:
1209    case NEXUS_TransportType_eDssPes:
1210        /* if input is DSS, a default output type of eTs is understood to be DSS. */
1211        rec_cfg.OutputFormat = BAVC_StreamType_eTsMpeg; /* this applies to DSS too */
1212        packetSize = NEXUS_IS_DSS_MODE(r->inputTransportType)?130:188;
1213        if (pSettings->timestampType != NEXUS_TransportTimestampType_eNone) {
1214            packetSize += 4;
1215        }
1216        break;
1217    case NEXUS_TransportType_eMpeg2Pes:
1218        /* the current impl does not use STREAM_ID_HI/LO for PES id filtering */
1219        rec_cfg.OutputFormat = BAVC_StreamType_ePes;
1220        packetSize = 0; /* there is no packet alignment for PES record. app can use M2M DMA to assemble byte aligned data into I/O sized (e.g. 4K) chunks. */
1221        if (pSettings->timestampType != NEXUS_TransportTimestampType_eNone) {
1222            return BERR_TRACE(NEXUS_NOT_SUPPORTED);
1223        }
1224        break;
1225    case NEXUS_TransportType_eEs:
1226        rec_cfg.OutputFormat = BAVC_StreamType_eEs;
1227        packetSize = 0; /* there is no packet alignment for ES record */
1228        if (pSettings->timestampType != NEXUS_TransportTimestampType_eNone) {
1229            return BERR_TRACE(NEXUS_NOT_SUPPORTED);
1230        }
1231        break;
1232    default:
1233        BDBG_ERR(("transport output format not supported"));
1234        return BERR_TRACE(NEXUS_NOT_SUPPORTED);
1235    }
1236
1237    /* The XPT threshold values are in units of NEXUS_RAVE_THRESHOLD_UNITS bytes. */
1238    rec_cfg.CdbUpperThreshold = r->openSettings.data.dataReadyThreshold / NEXUS_RAVE_THRESHOLD_UNITS;
1239    if (!rec_cfg.CdbUpperThreshold) {
1240        /* TODO: 0 should work (i.e. an interrupt for any data), but it does not */
1241        rec_cfg.CdbUpperThreshold = 1;
1242    }
1243    rec_cfg.CdbLowerThreshold = NEXUS_Recpump_P_GetLowThreshold(bandHold, rec_cfg.CdbUpperThreshold, r->openSettings.data.atomSize);
1244    rec_cfg.ItbUpperThreshold = r->openSettings.index.dataReadyThreshold / NEXUS_RAVE_THRESHOLD_UNITS;
1245    if (!rec_cfg.ItbUpperThreshold) {
1246        /* TODO: 0 should work (i.e. an interrupt for any data), but it does not */
1247        rec_cfg.ItbUpperThreshold = 1;
1248    }
1249    rec_cfg.ItbLowerThreshold = NEXUS_Recpump_P_GetLowThreshold(bandHold, rec_cfg.ItbUpperThreshold, r->openSettings.index.atomSize);
1250
1251    if (r->openSettings.data.atomSize % 64 != 0) {
1252        BDBG_ERR(("data.atomSize not supported. Recpump can be extended to support other atomSizes if required."));
1253        return BERR_TRACE(NEXUS_NOT_SUPPORTED);
1254    }
1255
1256    /* find "atom" which is a multiple of data.atomSize and packetSize */
1257    switch (packetSize) {
1258    case 188: atom = r->openSettings.data.atomSize * packetSize / 4; break;
1259    case 130: atom = r->openSettings.data.atomSize * packetSize / 2; break;
1260    case 192: atom = r->openSettings.data.atomSize * packetSize / 64; break;
1261    case 134: atom = r->openSettings.data.atomSize * packetSize / 2; break;
1262    case 0: atom = 0; break; /* no alignment */
1263    default:  return BERR_TRACE(NEXUS_NOT_SUPPORTED);
1264    }
1265
1266    /* Remove the last transport packet and replace with one whole XC packet. */
1267    if (pSettings->data.useBufferSize) {
1268        rec_cfg.UseCdbSize = pSettings->data.useBufferSize;
1269    } else {
1270        rec_cfg.UseCdbSize = r->openSettings.data.bufferSize;
1271    }
1272    if (atom) {
1273        rec_cfg.UseCdbSize -= rec_cfg.UseCdbSize % atom;
1274    }
1275    if (packetSize) {
1276        /* Remove the last transport packet and replace it with a whole NEXUS_RAVE_MEMC_BLOCK_SIZE, then remove an atom or packetSize in order
1277        to get be under the actual bufferSize. This is required for correct RAVE wraparound logic.
1278        Note that this logic allows a single recpump buffer to be used for any packet size and any atom size. It's just that some combinations
1279        result in more truncation at the end of the buffer. The only way to avoid any truncation is to only use one packet size, one atom size,
1280        and to anticipate the NEXUS_RAVE_MEMC_BLOCK_SIZE replacement in your application (e.g. bufferSize = bufferSize - 188 + 256). */
1281        rec_cfg.UseCdbSize -= packetSize;
1282        rec_cfg.UseCdbSize += NEXUS_RAVE_MEMC_BLOCK_SIZE;
1283        /* be sure we stick within the memory we're given */
1284        while (rec_cfg.UseCdbSize > r->openSettings.data.bufferSize) {
1285            rec_cfg.UseCdbSize -= atom?atom:packetSize;
1286        }
1287        BDBG_ASSERT(rec_cfg.UseCdbSize <= r->openSettings.data.bufferSize);
1288    }
1289
1290    BDBG_MSG(("Start: CDB alloc=%d use=%d, threshold=%d, ITB alloc=%d threshold=%d",
1291        r->openSettings.data.bufferSize, rec_cfg.UseCdbSize, r->openSettings.data.dataReadyThreshold,
1292        r->openSettings.index.bufferSize, r->openSettings.index.dataReadyThreshold));
1293
1294    switch (pSettings->timestampType) {
1295    case NEXUS_TransportTimestampType_eNone:
1296        rec_cfg.UseTimeStamps = false;
1297        break;
1298    case NEXUS_TransportTimestampType_e30_2U_Mod300:
1299        rec_cfg.TimestampMode = BXPT_TimestampMode_e30_2U_Mod300;
1300        rec_cfg.UseTimeStamps = true;
1301        rec_cfg.DisableTimestampParityCheck = false;
1302        break;
1303    case NEXUS_TransportTimestampType_e30_2U_Binary:
1304        rec_cfg.TimestampMode = BXPT_TimestampMode_e30_2U_Binary;
1305        rec_cfg.UseTimeStamps = true;
1306        rec_cfg.DisableTimestampParityCheck = false;
1307        break;
1308    case NEXUS_TransportTimestampType_e32_Mod300:   
1309        rec_cfg.TimestampMode = BXPT_TimestampMode_e30_2U_Mod300;
1310        rec_cfg.UseTimeStamps = true;
1311        rec_cfg.DisableTimestampParityCheck = true;
1312        break;
1313    case NEXUS_TransportTimestampType_e32_Binary:   
1314        rec_cfg.TimestampMode = BXPT_TimestampMode_e30_2U_Binary;
1315        rec_cfg.UseTimeStamps = true;
1316        rec_cfg.DisableTimestampParityCheck = true;
1317        break;
1318/* TODO: enable this when needed
1319    case NEXUS_TransportTimestampType_e28_4P_Mod300:   
1320        rec_cfg.TimestampMode = BXPT_TimestampMode_e28_4P_Mod300;
1321        rec_cfg.UseTimeStamps = true;
1322        rec_cfg.DisableTimestampParityCheck = true;
1323        break;
1324*/       
1325    default:
1326        BDBG_ERR(("Invalid timestamp mode"));
1327        return BERR_TRACE(NEXUS_INVALID_PARAMETER);
1328    }
1329   
1330    /* 1. Count number of pids that require indexing */
1331    for(scdNo=0,pid=BLST_S_FIRST(&r->pid_list);pid;pid=BLST_S_NEXT(pid, link)) {
1332        if (NEXUS_RECPUMP_PID_IS_INDEX(&pid->settings)) {
1333            scdNo++;
1334            if( pid->settings.pidType == NEXUS_PidType_eVideo &&
1335               (pid->settings.pidTypeSettings.video.codec == NEXUS_VideoCodec_eH264_Svc || pid->settings.pidTypeSettings.video.codec == NEXUS_VideoCodec_eH264_Mvc)) {
1336                svcVideo = true;
1337            }
1338        }
1339    }
1340
1341    rc = BXPT_Rave_SetRecordConfig(r->rave_rec, &rec_cfg);
1342    if (rc) {return BERR_TRACE(rc);}
1343
1344    /* 2. Allocate SCD indexer for desired number of pids (we only increase  number of SCD) */
1345    if(scdNo>r->scdPidCount) {
1346        if(r->scdIdx) {
1347            BXPT_Rave_FreeIndexer(r->scdIdx);
1348            r->scdPidCount = 0;
1349            r->scdIdx = NULL;
1350        }
1351        rc = BXPT_Rave_AllocIndexer(pTransport->rave[0].channel, BXPT_RaveIdx_eScd, scdNo, r->rave_rec, &r->scdIdx);
1352        if (rc) { return BERR_TRACE(rc); }
1353        r->scdPidCount = scdNo;
1354    }
1355
1356    for(scdNo=0,pid=BLST_S_FIRST(&r->pid_list);pid;pid=BLST_S_NEXT(pid, link)) {
1357        BXPT_Rave_IndexerSettings indx_cfg;
1358        BXPT_Rave_ScdEntry ScdConfig;
1359        const NEXUS_RecpumpAddPidChannelSettings *pSettings = &pid->settings;
1360
1361        if (!pid->pidChn) continue;
1362        if (!NEXUS_RECPUMP_PID_IS_INDEX(&pid->settings)) {
1363            continue;
1364        }
1365
1366        BKNI_Memset(&ScdConfig, 0, sizeof(ScdConfig));
1367
1368        if (pSettings->pidType == NEXUS_PidType_eVideo && pSettings->pidTypeSettings.video.index) {
1369
1370            if (!r->openSettings.index.bufferSize) {
1371                BDBG_ERR(("No index buffer allocated"));
1372                return BERR_TRACE(NEXUS_INVALID_PARAMETER);
1373            }
1374
1375            /* Set Index Configuration */
1376            BDBG_ASSERT(r->scdIdx);
1377            if(scdNo==0) {
1378                /* We are only capturing Index Data on the main video PID*/
1379                rc = BXPT_Rave_GetIndexerConfig( r->scdIdx, &indx_cfg);
1380                if (rc) {return BERR_TRACE(rc);}
1381
1382
1383                switch (pSettings->pidTypeSettings.video.codec) {
1384                case NEXUS_VideoCodec_eH264:
1385                case NEXUS_VideoCodec_eH264_Mvc:
1386                case NEXUS_VideoCodec_eH264_Svc:
1387                case NEXUS_VideoCodec_eH263:
1388                case NEXUS_VideoCodec_eVc1:
1389                case NEXUS_VideoCodec_eVc1SimpleMain:
1390                    /* 8 bytes of post-SC data is the max that can be captured.
1391                    AVC requires 59 bits, so we need them all. */
1392                    indx_cfg.Cfg.Scd.ScRange[0].RangeHi = 0x7F;
1393                    indx_cfg.Cfg.Scd.ScRange[0].RangeLo = 0x00;
1394                    indx_cfg.Cfg.Scd.ScRange[0].RangeEnable = true;
1395                    indx_cfg.Cfg.Scd.ScRange[0].RangeIsASlice = false;
1396                    break;
1397                case NEXUS_VideoCodec_eMpeg2:
1398                    indx_cfg.Cfg.Scd.ScRange[0].RangeHi = 0xB7;
1399                    indx_cfg.Cfg.Scd.ScRange[0].RangeLo = 0xB3;
1400                    indx_cfg.Cfg.Scd.ScRange[0].RangeEnable = true;
1401                    indx_cfg.Cfg.Scd.ScRange[0].RangeIsASlice = false;
1402#if BXPT_HAS_AVS
1403    /* for AVS-capable chips, we must explicitly enable SC 0x00 for MPEG */
1404                    indx_cfg.Cfg.Scd.ScRange[1].RangeHi = 0x00;
1405                    indx_cfg.Cfg.Scd.ScRange[1].RangeLo = 0x00;
1406                    indx_cfg.Cfg.Scd.ScRange[1].RangeEnable = true;
1407                    indx_cfg.Cfg.Scd.ScRange[1].RangeIsASlice = false;
1408#endif
1409                    break;
1410                case NEXUS_VideoCodec_eAvs:
1411                    /* sequence start and end */
1412                    indx_cfg.Cfg.Scd.ScRange[0].RangeHi = 0xB1;
1413                    indx_cfg.Cfg.Scd.ScRange[0].RangeLo = 0xB0;
1414                    indx_cfg.Cfg.Scd.ScRange[0].RangeEnable = true;
1415                    indx_cfg.Cfg.Scd.ScRange[0].RangeIsASlice = false;
1416                    /* I picture */
1417                    indx_cfg.Cfg.Scd.ScRange[1].RangeHi = 0xB3;
1418                    indx_cfg.Cfg.Scd.ScRange[1].RangeLo = 0xB3;
1419                    indx_cfg.Cfg.Scd.ScRange[1].RangeEnable = true;
1420                    indx_cfg.Cfg.Scd.ScRange[1].RangeIsASlice = false;
1421                    /* P and B pictures */
1422                    indx_cfg.Cfg.Scd.ScRange[2].RangeHi = 0xB6;
1423                    indx_cfg.Cfg.Scd.ScRange[2].RangeLo = 0xB6;
1424                    indx_cfg.Cfg.Scd.ScRange[2].RangeEnable = true;
1425                    indx_cfg.Cfg.Scd.ScRange[2].RangeIsASlice = false;
1426                    break;
1427                default:
1428                    BDBG_ERR(("Video Format not supported"));
1429                    return BERR_TRACE(NEXUS_NOT_SUPPORTED);
1430                }
1431#if NEXUS_SVC_MVC_SUPPORT
1432                indx_cfg.Cfg.Scd.SvcMvcMode = svcVideo;
1433#endif
1434
1435                rc = BXPT_Rave_SetIndexerConfig(r->scdIdx, &indx_cfg);
1436                if (rc) {return BERR_TRACE(rc);}
1437            }
1438
1439            ScdConfig.PidChannel = pid->pidChn->status.pidChannelIndex;
1440
1441#if BXPT_HAS_STARTCODE_BUFFER_WORKAROUND
1442            ScdConfig.EsCount = 9; /* EsCount 9 means 1 start code + 8 bytes of payload after the start code, which is the maximum allowed by 6 word SCT */
1443#else
1444            /* Wait for RAVE FW to fix so we can request all 8 bytes of Payload*/
1445            ScdConfig.EsCount = 7;
1446#endif
1447            ScdConfig.ExtractPts = true;
1448            if (pSettings->pidTypeSettings.video.pid != 0x1fff)
1449            {
1450                BDBG_WRN(("Generating index using pid 0x%x (%u), %u", pSettings->pidTypeSettings.video.pid, pSettings->pidTypeSettings.video.pid, scdNo));
1451                rc = BXPT_Rave_SetScdUsingPid(r->scdIdx, scdNo, pSettings->pidTypeSettings.video.pid, &ScdConfig);
1452                if (rc) {return BERR_TRACE(rc);}
1453            }
1454            else
1455            {
1456                /* TODO: verify not allPass */
1457                BDBG_MSG(("Generating index using pid channel %d",ScdConfig.PidChannel));
1458                rc = BXPT_Rave_SetScdEntry(r->scdIdx, scdNo, &ScdConfig);
1459                if (rc) {return BERR_TRACE(rc);}
1460            }
1461        }
1462        else if (pSettings->pidType == NEXUS_PidType_eOther && pSettings->pidTypeSettings.other.index) {
1463
1464            if (!r->openSettings.index.bufferSize) {
1465                BDBG_ERR(("No index buffer allocated"));
1466                return BERR_TRACE(NEXUS_INVALID_PARAMETER);
1467            }
1468
1469            if(scdNo==0) {
1470                unsigned i;
1471                /* Set Index Configuration */
1472                (void)BXPT_Rave_GetIndexerConfig( r->scdIdx, &indx_cfg);
1473                BDBG_CASSERT(NEXUS_NUM_STARTCODE_RANGES <= BXPT_MAX_STARTCODE_RANGES);
1474                for (i=0;i<NEXUS_NUM_STARTCODE_RANGES;i++) {
1475                    indx_cfg.Cfg.Scd.ScRange[i].RangeHi = pSettings->pidTypeSettings.other.startCodeRange[i].high;
1476                    indx_cfg.Cfg.Scd.ScRange[i].RangeLo = pSettings->pidTypeSettings.other.startCodeRange[i].low;
1477                    indx_cfg.Cfg.Scd.ScRange[i].RangeEnable = (pSettings->pidTypeSettings.other.startCodeRange[i].high >= pSettings->pidTypeSettings.other.startCodeRange[i].low);
1478                    indx_cfg.Cfg.Scd.ScRange[i].RangeIsASlice = false;
1479                }
1480                rc = BXPT_Rave_SetIndexerConfig(r->scdIdx, &indx_cfg);
1481                if (rc) {return BERR_TRACE(rc);}
1482            }
1483
1484            ScdConfig.PidChannel = pid->pidChn->status.pidChannelIndex;
1485            ScdConfig.EsCount = 2; /* no payload needed, min 2 required */
1486            ScdConfig.ExtractPts = true;
1487            rc = BXPT_Rave_SetScdEntry(r->scdIdx, scdNo, &ScdConfig);
1488            if (rc) {return BERR_TRACE(rc);}
1489        }
1490        scdNo++;
1491        startIndex = true;
1492
1493        if (pid->tpit.enabled) {
1494            startIndex = true;
1495        }
1496    }
1497
1498    if (r->tpitIdx) {
1499        unsigned i;
1500       
1501        BXPT_Rave_IndexerSettings indx_cfg;
1502        (void)BXPT_Rave_GetIndexerConfig(r->tpitIdx, &indx_cfg);
1503        indx_cfg.Cfg.Tpit.FirstPacketEnable = pSettings->tpit.firstPacketEnable;
1504        indx_cfg.Cfg.Tpit.StorePcrMsb = pSettings->tpit.storePcrMsb;
1505        indx_cfg.Cfg.Tpit.IdleEventEnable = pSettings->tpit.idleEventEnable;
1506        indx_cfg.Cfg.Tpit.RecordEventEnable = pSettings->tpit.recordEventEnable;
1507        rc = BXPT_Rave_SetIndexerConfig(r->tpitIdx, &indx_cfg);
1508        if (rc) {return BERR_TRACE(rc);}
1509       
1510        for (i=0;i<NEXUS_NUM_ECM_TIDS;i++) {
1511            if (pSettings->tpit.ecmPair[i].enabled) {
1512                rc = BXPT_Rave_SetTpitEcms(r->tpitIdx, i+1 /* PI is one-based */, pSettings->tpit.ecmPair[i].evenTid, pSettings->tpit.ecmPair[i].oddTid);
1513                if (rc) {return BERR_TRACE(rc);}
1514            }
1515            /* TODO: no disable */
1516        }
1517    }
1518
1519    rc = BXPT_Rave_EnableContext(r->rave_rec);
1520    if (rc) {rc=BERR_TRACE(rc);goto err_rave;}
1521
1522#if NEXUS_ENCRYPTED_DVR_WITH_M2M
1523    if(!r->settings.securityContext) {
1524        r->cryptoActive = false;
1525    } else {
1526        NEXUS_DmaJobSettings jobSettings;
1527        unsigned i;
1528
1529        if (packetSize) {
1530            r->data.dataReadyThreshold -= r->data.dataReadyThreshold%packetSize; /* convert dataReadyThreshold to multiplier of transport packet size */
1531        }
1532        if(!g_NEXUS_Transport_P_State.settings.dma) { rc = BERR_TRACE(BERR_NOT_SUPPORTED);goto err_dma;}
1533
1534        r->crypto.head = r->crypto.tail = NULL;
1535        NEXUS_DmaJob_GetDefaultSettings(&jobSettings);
1536        jobSettings.numBlocks = sizeof(r->crypto.blocks)/sizeof(*r->crypto.blocks);
1537        jobSettings.dataFormat = r->settings.securityDmaDataFormat;
1538        jobSettings.keySlot = r->settings.securityContext;
1539        r->crypto.job = NEXUS_DmaJob_Create(r->settings.securityDma, &jobSettings);
1540        if(!r->crypto.job) {rc=BERR_TRACE(BERR_OUT_OF_SYSTEM_MEMORY);goto err_dma;}
1541        for(i=0;i<sizeof(r->crypto.blocks)/sizeof(*r->crypto.blocks);i++) { /* initialize dma blocks */
1542            NEXUS_DmaJob_GetDefaultBlockSettings(&r->crypto.blocks[i]);
1543            r->crypto.blocks[i].cached = false;
1544        }
1545        r->crypto.blocks[0].resetCrypto = true;
1546        r->crypto.blocks[0].scatterGatherCryptoStart = true;
1547        r->crypto.blocks[1].scatterGatherCryptoEnd = true;
1548        r->crypto.packetSize = packetSize;
1549        r->cryptoActive = true;
1550    }
1551#endif
1552
1553    for(pid=BLST_S_FIRST(&r->pid_list);pid;pid=BLST_S_NEXT(pid, link)) {
1554        if (pid->pidChn) {
1555            NEXUS_Recpump_P_StartPid(r, pid);
1556        }
1557    }
1558
1559    /* start MPEG data flow */
1560    BDBG_MSG(("Starting data flow"));
1561    rc = NEXUS_Recpump_P_StartFlow(&r->data);
1562    if (rc) {rc=BERR_TRACE(rc);goto err_record_data; }
1563
1564    if (startIndex) {
1565        /* start Index data flow */
1566        BDBG_MSG(("Starting Index flow"));
1567        rc = NEXUS_Recpump_P_StartFlow(&r->index);
1568        if (rc) {rc=BERR_TRACE(rc);goto err_record_scd; }
1569
1570        /* keep track of indexing with a separate variable. the indexPidChannel might be removed before we stop the flow. */
1571        r->indexing = true;
1572    }
1573    else {
1574        r->indexing = false;
1575    }
1576
1577    r->actuallyStarted = true;
1578    return 0;
1579
1580#if NEXUS_ENCRYPTED_DVR_WITH_M2M
1581err_dma:
1582    NEXUS_Recpump_P_StopFlow(&r->index);
1583#endif
1584err_record_scd:
1585    NEXUS_Recpump_P_StopFlow(&r->data);
1586err_record_data:
1587    BXPT_Rave_DisableContext(r->rave_rec);
1588err_rave:
1589    BDBG_ASSERT(rc);
1590    return rc;
1591}
1592
1593NEXUS_Error NEXUS_Recpump_Start(NEXUS_RecpumpHandle r)
1594{
1595    NEXUS_Error rc;
1596
1597    BDBG_OBJECT_ASSERT(r, NEXUS_Recpump);
1598    if (r->started) {
1599        return BERR_TRACE(NEXUS_UNKNOWN);
1600    }
1601    BDBG_ASSERT(!r->started);
1602    BDBG_ASSERT(!r->actuallyStarted);
1603
1604    r->started = true;
1605    if (r->pidChannelCnt) {
1606        rc = NEXUS_Recpump_P_Start(r);
1607    }
1608    else {
1609        /* defer */
1610        rc = 0;
1611    }
1612
1613    /* mark started only if successful */
1614    if (rc) {
1615        r->started = false;
1616    } else {
1617        r->dataStopped = false;
1618    }
1619    return rc;
1620}
1621
1622void NEXUS_Recpump_StopData(NEXUS_RecpumpHandle r)
1623{
1624    BERR_Code rc;
1625    NEXUS_Recpump_P_PidChannel *pid;
1626
1627    BDBG_OBJECT_ASSERT(r, NEXUS_Recpump);
1628    if (!r->started)  {
1629        BDBG_ERR(("Recpump %d not started", r->tindex));
1630        return;
1631    }
1632    if(r->dataStopped) {
1633        BDBG_ERR(("Recpump %d already stopped", r->tindex));
1634        return;
1635    }
1636    r->dataStopped = true;
1637
1638    if (r->rave_state != Terminated) {
1639        r->rave_state = Done;
1640    }
1641
1642    if(r->actuallyStarted)
1643    {
1644
1645        rc = BXPT_Rave_DisableContext(r->rave_rec);
1646        if (rc) { BDBG_ERR(("Error from BXPT_Rave_DisableContext, ignored")); }
1647
1648        NEXUS_Recpump_P_StopFlow(&r->data);
1649        if (r->indexing) {
1650            NEXUS_Recpump_P_StopFlow(&r->index);
1651        }
1652#if NEXUS_ENCRYPTED_DVR_WITH_M2M
1653        if(r->cryptoActive) {
1654            unsigned i;
1655            for(i=0;i<100;i++) {
1656                NEXUS_DmaJobStatus jobStatus;
1657                if(r->crypto.tail == r->crypto.head) { /*  DMA idle */
1658                    break;
1659                }
1660                rc = NEXUS_DmaJob_GetStatus(r->crypto.job, &jobStatus);
1661                if(rc!=NEXUS_SUCCESS) {rc=BERR_TRACE(rc);break;}
1662                if(jobStatus.currentState == NEXUS_DmaJobState_eComplete) {
1663                    break;
1664                }
1665                BDBG_MSG(("NEXUS_Recpump_StopData: %#lx waiting for DMA to complete %u", (unsigned long)r, i));
1666                BKNI_Sleep(1);
1667            }
1668            NEXUS_DmaJob_Destroy(r->crypto.job);
1669            r->crypto.job = NULL;
1670            r->cryptoActive = false;
1671        }
1672#endif
1673        for(pid=BLST_S_FIRST(&r->pid_list);pid;pid=BLST_S_NEXT(pid, link)) {
1674            if (pid->pidChn) {
1675                NEXUS_Recpump_P_StopPid(r, pid);
1676            }
1677        }
1678    }
1679
1680    return;
1681}
1682
1683void NEXUS_Recpump_Stop(NEXUS_RecpumpHandle r)
1684{
1685    BDBG_OBJECT_ASSERT(r, NEXUS_Recpump);
1686    r->rave_state = Terminated;
1687    if(!r->dataStopped) {
1688        NEXUS_Recpump_StopData(r);
1689    }
1690    r->actuallyStarted = false;
1691    r->started = false;
1692    return;
1693}
1694
1695void NEXUS_Recpump_GetDefaultAddPidChannelSettings(NEXUS_RecpumpAddPidChannelSettings *pSettings)
1696{
1697    unsigned i;
1698    BKNI_Memset(pSettings, 0, sizeof(*pSettings));
1699    pSettings->pidType = NEXUS_PidType_eUnknown;
1700    pSettings->pidTypeSettings.video.pid = 0x1fff;
1701    for (i=0;i<NEXUS_NUM_STARTCODE_RANGES;i++) {
1702        if (i == 0) {
1703            /* all start codes */
1704            pSettings->pidTypeSettings.other.startCodeRange[i].low  = 0x00;
1705            pSettings->pidTypeSettings.other.startCodeRange[i].high = 0xFF;
1706        }
1707        else {
1708            /* disabled (if low > high) */
1709            pSettings->pidTypeSettings.other.startCodeRange[i].low  = 0x01;
1710            pSettings->pidTypeSettings.other.startCodeRange[i].high = 0x00;
1711        }
1712    }
1713}
1714
1715
1716
1717NEXUS_Error NEXUS_Recpump_AddPidChannel(NEXUS_RecpumpHandle r, NEXUS_PidChannelHandle pidChannel, const NEXUS_RecpumpAddPidChannelSettings *pSettings)
1718{
1719    NEXUS_Error rc;
1720    NEXUS_RecpumpAddPidChannelSettings settings;
1721    NEXUS_TransportType transportType;
1722    NEXUS_Recpump_P_PidChannel *pid;
1723
1724    BDBG_OBJECT_ASSERT(r, NEXUS_Recpump);
1725    if (!pSettings) {
1726        NEXUS_Recpump_GetDefaultAddPidChannelSettings(&settings);
1727        pSettings = &settings;
1728    }
1729
1730    if (BLST_S_FIRST(&r->pid_list)) {
1731        /* check if already playback or not */
1732        if (pidChannel->status.playback != r->playback) {
1733            BDBG_ERR(("You cannot mix playback and non-playback pid channels to the same recpump"));
1734            return BERR_TRACE(NEXUS_INVALID_PARAMETER);
1735        }
1736    }
1737    else {
1738        r->playback = pidChannel->status.playback;
1739    }
1740
1741    pid = BKNI_Malloc(sizeof(*pid));
1742    if ( NULL == pid )
1743    {
1744       return BERR_TRACE(BERR_OUT_OF_SYSTEM_MEMORY);
1745    }
1746    BKNI_Memset((void*)pid, 0x0, sizeof(*pid));
1747
1748    pid->pidChn = pidChannel;
1749
1750    BLST_S_DICT_ADD(&r->pid_list, pid, NEXUS_Recpump_P_PidChannel, pidChn, link, err_duplicate);
1751
1752    pid->settings = *pSettings;
1753
1754    if (NEXUS_RECPUMP_PID_IS_INDEX(pSettings)) {
1755        if (r->actuallyStarted) {
1756            BDBG_WRN(("You must set open the index pid channel before starting recpump. This pid channel's index setting will be ignored."));
1757        }
1758    }
1759
1760    if (pidChannel->status.playback) {
1761        NEXUS_PlaypumpSettings playpumpSettings;
1762        NEXUS_Playpump_GetSettings(pTransport->playpump[pidChannel->status.playbackIndex].playpump, &playpumpSettings);
1763        transportType = playpumpSettings.transportType;
1764        switch(transportType) {
1765        case NEXUS_TransportType_eMpeg2Pes:
1766            transportType = NEXUS_TransportType_eTs;
1767            break;
1768        default:
1769            break;
1770        }
1771    }
1772    else {
1773        NEXUS_ParserBandSettings parserBandSettings;
1774        NEXUS_ParserBand_P_GetSettings(pidChannel->parserBand, &parserBandSettings);
1775        transportType = parserBandSettings.transportType;
1776    }
1777    if (r->pidChannelCnt == 0) {
1778        r->inputTransportType = transportType;
1779    }
1780    else if (r->inputTransportType != transportType) {
1781        BDBG_ERR(("transport type for all pid channels must match"));
1782        rc = BERR_TRACE(NEXUS_INVALID_PARAMETER);
1783        goto error;
1784    }
1785
1786    rc = BXPT_Rave_AddPidChannel(r->rave_rec, pidChannel->status.pidChannelIndex, pSettings->useRPipe);
1787    if (rc) {
1788        rc = BERR_TRACE(rc);
1789        goto error;
1790    }
1791
1792    /* now that we're up, we can do the bookkeeping. if we fail between here and the end, we must unwind. */
1793    r->pidChannelCnt++;
1794
1795    if (r->started) {
1796        if (!r->actuallyStarted) {
1797            BDBG_ASSERT(r->pidChannelCnt == 1);
1798            rc = NEXUS_Recpump_P_Start(r);
1799        }
1800        else {
1801            /* already started, so just start this pid */
1802            (void)NEXUS_Recpump_P_StartPid(r, pid);
1803        }
1804    }
1805
1806    /* if the last step failed, we have to undo the bookkeeping */
1807    if (rc) {
1808        BXPT_Rave_RemovePidChannel(r->rave_rec, pidChannel->status.pidChannelIndex);
1809        r->pidChannelCnt--;
1810        goto error;
1811    }
1812
1813    return 0;
1814
1815error:
1816    BLST_S_DICT_REMOVE(&r->pid_list, pid, pidChannel, NEXUS_Recpump_P_PidChannel, pidChn, link);
1817    pid->pidChn = NULL;
1818    BKNI_Free(pid);
1819    BDBG_ASSERT(rc);
1820    return rc;
1821err_duplicate:
1822    rc = BERR_TRACE(NEXUS_INVALID_PARAMETER);
1823    BKNI_Free(pid);
1824    return rc;
1825}
1826
1827NEXUS_Error NEXUS_Recpump_RemovePidChannel(NEXUS_RecpumpHandle r, NEXUS_PidChannelHandle pidChannel)
1828{
1829    NEXUS_Error rc;
1830    NEXUS_Recpump_P_PidChannel *pid;
1831
1832    BDBG_OBJECT_ASSERT(r, NEXUS_Recpump);
1833    BDBG_OBJECT_ASSERT(pidChannel, NEXUS_PidChannel);
1834    BLST_S_DICT_FIND(&r->pid_list, pid, pidChannel, pidChn, link);
1835    if(pid==NULL) {
1836        BDBG_WRN(("NEXUS_Recpump_RemovePidChannel: %#lx can't find pid:%#lx", (unsigned long)r, (unsigned long)pidChannel));
1837        rc = BERR_TRACE(NEXUS_INVALID_PARAMETER);
1838        goto err_pid;
1839    }
1840
1841    if (r->actuallyStarted) {
1842        NEXUS_Recpump_P_StopPid(r, pid);
1843    }
1844
1845    (void)NEXUS_Recpump_SetTpitFilter(r, pidChannel, NULL);
1846
1847    BLST_S_DICT_REMOVE(&r->pid_list, pid, pidChannel, NEXUS_Recpump_P_PidChannel, pidChn, link);
1848    if(!pid) { rc = BERR_TRACE(NEXUS_INVALID_PARAMETER); goto err_pid;}
1849
1850    BDBG_ASSERT(r->pidChannelCnt);
1851
1852    pid->pidChn = NULL;
1853    r->pidChannelCnt--;
1854    if (r->scdIdx && r->pidChannelCnt==0) { /* when all pids were removed free indexer */
1855        BXPT_Rave_FreeIndexer(r->scdIdx);
1856        r->scdIdx=NULL;
1857        r->scdPidCount = 0;
1858    }
1859
1860    BKNI_Free(pid);
1861
1862    rc = BXPT_Rave_RemovePidChannel(r->rave_rec, pidChannel->status.pidChannelIndex);
1863    if (rc) return BERR_TRACE(rc);
1864
1865    return 0;
1866err_pid:
1867    return rc;
1868}
1869
1870void NEXUS_Recpump_RemoveAllPidChannels(NEXUS_RecpumpHandle r)
1871{
1872    NEXUS_Recpump_P_PidChannel *pid;
1873
1874    BDBG_OBJECT_ASSERT(r, NEXUS_Recpump);
1875
1876    while(NULL!=(pid=BLST_S_FIRST(&r->pid_list))) {
1877        NEXUS_Recpump_RemovePidChannel(r, pid->pidChn);
1878    }
1879
1880    BDBG_ASSERT(r->pidChannelCnt == 0);
1881}
1882
1883static NEXUS_Error
1884NEXUS_Recpump_P_GetBuffer(struct NEXUS_RecpumpFlow *flow, const void **buffer, size_t *bufferSize, const void **buffer2, size_t *bufferSize2, bool *pBypassThresholdTest)
1885{
1886    BERR_Code rc;
1887    BXPT_Rave_ContextPtrs ptrs;
1888    const BXPT_Rave_DataPtrs *ptr;
1889    unsigned size;
1890    bool bypassThresholdTest = false;
1891    NEXUS_RecpumpHandle pump;
1892    uint8_t *dataPtr;
1893
1894    pump = flow->recpump;
1895
1896    if (!pump->actuallyStarted)  {
1897        /* don't print error message, because this is a normal exit from thread processing */
1898        return NEXUS_UNKNOWN;
1899    }
1900    rc = BXPT_Rave_CheckBuffer(pump->rave_rec, &ptrs);
1901    if (rc) return BERR_TRACE(rc);
1902
1903    if (flow==&pump->data) {
1904        ptr = &ptrs.Cdb;
1905    }
1906    else {
1907        ptr = &ptrs.Itb;
1908    }
1909    BDBG_MSG_TRACE(("RAVE %s depth %u %u, size %u", NEXUS_P_FLOW_NAME(flow),
1910            (unsigned long)(ptr->ByteCount), (unsigned long)ptr->WrapByteCount,
1911            flow->bufferSize));
1912
1913    /* if the depth is greater than the size, then underlying FW or SW must be in a bad state.
1914    the chances that upper level software can survive this are very low. better to assert now and fix the problem. */
1915    if ((unsigned long)(ptr->ByteCount + ptr->WrapByteCount) > flow->bufferSize) {
1916        BDBG_ERR(("Invalid RAVE %s depth %u, size %u", NEXUS_P_FLOW_NAME(flow),
1917            (unsigned long)(ptr->ByteCount + ptr->WrapByteCount),
1918            flow->bufferSize));
1919        BKNI_Fail();
1920    }
1921
1922    if (flow==&pump->data) {
1923        size = ptr->ByteCount;
1924        dataPtr = ptr->DataPtr;
1925        if(size<=0) {
1926            goto done;
1927        } else {
1928            bypassThresholdTest = ptr->WrapByteCount>0;
1929        }
1930#if NEXUS_ENCRYPTED_DVR_WITH_M2M
1931        if(pump->cryptoActive) {
1932            uint8_t *tail = pump->crypto.tail;
1933            if(pump->crypto.head == tail) { /* DMA was completed, check if there is new data */
1934                unsigned nvecs;
1935                if(tail==NULL) { /* after start we don't know start of CDB buffer */
1936                    tail = pump->crypto.head=pump->crypto.tail = dataPtr;
1937                }
1938                if(ptr->WrapByteCount==0) {
1939                    if(((uint8_t *)dataPtr + size) >= tail) {
1940                        /*      |---------|++++++++|~~~~~~~~~~~~|-------------|
1941                         *   FifoStart  dataPtr  tail     (dataPtr+size) FifoEnd(Wrap) */
1942                        size  = (dataPtr + size) - tail;
1943                    } else { /* we just passed through FIFO wrap pointer, reset head */
1944                        /*      |~~~~~~~~~~~~~~~~~|---------------------------|
1945                         *   dataPtr/FifoStart (dataPtr+size)         tail/FifoEnd(Wrap) */
1946                        tail = pump->crypto.tail = dataPtr;
1947                    }
1948                    nvecs = 1;
1949                    if (pump->crypto.packetSize) {
1950                        size -= size%pump->crypto.packetSize;
1951                    }
1952                    pump->crypto.head = tail + size;
1953                } else {
1954                    unsigned partialPacket;
1955
1956                    if(dataPtr > tail)  {
1957                        /* all data prior to wrap is encrypted */
1958                        if( ((uint8_t *)ptr->WrapDataPtr + ptr->WrapByteCount) >= tail) {
1959                            /*     |++++++++++++++++++++|~~~~~~~~~~~~|----------------|+++++++++++++++|
1960                             * FifoStart/WrapDataPtr  tail WrapDataPtr+WrapByteCount dataPtr   FifoEnd(Wrap)/dataPtr+size */
1961                            nvecs = 1;
1962                            size  = ((uint8_t *)ptr->WrapDataPtr + ptr->WrapByteCount) - tail; /* number of bytes prior to wrap */
1963                            if (pump->crypto.packetSize) {
1964                                size -= size%pump->crypto.packetSize; /* if there is no wrap, then don't cross packet boundary */
1965                            }
1966                            pump->crypto.head = tail + size;
1967                        } else {
1968                            return BERR_TRACE(NEXUS_UNKNOWN); /* somehow rave pointer raced ahead of DMA pointer*/
1969                        }
1970                    } else if((dataPtr + size) >= tail) {
1971                        /*     |~~~~~~~~~~~~~~~~~~~~~~~|-------------------|++++++++++|~~~~~~~~|
1972                        * FifoStart/WrapDataPtr  WrapDataPtr+WrapByteCount dataPtr  tail  FifoEnd(Wrap)/dataPtr+size */
1973                        size = (dataPtr + size) - tail; /* number of bytes prior to wrap */
1974                        if(size>0) { /* if there is unecrypted data prior to wrap */
1975                            if (pump->crypto.packetSize) {
1976                                partialPacket = (ptr->WrapByteCount + size)%pump->crypto.packetSize; /* size of partial packet */
1977                            }
1978                            else {
1979                                partialPacket = 0;
1980                            }
1981                            if(ptr->WrapByteCount > partialPacket) { /* if after write there is complete packet after wrap */
1982                                nvecs = 2;
1983                                pump->crypto.head = (uint8_t*)ptr->WrapDataPtr + (ptr->WrapByteCount - partialPacket);
1984                                pump->crypto.blocks[1].blockSize = ptr->WrapByteCount - partialPacket;
1985                                pump->crypto.blocks[1].pSrcAddr = ptr->WrapDataPtr;
1986                                pump->crypto.blocks[1].pDestAddr = ptr->WrapDataPtr;
1987                            } else { /* Can't use data after wrap yet */
1988                                nvecs = 1;
1989                                if (pump->crypto.packetSize) {
1990                                    size -= size%pump->crypto.packetSize;
1991                                }
1992                                pump->crypto.head = tail + size;
1993                            }
1994                        } else {
1995                            /* there was wrap and only unecrypted data after wrap */
1996                            /*     |~~~~~~~~~~~~~~~~~~~~~~~|-------------------|++++++++++|
1997                            * FifoStart/WrapDataPtr  WrapDataPtr+WrapByteCount dataPtr  tail/FifoEnd(Wrap)/dataPtr+size */
1998                            nvecs = 1;
1999                            size = ptr->WrapByteCount;
2000                            if (pump->crypto.packetSize) {
2001                                size -= size%pump->crypto.packetSize;
2002                            }
2003                            tail = pump->crypto.tail = ptr->WrapDataPtr;
2004                            pump->crypto.head = tail + size;
2005                        }
2006                    } else {
2007                        return BERR_TRACE(NEXUS_UNKNOWN); /* somehow rave pointer raced ahead of DMA pointer*/
2008                    }
2009                }
2010                /* BDBG_MSG(("DMA: %u %u %u (%u %u %u(%p:%p:%u)", tail != pump->crypto.head,nvecs, size>flow->dataReadyThreshold, !flow->pending, tail<(dataPtr+flow->dataReadyThreshold), (tail+size)>=(dataPtr+flow->dataReadyThreshold), (tail+size), (dataPtr+flow->dataReadyThreshold), size)); */
2011
2012                if(tail != pump->crypto.head && /* there is new data avaliable */
2013                   (nvecs>1 ||  /* wrap */
2014                    size>flow->dataReadyThreshold || /* or DMA block large enough */
2015                    (!flow->pending && tail<(dataPtr+flow->dataReadyThreshold) && (tail+size)>=(dataPtr+flow->dataReadyThreshold))) /* application waits for data and completed DMA would make threshold test to pass */
2016                        ) {
2017                    pump->crypto.blocks[0].blockSize = size;
2018                    pump->crypto.blocks[0].pSrcAddr = tail;
2019                    pump->crypto.blocks[0].pDestAddr = tail;
2020                    pump->crypto.blocks[0].scatterGatherCryptoEnd = nvecs==2?false:true;
2021
2022                    NEXUS_Module_Lock(g_NEXUS_Transport_P_State.settings.dma);
2023                    rc = NEXUS_DmaJob_ProcessBlocks_priv(pump->crypto.job, pump->crypto.blocks, nvecs, pump->crypto.event);
2024                    NEXUS_Module_Unlock(g_NEXUS_Transport_P_State.settings.dma);
2025                    BDBG_MSG(("NEXUS_Recpump_P_GetBuffer:%#lx DMA(%#lx:%u) %u->%u", (unsigned long)pump, (unsigned long)pump->crypto.tail, nvecs, size, rc));
2026                    if(rc==NEXUS_SUCCESS) {
2027                        tail = pump->crypto.tail = pump->crypto.head;
2028                    } else if (rc!=NEXUS_DMA_QUEUED) {
2029                        pump->crypto.head = tail; /* revert changes */
2030                        return BERR_TRACE(rc);
2031                    }
2032                } else {
2033                    pump->crypto.head = tail;
2034                }
2035            }
2036
2037            if(tail >= dataPtr) {
2038                size = tail - dataPtr;
2039                bypassThresholdTest = false;
2040            } else {
2041                size = ptr->ByteCount;
2042                bypassThresholdTest = true;
2043            }
2044        }
2045#endif
2046    } else {
2047        size = ptr->ByteCount;
2048        dataPtr = ptr->DataPtr;
2049        if (size<=0) {
2050            goto done;
2051        } else {
2052            /* on a wrap around, we must always return whatever data is available */
2053            bypassThresholdTest = ptr->WrapByteCount>0;
2054        }
2055    }
2056
2057done:
2058    if (buffer2) {
2059        /* if you want to peek around the wrap around, don't apply any atomSize truncation. just give
2060        both buffer and buffer2 exactly as is.
2061        if crypto is active, don't peek around. */
2062#if NEXUS_ENCRYPTED_DVR_WITH_M2M
2063        if (!pump->cryptoActive && ptr->WrapByteCount>0) {
2064#else
2065        if (ptr->WrapByteCount>0) {
2066#endif
2067            *buffer2 = ptr->WrapDataPtr;
2068            *bufferSize2 = ptr->WrapByteCount;
2069        }
2070        else {
2071            /* the user is requesting peek around, but there is none or it is wrapped with
2072            dma logic and can't be provided. */
2073            *buffer2 = NULL;
2074            *bufferSize2 = 0;
2075        }
2076    }
2077    else {
2078        /* apply atomSize limitations before setting buffer/bufferSize */
2079        if (pump->rave_state != Done) {
2080            if (size >= flow->atomSize || bypassThresholdTest) {
2081                /* don't modify size & dataPtr */
2082            } else {
2083                /* If we're not at wrap around, and we're not done, then GetBuffer shouldn't report any data which is
2084                less than the threshold. Let the app wait for the interrupt. */
2085                size = 0;
2086                dataPtr = NULL;
2087            }
2088        } else {
2089            /* If we're done, we send everything out. The last piece of data can be < atomSize. */
2090            if (flow->atomSize && size > flow->atomSize) {
2091                size -= (size % flow->atomSize);
2092            }
2093        }
2094    }
2095    *bufferSize = size;
2096    *buffer = dataPtr;
2097    *pBypassThresholdTest = bypassThresholdTest;
2098
2099    BDBG_MSG(("GetBuffer[%s] %u (actual %u, threshold %u)", NEXUS_P_FLOW_NAME(flow), *bufferSize, size, flow->dataReadyThreshold));
2100
2101    return NEXUS_SUCCESS;
2102}
2103
2104
2105static NEXUS_Error
2106NEXUS_Recpump_P_WriteComplete(struct NEXUS_RecpumpFlow *flow, size_t amount_written)
2107{
2108    BERR_Code rc;
2109    BXPT_RaveCx_Status status;
2110
2111    if (!flow->recpump->actuallyStarted)  {
2112        /* don't print error message, because this is a normal exit from thread processing */
2113        return BERR_TRACE(NEXUS_UNKNOWN);
2114    }
2115    if (amount_written > flow->lastGetBuffer) {
2116        BDBG_WRN(("Cannot WriteComplete %u when last GetBuffer was %u", amount_written, flow->lastGetBuffer));
2117        return BERR_TRACE(NEXUS_UNKNOWN);
2118    }
2119
2120    BDBG_MSG(("WriteComplete[%s] %u", NEXUS_P_FLOW_NAME(flow), amount_written));
2121    flow->bytesRecorded += amount_written;
2122
2123    if (flow == &flow->recpump->index) {
2124        /* Itb read pointer is updated here */
2125        rc = BXPT_Rave_UpdateReadOffset(flow->recpump->rave_rec, 0 /* CDB count */, amount_written);
2126    }
2127    else {
2128        rc = BXPT_Rave_UpdateReadOffset(flow->recpump->rave_rec, amount_written, 0 /* ITB count */);
2129    }
2130    if (rc) {return BERR_TRACE(rc);}
2131
2132    rc = BXPT_Rave_GetContextStatus(flow->recpump->rave_rec, &status);
2133    if (rc) {return BERR_TRACE(rc);}
2134
2135    /* TODO: calling stop on overflow is not required. settop api has a bug. we need to have RecpumpSetting bool to stop record or keep
2136    going on overflow. see settop api for solution. */
2137    if (status.CdbOverflow || status.ItbOverflow  ) {
2138        if (status.CdbOverflow) {
2139            BDBG_ERR(("[%#x]CDB Overflow detected in record",flow));
2140        }
2141        if (status.ItbOverflow) {
2142            BXPT_Rave_ContextPtrs ptrs;
2143            BDBG_ERR(("[%#x]ITB Overflow detected in record",flow));
2144
2145            rc = BXPT_Rave_CheckBuffer(flow->recpump->rave_rec, &ptrs);
2146            if (rc) return BERR_TRACE(rc);
2147
2148            /* We are helping the application move along by clearing out some ITB Data. This is harmless.
2149            CDB data cannot be flushed and should be recorded. */
2150            BXPT_Rave_UpdateReadOffset(flow->recpump->rave_rec, 0 /* CDB count */, ptrs.Itb.ByteCount);
2151        }
2152
2153        NEXUS_TaskCallback_Fire(flow->overflowCallback);
2154    }
2155    flow->pending = false;
2156    flow->lastGetBuffer = 0;
2157
2158    /* This can generate a callback if data is available */
2159    (void)NEXUS_Recpump_P_TestDataReadyCallback(flow);
2160    /* Be aware that we may be stopped right now. */
2161
2162    return NEXUS_SUCCESS;
2163}
2164
2165/* this function handles calls from application, it checks rave buffer, saves last returned size and flushes cache */
2166static NEXUS_Error
2167NEXUS_Recpump_P_GetBufferApi(struct NEXUS_RecpumpFlow *flow, const void **buffer, size_t *bufferSize, const void **buffer2, size_t *bufferSize2)
2168{
2169    NEXUS_Error rc;
2170    bool wrapped;
2171    rc = NEXUS_Recpump_P_GetBuffer(flow, buffer, bufferSize, buffer2, bufferSize2, &wrapped);
2172    if(rc==NEXUS_SUCCESS) {
2173        flow->lastGetBuffer = *bufferSize;
2174
2175        if(*bufferSize>0) {
2176            rc = BMEM_Heap_ConvertAddressToCached(g_pCoreHandles->heap[0], (void *)*buffer, (void **)buffer);
2177            if (rc) return BERR_TRACE(rc);
2178            NEXUS_FlushCache(*buffer, *bufferSize);
2179        } else {
2180            *buffer = NULL;
2181        }
2182
2183        if (bufferSize2) {
2184            flow->lastGetBuffer += *bufferSize2;
2185            if(*bufferSize2>0) {
2186                rc = BMEM_Heap_ConvertAddressToCached(g_pCoreHandles->heap[0], (void *)*buffer2, (void **)buffer2);
2187                if (rc) return BERR_TRACE(rc);
2188                NEXUS_FlushCache(*buffer2, *bufferSize2);
2189            } else {
2190                *buffer2 = NULL;
2191            }
2192        }
2193    }
2194    return rc;
2195}
2196
2197
2198NEXUS_Error NEXUS_Recpump_GetDataBuffer(NEXUS_RecpumpHandle r, const void **pBuffer, size_t *pAmount)
2199{
2200    BDBG_OBJECT_ASSERT(r, NEXUS_Recpump);
2201    return NEXUS_Recpump_P_GetBufferApi(&r->data, pBuffer, pAmount, NULL, NULL);
2202}
2203
2204NEXUS_Error NEXUS_Recpump_GetDataBufferWithWrap( NEXUS_RecpumpHandle r, const void **pBuffer, size_t *pAmount, const void **pBuffer2, size_t *pAmount2 )
2205{
2206    BDBG_OBJECT_ASSERT(r, NEXUS_Recpump);
2207    return NEXUS_Recpump_P_GetBufferApi(&r->data, pBuffer, pAmount, pBuffer2, pAmount2);
2208}
2209
2210NEXUS_Error NEXUS_Recpump_DataReadComplete(NEXUS_RecpumpHandle r, size_t amount)
2211{
2212    BDBG_OBJECT_ASSERT(r, NEXUS_Recpump);
2213    return NEXUS_Recpump_P_WriteComplete(&r->data, amount);
2214}
2215
2216NEXUS_Error NEXUS_Recpump_GetIndexBuffer(NEXUS_RecpumpHandle r, const void **pBuffer, size_t *pAmount)
2217{
2218    BDBG_OBJECT_ASSERT(r, NEXUS_Recpump);
2219    return NEXUS_Recpump_P_GetBufferApi(&r->index, pBuffer, pAmount, NULL, NULL);
2220}
2221
2222NEXUS_Error NEXUS_Recpump_GetIndexBufferWithWrap( NEXUS_RecpumpHandle r, const void **pBuffer, size_t *pAmount, const void **pBuffer2, size_t *pAmount2)
2223{
2224    BDBG_OBJECT_ASSERT(r, NEXUS_Recpump);
2225    return NEXUS_Recpump_P_GetBufferApi(&r->index, pBuffer, pAmount, pBuffer2, pAmount2);
2226}
2227
2228NEXUS_Error NEXUS_Recpump_IndexReadComplete(NEXUS_RecpumpHandle r, size_t amount)
2229{
2230    BDBG_OBJECT_ASSERT(r, NEXUS_Recpump);
2231    return NEXUS_Recpump_P_WriteComplete(&r->index, amount);
2232}
2233
2234NEXUS_Error NEXUS_Recpump_GetStatus(NEXUS_RecpumpHandle r, NEXUS_RecpumpStatus *pStatus)
2235{
2236    BERR_Code rc;
2237    BXPT_Rave_ContextPtrs ptrs;
2238    BXPT_Rave_DataPtrs *ptr;
2239    BXPT_Rave_RecordStats stats;
2240    NEXUS_Recpump_P_PidChannel *pid;
2241
2242    BDBG_OBJECT_ASSERT(r, NEXUS_Recpump);
2243    BKNI_Memset(pStatus, 0, sizeof(*pStatus));
2244
2245    pStatus->openSettings = r->openSettings;
2246    pStatus->rave.index = r->rave_rec_index;
2247
2248    rc = BXPT_Rave_CheckBuffer(r->rave_rec, &ptrs);
2249    if (rc) return BERR_TRACE(rc);
2250    rc = BXPT_Rave_GetRecordStats(r->rave_rec, &stats);
2251    if (rc) return BERR_TRACE(rc);
2252
2253    ptr = &ptrs.Cdb;
2254    pStatus->data.bytesRecorded = (unsigned long)stats.ByteCount;
2255    pStatus->data.bufferBase = r->data.bufferBase;
2256    pStatus->data.fifoDepth = (unsigned long)(ptr->ByteCount + ptr->WrapByteCount);
2257    pStatus->data.fifoSize =  r->data.bufferSize;
2258    if (pStatus->data.fifoDepth > pStatus->data.fifoSize) {
2259        BDBG_ERR(("Invalid RAVE CDB depth %d, size %d", pStatus->data.fifoDepth, pStatus->data.fifoSize));
2260        pStatus->data.fifoDepth = 0;
2261        return BERR_TRACE(NEXUS_UNKNOWN);
2262    }
2263
2264    ptr = &ptrs.Itb;
2265    pStatus->index.bytesRecorded = r->index.bytesRecorded;
2266    pStatus->index.bufferBase = r->index.bufferBase;
2267    pStatus->index.fifoDepth = (unsigned long)(ptr->ByteCount + ptr->WrapByteCount);
2268    pStatus->index.fifoSize = r->index.bufferSize;
2269    if (pStatus->index.fifoDepth > pStatus->index.fifoSize) {
2270        BDBG_ERR(("Invalid RAVE ITB depth %d, size %d", pStatus->index.fifoDepth, pStatus->index.fifoSize));
2271        pStatus->index.fifoDepth = 0;
2272        return BERR_TRACE(NEXUS_UNKNOWN);
2273    }
2274   
2275    for(pid=BLST_S_FIRST(&r->pid_list);pid;pid=BLST_S_NEXT(pid, link)) {
2276        if (NEXUS_RECPUMP_PID_IS_INDEX(&pid->settings)) {
2277            pStatus->hasIndex = true;
2278            break;
2279        }
2280    }
2281   
2282    return 0;
2283}
2284
2285static bool
2286NEXUS_Recpump_P_TestDataReadyCallback(struct NEXUS_RecpumpFlow *flow)
2287{
2288    const void *buffer, *buffer2;
2289    bool bypassThresholdTest = false;
2290    size_t size = 0, size2 = 0;
2291
2292    if (flow->recpump->rave_state == Terminated) {
2293        return false;
2294    }
2295
2296    if (NEXUS_Recpump_P_GetBuffer(flow, &buffer, &size, &buffer2, &size2, &bypassThresholdTest)!=NEXUS_SUCCESS) {
2297        return false;
2298    }
2299
2300    /* If we haven't exceeded the threshold, we should not fire the dataReady callback. Excessive callbacks lead to poor performance.
2301    However, we must always fire the callback at the wraparound so the application doesn't get stuck if relying on this callback.
2302    Must apply NEXUS_RAVE_THRESHOLD_UNITS adjustment before comparing with flow->dataReadyThreshold because XPT is one-based, not zero-based. */
2303    if (size+NEXUS_RAVE_THRESHOLD_UNITS < flow->dataReadyThreshold && !bypassThresholdTest) {
2304        return false;
2305    }
2306
2307    if (flow->pending) {
2308        return false;
2309    }
2310
2311    flow->pending = true;
2312    BDBG_MSG(("dataReady[%s] size=%d", NEXUS_P_FLOW_NAME(flow), size));
2313
2314    NEXUS_TaskCallback_Fire(flow->dataReadyCallback);
2315    return true;
2316}
2317
2318static void
2319NEXUS_Recpump_P_RaveEvent(void *flow_)
2320{
2321    struct NEXUS_RecpumpFlow *flow = flow_;
2322    BDBG_MSG(("NEXUS_Recpump_P_RaveEvent:%#lx %s", (unsigned long)flow, NEXUS_P_FLOW_NAME(flow)));
2323
2324    /* it's normal that we may get an event even though there's no dataready callback. there may be a rave event set
2325    while a WriteComplete finishes. no need to test here. */
2326    (void)NEXUS_Recpump_P_TestDataReadyCallback(flow);
2327}
2328
2329static NEXUS_Error
2330NEXUS_Recpump_P_StartFlow(struct NEXUS_RecpumpFlow *flow)
2331{
2332    flow->eventHandle = NEXUS_RegisterEvent(flow->event, NEXUS_Recpump_P_RaveEvent, flow);
2333    if (!flow->eventHandle) {
2334        return BERR_TRACE(NEXUS_UNKNOWN);
2335    }
2336    flow->pending = false;
2337    flow->bytesRecorded = 0;
2338    return 0;
2339}
2340
2341static void
2342NEXUS_Recpump_P_StopFlow(struct NEXUS_RecpumpFlow *flow)
2343{
2344    bool data = true;
2345
2346    /* we can disable events immediately because we'll do an explicit check for new descriptors
2347    at the bottom */
2348    NEXUS_UnregisterEvent(flow->eventHandle);
2349
2350    /* We should clean up here and empty the rave buffers by calling the usercallbacks */
2351    /* if there are any descriptors pending, this will fire a callback */
2352
2353    /* TODO: this has a bug in Settop API. please see Settop API for fix, then reapply */
2354    while (data) {
2355        /* empty out all data from this flow */
2356        data = NEXUS_Recpump_P_TestDataReadyCallback(flow);
2357    }
2358}
2359
2360void NEXUS_Recpump_GetDefaultTpitFilter( NEXUS_RecpumpTpitFilter *pFilter )
2361{
2362    BKNI_Memset(pFilter, 0, sizeof(*pFilter));
2363    pFilter->mpegMode = true;
2364}
2365
2366NEXUS_Error NEXUS_Recpump_SetTpitFilter( NEXUS_RecpumpHandle r, NEXUS_PidChannelHandle pidChannel, const NEXUS_RecpumpTpitFilter *pFilter )
2367{
2368    BERR_Code rc;
2369    NEXUS_Recpump_P_PidChannel *pid;
2370    NEXUS_Recpump_P_PidChannel *pid1;
2371
2372    BDBG_OBJECT_ASSERT(r, NEXUS_Recpump);
2373    BDBG_OBJECT_ASSERT(pidChannel, NEXUS_PidChannel);
2374    BDBG_CASSERT(sizeof(BXPT_Rave_TpitEntry) == sizeof(NEXUS_RecpumpTpitFilter));
2375    BDBG_CASSERT(NEXUS_NUM_TPIT_PIDS <= BXPT_NUM_TPIT_PIDS);
2376
2377    BLST_S_DICT_FIND(&r->pid_list, pid, pidChannel, pidChn, link);
2378    if(pid==NULL) {
2379        BDBG_WRN(("NEXUS_Recpump_SetTpitFilter: %#lx can't find pid:%#lx", (unsigned long)r, (unsigned long)pidChannel));
2380        rc = BERR_TRACE(NEXUS_INVALID_PARAMETER);
2381        goto err_pid;
2382    }
2383
2384
2385    if (pFilter) {
2386        /* validation */
2387        if (pFilter->mpegMode != !NEXUS_IS_DSS_MODE(r->inputTransportType)) {
2388            BDBG_ERR(("NEXUS_RecpumpTpitFilter.mpegMode does not match parser band's transportType"));
2389            return BERR_TRACE(NEXUS_INVALID_PARAMETER);
2390        }
2391
2392        /* recpump init */
2393        if (r->tpitCount == 0) {
2394            BDBG_ASSERT(!r->tpitIdx);
2395            rc = BXPT_Rave_AllocIndexer(pTransport->rave[0].channel, BXPT_RaveIdx_eTpit, 1, r->rave_rec, &r->tpitIdx);
2396            if (rc) return BERR_TRACE(rc);
2397        }
2398
2399        if (!pid->tpit.enabled) {
2400            /* enable a new filter. this requires finding an available tpit filter index.
2401            this search doesn't assume BXPT_P_MAX_TPIT_PIDS is > or < than NEXUS_TOTAL_RECPUMP_PIDCHANNELS. */
2402            unsigned availableIndex;
2403            for (availableIndex=0;availableIndex<BXPT_NUM_TPIT_PIDS;availableIndex++) {
2404                bool taken = false;
2405
2406                for(pid1=NULL, pid1=BLST_S_FIRST(&r->pid_list);pid1;pid1=BLST_S_NEXT(pid1, link)) {
2407                     if (pid1->pidChn != pidChannel && pid1->tpit.enabled) {
2408                        if (pid1->tpit.index == availableIndex) {
2409                            BDBG_ASSERT(availableIndex <= BXPT_NUM_TPIT_PIDS);
2410                            taken = true;
2411                            break;
2412                        }
2413                    }
2414                }
2415                if (!taken) break;
2416            }
2417            if (availableIndex == BXPT_NUM_TPIT_PIDS) {
2418                return BERR_TRACE(NEXUS_NOT_SUPPORTED);
2419            }
2420
2421            pid->tpit.index = availableIndex;
2422        }
2423
2424        pid->tpit.filter = *pFilter;
2425        pid->tpit.filter.pid = pidChannel->status.pid; /* force the pid */
2426
2427        /*BDBG_MSG(("setting tpit filter slot %d: tpit index %d", i, pid->tpit.index));*/
2428        rc = BXPT_Rave_SetTpitFilter(r->tpitIdx, pid->tpit.index, (const BXPT_Rave_TpitEntry *)&pid->tpit.filter);
2429        if (rc) return BERR_TRACE(rc);
2430
2431        /* only do bookkeeping after complete success */
2432        if (!pid->tpit.enabled) {
2433            pid->tpit.enabled = true;
2434            r->tpitCount++;
2435            BDBG_ASSERT(r->tpitCount);
2436        }
2437    }
2438    else {
2439        /* disable */
2440        if (pid->tpit.enabled) {
2441            BKNI_Memset(&pid->tpit.filter, 0, sizeof(pid->tpit.filter));
2442
2443            /*BDBG_MSG(("unsetting tpit filter slot %d: tpit index %d", i, pid->tpit.index));*/
2444            (void)BXPT_Rave_SetTpitFilter(r->tpitIdx, pid->tpit.index, (const BXPT_Rave_TpitEntry *)&pid->tpit.filter);
2445            /* don't fail on the disable. we can't mess up the bookkeeping. */
2446
2447            pid->tpit.enabled = false;
2448            pid->tpit.index = 0xFFFFFFFF; /* don't care */
2449            BDBG_ASSERT(r->tpitCount);
2450            r->tpitCount--;
2451        }
2452
2453        /* recpump uninit */
2454        if (r->tpitCount == 0 && r->tpitIdx) {
2455            BXPT_Rave_FreeIndexer(r->tpitIdx);
2456            r->tpitIdx = NULL;
2457        }
2458    }
2459
2460    return 0;
2461err_pid:
2462    return rc;
2463}
Note: See TracBrowser for help on using the repository browser.