| 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 | /* |
|---|
| 469 | security & dma options |
|---|
| 470 | 1) NEXUS_ENCRYPTED_DVR_WITH_M2M - nexus uses M2M DMA to decrypt |
|---|
| 471 | 2) otherwise - nexus uses keyslots to decrypt |
|---|
| 472 | There is no current option for NEXUS_HAS_DMA-only or internal hooks for SW-based decrypt (ala playpump external crypto) |
|---|
| 473 | */ |
|---|
| 474 | |
|---|
| 475 | BDBG_MODULE(nexus_recpump); |
|---|
| 476 | |
|---|
| 477 | #define BDBG_MSG_TRACE(x) /* BDBG_MSG(x) */ |
|---|
| 478 | |
|---|
| 479 | struct 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 | |
|---|
| 500 | BDBG_OBJECT_ID(NEXUS_Recpump); |
|---|
| 501 | |
|---|
| 502 | typedef 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 | |
|---|
| 514 | struct 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 | |
|---|
| 579 | static NEXUS_Error NEXUS_Recpump_P_Start(NEXUS_RecpumpHandle r); |
|---|
| 580 | static NEXUS_Error NEXUS_Recpump_P_StartFlow(struct NEXUS_RecpumpFlow *flow); |
|---|
| 581 | static void NEXUS_Recpump_P_StopFlow(struct NEXUS_RecpumpFlow *flow); |
|---|
| 582 | static 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 | |
|---|
| 591 | void 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 | |
|---|
| 611 | void 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 |
|---|
| 628 | static void |
|---|
| 629 | NEXUS_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 | |
|---|
| 645 | static void |
|---|
| 646 | NEXUS_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 */ |
|---|
| 655 | static NEXUS_Error |
|---|
| 656 | NEXUS_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 | |
|---|
| 681 | NEXUS_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 | |
|---|
| 922 | error: |
|---|
| 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 | |
|---|
| 933 | void 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 | |
|---|
| 1021 | void NEXUS_Recpump_GetSettings(NEXUS_RecpumpHandle r, NEXUS_RecpumpSettings *pSettings) |
|---|
| 1022 | { |
|---|
| 1023 | BDBG_OBJECT_ASSERT(r, NEXUS_Recpump); |
|---|
| 1024 | *pSettings = r->settings; |
|---|
| 1025 | } |
|---|
| 1026 | |
|---|
| 1027 | NEXUS_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 | |
|---|
| 1060 | static 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 | |
|---|
| 1078 | static 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 | |
|---|
| 1092 | static 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 | |
|---|
| 1111 | static 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 |
|---|
| 1581 | err_dma: |
|---|
| 1582 | NEXUS_Recpump_P_StopFlow(&r->index); |
|---|
| 1583 | #endif |
|---|
| 1584 | err_record_scd: |
|---|
| 1585 | NEXUS_Recpump_P_StopFlow(&r->data); |
|---|
| 1586 | err_record_data: |
|---|
| 1587 | BXPT_Rave_DisableContext(r->rave_rec); |
|---|
| 1588 | err_rave: |
|---|
| 1589 | BDBG_ASSERT(rc); |
|---|
| 1590 | return rc; |
|---|
| 1591 | } |
|---|
| 1592 | |
|---|
| 1593 | NEXUS_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 | |
|---|
| 1622 | void 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 | |
|---|
| 1683 | void 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 | |
|---|
| 1695 | void 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 | |
|---|
| 1717 | NEXUS_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 | |
|---|
| 1815 | error: |
|---|
| 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; |
|---|
| 1821 | err_duplicate: |
|---|
| 1822 | rc = BERR_TRACE(NEXUS_INVALID_PARAMETER); |
|---|
| 1823 | BKNI_Free(pid); |
|---|
| 1824 | return rc; |
|---|
| 1825 | } |
|---|
| 1826 | |
|---|
| 1827 | NEXUS_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; |
|---|
| 1866 | err_pid: |
|---|
| 1867 | return rc; |
|---|
| 1868 | } |
|---|
| 1869 | |
|---|
| 1870 | void 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 | |
|---|
| 1883 | static NEXUS_Error |
|---|
| 1884 | NEXUS_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 | |
|---|
| 2057 | done: |
|---|
| 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 | |
|---|
| 2105 | static NEXUS_Error |
|---|
| 2106 | NEXUS_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 */ |
|---|
| 2166 | static NEXUS_Error |
|---|
| 2167 | NEXUS_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 | |
|---|
| 2198 | NEXUS_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 | |
|---|
| 2204 | NEXUS_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 | |
|---|
| 2210 | NEXUS_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 | |
|---|
| 2216 | NEXUS_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 | |
|---|
| 2222 | NEXUS_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 | |
|---|
| 2228 | NEXUS_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 | |
|---|
| 2234 | NEXUS_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 | |
|---|
| 2285 | static bool |
|---|
| 2286 | NEXUS_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 | |
|---|
| 2318 | static void |
|---|
| 2319 | NEXUS_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 | |
|---|
| 2329 | static NEXUS_Error |
|---|
| 2330 | NEXUS_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 | |
|---|
| 2341 | static void |
|---|
| 2342 | NEXUS_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 | |
|---|
| 2360 | void NEXUS_Recpump_GetDefaultTpitFilter( NEXUS_RecpumpTpitFilter *pFilter ) |
|---|
| 2361 | { |
|---|
| 2362 | BKNI_Memset(pFilter, 0, sizeof(*pFilter)); |
|---|
| 2363 | pFilter->mpegMode = true; |
|---|
| 2364 | } |
|---|
| 2365 | |
|---|
| 2366 | NEXUS_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; |
|---|
| 2461 | err_pid: |
|---|
| 2462 | return rc; |
|---|
| 2463 | } |
|---|