Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2076 lines
82 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1999 - 2000
  3. Module Name:
  4. MSDVLowr.c
  5. Abstract:
  6. Interface code with 61883 or 1394 class driver.
  7. Last changed by:
  8. Author: Yee J. Wu
  9. Environment:
  10. Kernel mode only
  11. Revision History:
  12. $Revision:: $
  13. $Date:: $
  14. --*/
  15. #include "strmini.h"
  16. #include "ksmedia.h"
  17. #include "1394.h"
  18. #include "61883.h"
  19. #include "dbg.h"
  20. #include "msdvfmt.h"
  21. #include "msdvdef.h"
  22. #include "MSDVUtil.h"
  23. #include "MSDVGuts.h"
  24. #include "XPrtDefs.h"
  25. #include "EDevCtrl.h"
  26. extern DV_FORMAT_INFO DVFormatInfoTable[];
  27. extern const GUID KSEVENTSETID_Connection_Local;
  28. //
  29. // Simple function prototype
  30. //
  31. VOID
  32. DVSRBRead(
  33. IN PKSSTREAM_HEADER pStrmHeader,
  34. IN ULONG ulFrameSize,
  35. IN PDVCR_EXTENSION pDevExt,
  36. IN PSTREAMEX pStrmExt,
  37. IN PHW_STREAM_REQUEST_BLOCK pSrb // needs Srb->Status
  38. );
  39. NTSTATUS
  40. DVAttachWriteFrame(
  41. IN PSTREAMEX pStrmExt
  42. );
  43. VOID
  44. DVFormatAttachFrame(
  45. IN KSPIN_DATAFLOW DataFlow,
  46. IN PSTREAMEX pStrmExt,
  47. IN PAV_61883_REQUEST pAVReq,
  48. IN PHW_STREAM_REQUEST_BLOCK pSrb,
  49. IN PSRB_DATA_PACKET pSrbDataPacket,
  50. IN ULONG ulSourceLength, // Packet length in bytes
  51. IN ULONG ulFrameSize,
  52. IN PVOID pFrameBuffer
  53. );
  54. #if DBG
  55. ULONG cntInvSrcPkt = 0;
  56. #endif
  57. #if 0 // Enable later
  58. #ifdef ALLOC_PRAGMA
  59. #pragma alloc_text(PAGE, DVSRBRead)
  60. #pragma alloc_text(PAGE, DVFormatAttachFrame)
  61. #pragma alloc_text(PAGE, DVAttachFrameThread)
  62. #pragma alloc_text(PAGE, DVTerminateAttachFrameThread)
  63. #pragma alloc_text(PAGE, DVAttachWriteFrame)
  64. #pragma alloc_text(PAGE, DVFormatAttachFrame)
  65. #endif
  66. #endif
  67. ULONG
  68. DVReadFrameValidate(
  69. IN PCIP_VALIDATE_INFO pInfo
  70. )
  71. /*++
  72. Routine Description:
  73. Used to detect the start of a DV frame. A DV frame is started with a header section.
  74. Return
  75. 0 verified
  76. 1: invallid
  77. --*/
  78. {
  79. if(pInfo->Packet) {
  80. //
  81. // Detect header 0 signature.
  82. //
  83. if(
  84. (pInfo->Packet[0] & DIF_BLK_ID0_SCT_MASK) == 0
  85. && (pInfo->Packet[1] & DIF_BLK_ID1_DSEQ_MASK) == 0
  86. && (pInfo->Packet[2] & DIF_BLK_ID2_DBN_MASK) == 0
  87. ) {
  88. //
  89. // This can be used to detect dynamic format change if this function is called
  90. // to check for data packets always. This may require setting this flag:
  91. // CIP_VALIDATE_ALL_SOURCE instead of CIP_VALIDATE_FIRST_SOURCE
  92. //
  93. #if 0 // DBG
  94. PSRB_DATA_PACKET pSrbDataPacket = pInfo->Context;
  95. PSTREAMEX pStrmExt = pSrbDataPacket->pStrmExt;
  96. PDVCR_EXTENSION pDevExt = pStrmExt->pDevExt;
  97. if((pInfo->Packet[0] & DIF_HEADER_DSF) == 0) {
  98. // Indicate a 10 DIF sequences include in a video frame (525-60)/NTSC.
  99. if(
  100. pDevExt->VideoFormatIndex == FMT_IDX_SD_DVCR_PAL
  101. || pDevExt->VideoFormatIndex == FMT_IDX_SDL_DVCR_PAL
  102. ) {
  103. // Dynamic format changes!!
  104. TRACE(TL_STRM_ERROR|TL_CIP_WARNING,("Detect dynamic format change PAL -> NTSC!\n"));
  105. }
  106. } else {
  107. // Indicate a 12 DIF sequences include in a video frame (625-50)/PAL.
  108. if(
  109. pDevExt->VideoFormatIndex == FMT_IDX_SD_DVCR_NTSC
  110. || pDevExt->VideoFormatIndex == FMT_IDX_SDL_DVCR_NTSC
  111. ) {
  112. // Dynamic format changes!!
  113. TRACE(TL_STRM_ERROR|TL_CIP_WARNING,("Detect dynamic format change NTSC -> PAL!\n"));
  114. }
  115. }
  116. #endif
  117. // Check TF1, TF2, and TF3: 1: not transmitted; 0:transmitted
  118. // TF1:Audio; TF2:Video; TF3:Subcode; they all need to be 0 to be valid.
  119. if(
  120. (pInfo->Packet[5] & DIF_HEADER_TFn)
  121. || (pInfo->Packet[6] & DIF_HEADER_TFn)
  122. || (pInfo->Packet[7] & DIF_HEADER_TFn)
  123. ) {
  124. TRACE(TL_STRM_ERROR|TL_CIP_WARNING,("\'%d inv src pkts; [%x %x %d %x], [%x %x %x %x]\n",
  125. cntInvSrcPkt,
  126. pInfo->Packet[0],
  127. pInfo->Packet[1],
  128. pInfo->Packet[2],
  129. pInfo->Packet[3],
  130. pInfo->Packet[4],
  131. pInfo->Packet[5],
  132. pInfo->Packet[6],
  133. pInfo->Packet[7]
  134. ));
  135. // Valid header but DIF block for this area is not transmitted.
  136. // Some DV (such as DVCPro) may wait untill its "mecha and servo" to be stable to make these valid.
  137. // This should happen if a graph is in run state before a tape is played (and stablized).
  138. return 1;
  139. }
  140. #if DBG
  141. if(cntInvSrcPkt > 0) {
  142. TRACE(TL_CIP_TRACE,("\'%d inv src pkts; [%x %x %d %x] [%x %x %x %x]\n",
  143. cntInvSrcPkt,
  144. pInfo->Packet[0],
  145. pInfo->Packet[1],
  146. pInfo->Packet[2],
  147. pInfo->Packet[3],
  148. pInfo->Packet[4],
  149. pInfo->Packet[5],
  150. pInfo->Packet[6],
  151. pInfo->Packet[7]
  152. ));
  153. cntInvSrcPkt = 0; // Reset
  154. }
  155. #endif
  156. return 0;
  157. }
  158. else {
  159. #if DBG
  160. //
  161. // To detect invalid src pkt sequence;
  162. // If it exceeded the number of source packet per frame, we need to know about it.
  163. //
  164. PSRB_DATA_PACKET pSrbDataPacket = pInfo->Context;
  165. PSTREAMEX pStrmExt = pSrbDataPacket->pStrmExt;
  166. PDVCR_EXTENSION pDevExt = pStrmExt->pDevExt;
  167. if(++cntInvSrcPkt >= DVFormatInfoTable[pDevExt->VideoFormatIndex].ulSrcPackets) {
  168. TRACE(TL_CIP_TRACE,("(%d) Invalid SrcPkt >= max inv src pkt %d; ID0,1,2 = [%x %x %x]\n",
  169. cntInvSrcPkt,
  170. DVFormatInfoTable[pDevExt->VideoFormatIndex].ulSrcPackets,
  171. pInfo->Packet[0], pInfo->Packet[1], pInfo->Packet[2]
  172. ));
  173. if(DVTraceMask & TL_CIP_TRACE) {
  174. ASSERT(cntInvSrcPkt < DVFormatInfoTable[pDevExt->VideoFormatIndex].ulSrcPackets);
  175. }
  176. cntInvSrcPkt = 0; // Reset
  177. }
  178. else {
  179. TRACE(TL_CIP_INFO,("(%d) Invalid SrcPktSeq; ID0,1,2 = [%x,%x,%x]\n",
  180. cntInvSrcPkt, pInfo->Packet[0], pInfo->Packet[1], pInfo->Packet[2] ));
  181. }
  182. #endif
  183. return 1;
  184. }
  185. }
  186. else {
  187. TRACE(TL_CIP_WARNING, ("\'Validate: invalid SrcPktSeq; Packet %x\n", pInfo->Packet));
  188. return 1;
  189. }
  190. } // DVReadFrameValidate
  191. #if DBG
  192. LONGLONG PreviousPictureNumber;
  193. LONGLONG PreviousTime;
  194. CYCLE_TIME PreviousTimestamp;
  195. #endif
  196. ULONG
  197. DVCompleteSrbRead(
  198. PCIP_NOTIFY_INFO pInfo
  199. )
  200. /*++
  201. Routine Description:
  202. 61883 has completed receiving data and callback to us to complete.
  203. --*/
  204. {
  205. PSRB_DATA_PACKET pSrbDataPacket;
  206. PHW_STREAM_REQUEST_BLOCK pSrb;
  207. PKSSTREAM_HEADER pStrmHeader;
  208. PDVCR_EXTENSION pDevExt;
  209. PSTREAMEX pStrmExt;
  210. LONGLONG LastPictureNumber;
  211. PUCHAR pFrameBuffer;
  212. KIRQL oldIrql;
  213. PKS_FRAME_INFO pFrameInfo; // For VidOnly pin only
  214. #if DBG
  215. PXMT_FRAME_STAT pXmtStat;
  216. #endif
  217. // Callback and might be at the DISPATCH_LEVEL
  218. // The caller might have acquired spinlock as well!
  219. pSrbDataPacket = pInfo->Context;
  220. if(!pSrbDataPacket) {
  221. ASSERT(pSrbDataPacket && "Context is NULL!");
  222. return 1;
  223. }
  224. pStrmExt = pSrbDataPacket->pStrmExt;
  225. KeAcquireSpinLock(pStrmExt->DataListLock, &oldIrql);
  226. #if DBG
  227. // Once it is completed by 61883, it becomes non-cancellable.
  228. if(!pStrmExt->bIsochIsActive) {
  229. TRACE(TL_CIP_WARNING,("CompleteSrbRead: bIsochActive:%d; pSrbDataPacket:%x\n", pStrmExt->bIsochIsActive, pSrbDataPacket));
  230. }
  231. #endif
  232. pSrb = pSrbDataPacket->pSrb; ASSERT(pSrbDataPacket->pSrb);
  233. pDevExt = pStrmExt->pDevExt;
  234. pFrameBuffer = (PUCHAR) pSrbDataPacket->FrameBuffer;
  235. pStrmHeader = pSrb->CommandData.DataBufferArray; ASSERT(pStrmHeader->Size >= sizeof(KSSTREAM_HEADER));
  236. //
  237. // Check CIP_STATUS_* from 61883
  238. //
  239. // CIP_STATUS_CORRUPT_FRAME (0x00000001) // isoch header or cip header was incorrect
  240. if(pSrbDataPacket->Frame->Status & CIP_STATUS_CORRUPT_FRAME) {
  241. TRACE(TL_STRM_WARNING|TL_CIP_TRACE,("\'CIP_STATUS_CORRUPT_FRAME\n"));
  242. pStrmHeader->OptionsFlags = 0;
  243. pSrb->Status = STATUS_SUCCESS; // Success but no data !
  244. pStrmHeader->DataUsed = 0;
  245. pStrmExt->PictureNumber++; pStrmExt->FramesProcessed++;
  246. }
  247. else
  248. // CIP_STATUS_SUCCESS (0x00000000) // 0 so cannot do bitwise operation!!
  249. // CIP_STATUS_FIRST_FRAME (0x00000002) // First attached frame to 61883
  250. if(pSrbDataPacket->Frame->Status == CIP_STATUS_SUCCESS ||
  251. (pSrbDataPacket->Frame->Status & CIP_STATUS_FIRST_FRAME)) {
  252. // Only increment FramesProcessed if it is a valid frame;
  253. pStrmExt->FramesProcessed++;
  254. pSrb->Status = STATUS_SUCCESS;
  255. pStrmHeader->OptionsFlags = KSSTREAM_HEADER_OPTIONSF_SPLICEPOINT;
  256. pStrmHeader->DataUsed = DVFormatInfoTable[pDevExt->VideoFormatIndex].ulFrameSize;
  257. // Put in Timestamp info depending on clock provider
  258. pStrmHeader->PresentationTime.Numerator = 1;
  259. pStrmHeader->PresentationTime.Denominator = 1;
  260. if(pStrmExt->hMasterClock || pStrmExt->hClock) {
  261. pStrmHeader->Duration =
  262. DVFormatInfoTable[pDevExt->VideoFormatIndex].ulAvgTimePerFrame;
  263. pStrmHeader->OptionsFlags |=
  264. (KSSTREAM_HEADER_OPTIONSF_TIMEVALID | // pStrmHeader->PresentationTime.Time is valid
  265. KSSTREAM_HEADER_OPTIONSF_DURATIONVALID);
  266. }
  267. //
  268. // Only if there is a clock, presentation time and drop frames information are set.
  269. // Acoording to DDK:
  270. // The PictureNumber member count represents the idealized count of the current picture,
  271. // which is calculated in one of two ways:
  272. // ("Other" clock) Measure the time since the stream was started and divide by the frame duration.
  273. // (MasterClock) Add together the count of frames captured and the count of frame dropped.
  274. //
  275. // Other device (audio?) is the clock provider
  276. if(pStrmExt->hClock) {
  277. pStrmExt->TimeContext.HwDeviceExtension = (struct _HW_DEVICE_EXTENSION *) pDevExt;
  278. pStrmExt->TimeContext.HwStreamObject = pStrmExt->pStrmObject;
  279. pStrmExt->TimeContext.Function = TIME_GET_STREAM_TIME;
  280. pStrmExt->TimeContext.Time = 0;
  281. pStrmExt->TimeContext.SystemTime = 0;
  282. StreamClassQueryMasterClockSync(
  283. pStrmExt->hClock,
  284. &(pStrmExt->TimeContext)
  285. );
  286. pStrmHeader->PresentationTime.Time = pStrmExt->CurrentStreamTime = pStrmExt->TimeContext.Time;
  287. // Calculate picture number and dropped frame;
  288. // For NTSC, it could be 267 or 266 packet time per frame. Since integer calculation will round,
  289. // we will add a packet time (TIME_PER_CYCLE = 125 us = 1250 100nsec) to that.This is only used for calculation.
  290. LastPictureNumber = pStrmExt->PictureNumber;
  291. pStrmExt->PictureNumber =
  292. 1 + // Picture number start with 1.
  293. (pStrmHeader->PresentationTime.Time + TIME_PER_CYCLE)
  294. * (LONGLONG) GET_AVG_TIME_PER_FRAME_DENOM(pStrmExt->pDevExt->VideoFormatIndex)
  295. / (LONGLONG) GET_AVG_TIME_PER_FRAME_NUM(pStrmExt->pDevExt->VideoFormatIndex);
  296. // Detect discontinuity
  297. if(pStrmExt->PictureNumber > LastPictureNumber+1) {
  298. pStrmHeader->OptionsFlags |= KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY; // If there is a skipped frame, set the discontinuity flag
  299. TRACE(TL_CIP_WARNING,("\'Discontinuity: LastPic#:%d; Pic#%d; PresTime:%d;\n", (DWORD) LastPictureNumber, (DWORD) pStrmExt->PictureNumber, (DWORD) pStrmHeader->PresentationTime.Time));
  300. }
  301. // Detect if picture number did not progress.
  302. // This could be due to two frame being completely very close to each other.
  303. if(pStrmExt->PictureNumber <= LastPictureNumber) {
  304. TRACE(TL_CIP_WARNING,("\'hClock:Same pic #:(%d->%d); tmPres:(%d->%d); (%d:%d:%d) -> (%d:%d:%d); AQD[%d:%d:%d]\n",
  305. (DWORD) PreviousPictureNumber,
  306. (DWORD) pStrmExt->PictureNumber,
  307. (DWORD) PreviousTime,
  308. (DWORD) pStrmHeader->PresentationTime.Time,
  309. PreviousTimestamp.CL_SecondCount, PreviousTimestamp.CL_CycleCount, PreviousTimestamp.CL_CycleOffset,
  310. pSrbDataPacket->Frame->Timestamp.CL_SecondCount,
  311. pSrbDataPacket->Frame->Timestamp.CL_CycleCount,
  312. pSrbDataPacket->Frame->Timestamp.CL_CycleOffset,
  313. pStrmExt->cntDataAttached,
  314. pStrmExt->cntSRBQueued,
  315. pStrmExt->cntDataDetached
  316. ));
  317. pStrmExt->PictureNumber = LastPictureNumber + 1; // Picture number must progress !!!!
  318. }
  319. #if DBG
  320. PreviousPictureNumber = pStrmExt->PictureNumber;
  321. PreviousTime = pStrmHeader->PresentationTime.Time;
  322. PreviousTimestamp = pSrbDataPacket->Frame->Timestamp;
  323. #endif
  324. pStrmExt->FramesDropped = pStrmExt->PictureNumber - pStrmExt->FramesProcessed;
  325. // This subunit driver is a Master clock
  326. } else if (pStrmExt->hMasterClock) {
  327. #ifdef NT51_61883
  328. ULONG ulDeltaCycleCounts;
  329. // No drop frame for PAUSE->RUN transition
  330. if(pStrmExt->b1stNewFrameFromPauseState) {
  331. pStrmHeader->OptionsFlags |= KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY;
  332. pStrmExt->b1stNewFrameFromPauseState = FALSE;
  333. } else {
  334. ULONG ulCycleCount16bits;
  335. // Calculate skipped 1394 cycle from the returned CycleTime
  336. VALIDATE_CYCLE_COUNTS(pSrbDataPacket->Frame->Timestamp);
  337. ulCycleCount16bits = CALCULATE_CYCLE_COUNTS(pSrbDataPacket->Frame->Timestamp);
  338. ulDeltaCycleCounts = CALCULATE_DELTA_CYCLE_COUNT(pStrmExt->CycleCount16bits, ulCycleCount16bits);
  339. // Adjust to max allowable gap to the max elapsed time of the CycleTime returned by OHCI 1394.
  340. if(ulDeltaCycleCounts > MAX_CYCLES)
  341. ulDeltaCycleCounts = MAX_CYCLES; // Wrap around
  342. //
  343. // There are two cases for drop frames:
  344. // (1) Starve of buffer; or,
  345. // (2) no data (blank tape or tape is not playing)
  346. //
  347. // For case (1), 61883 returns CIP_STATUS_FIRST_FRAME.
  348. if(pSrbDataPacket->Frame->Status & CIP_STATUS_FIRST_FRAME) {
  349. // Use cycle count to calculate drop frame. We substract 1 from the MaxSrcPacket on purpose to avoid truncating.
  350. // The max range is MAX_CYCLE (8 * 8000 = 64000 cycles)
  351. // 64000 * 125 * 3 / 100100 = 239.76
  352. // 64000 / 266 = 240
  353. // 64000 / 267 = 239
  354. if(ulDeltaCycleCounts >= (DVFormatInfoTable[pDevExt->VideoFormatIndex].ulMaxSrcPackets - 1)) {
  355. ULONG ulFrameElapsed = ulDeltaCycleCounts / (DVFormatInfoTable[pDevExt->VideoFormatIndex].ulMaxSrcPackets - 1);
  356. pStrmExt->FramesDropped += (ulFrameElapsed - 1); // There is a valid frame that is not dropped.
  357. }
  358. TRACE(TL_STRM_WARNING|TL_CIP_WARNING,("CIP_STATUS_FIRST_FRAME: Drop:%d; Processed:%d\n", (DWORD) pStrmExt->FramesDropped, pStrmExt->FramesProcessed ));
  359. pStrmHeader->OptionsFlags |= KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY;
  360. } else {
  361. // Ignore all "drop frames" in the "no data" case
  362. // pStrmExt->FramesDropped += 0;
  363. }
  364. }
  365. // If we are the clock provider, the stream time is based on sample number * AvgTimePerFrame
  366. pStrmExt->PictureNumber = pStrmExt->FramesProcessed + pStrmExt->FramesDropped;
  367. pStrmHeader->PresentationTime.Time = pStrmExt->CurrentStreamTime =
  368. pStrmExt->PictureNumber
  369. * (LONGLONG) GET_AVG_TIME_PER_FRAME_NUM(pStrmExt->pDevExt->VideoFormatIndex)
  370. / (LONGLONG) GET_AVG_TIME_PER_FRAME_DENOM(pStrmExt->pDevExt->VideoFormatIndex);
  371. // Use to adjust the queried stream time
  372. pStrmExt->LastSystemTime = GetSystemTime();
  373. // Cache current CycleCount
  374. pStrmExt->CycleCount16bits = CALCULATE_CYCLE_COUNTS(pSrbDataPacket->Frame->Timestamp);
  375. #if DBG
  376. // First frame or skipped frame
  377. if(pStrmExt->PictureNumber <= 1 ||
  378. pStrmExt->PictureNumber <= PreviousPictureNumber ||
  379. ulDeltaCycleCounts > DVFormatInfoTable[pDevExt->VideoFormatIndex].ulMaxSrcPackets
  380. )
  381. TRACE(TL_CIP_WARNING,("\'hMasterClock: Same pic #:(%d->%d); tmPres:(%d->%d); (%d:%d:%d) -> (%d:%d:%d); AQD[%d:%d:%d]\n",
  382. (DWORD) PreviousPictureNumber,
  383. (DWORD) pStrmExt->PictureNumber,
  384. (DWORD) PreviousTime,
  385. (DWORD) pStrmHeader->PresentationTime.Time,
  386. PreviousTimestamp.CL_SecondCount, PreviousTimestamp.CL_CycleCount, PreviousTimestamp.CL_CycleOffset,
  387. pSrbDataPacket->Frame->Timestamp.CL_SecondCount,
  388. pSrbDataPacket->Frame->Timestamp.CL_CycleCount,
  389. pSrbDataPacket->Frame->Timestamp.CL_CycleOffset,
  390. pStrmExt->cntDataAttached,
  391. pStrmExt->cntSRBQueued,
  392. pStrmExt->cntDataDetached
  393. ));
  394. PreviousPictureNumber = pStrmExt->PictureNumber;
  395. PreviousTime = pStrmHeader->PresentationTime.Time;
  396. PreviousTimestamp = pSrbDataPacket->Frame->Timestamp;
  397. #endif
  398. #else // NT51_61883
  399. // This is the old way when 61883 was not returning the correct CycleTime.
  400. pStrmHeader->PresentationTime.Time = pStrmExt->CurrentStreamTime;
  401. pStrmExt->LastSystemTime = GetSystemTime(); // Use to adjust the queried stream time
  402. pStrmExt->CurrentStreamTime += DVFormatInfoTable[pDevExt->VideoFormatIndex].ulAvgTimePerFrame;
  403. #endif // NT51_61883
  404. // no Clock so "free flowing!"
  405. } else {
  406. pStrmHeader->PresentationTime.Time = 0;
  407. pStrmHeader->Duration = 0; // No clock so not valid.
  408. pStrmExt->PictureNumber++;
  409. TRACE(TL_CIP_TRACE,("\'No clock: PicNum:%d\n", (DWORD) pStrmExt->PictureNumber));
  410. }
  411. }
  412. else {
  413. // 61883 has not defined this new status at this time!
  414. // Do not know what to do so we will complete it with 0 length for now.
  415. pStrmHeader->OptionsFlags = 0;
  416. pSrb->Status = STATUS_SUCCESS;
  417. pStrmHeader->DataUsed = 0;
  418. pStrmExt->PictureNumber++; pStrmExt->FramesProcessed++;
  419. TRACE(TL_STRM_WARNING|TL_CIP_ERROR,("pSrbDataPacket:%x; unexpected Frame->Status %x\n", pSrbDataPacket, pSrbDataPacket->Frame->Status));
  420. ASSERT(FALSE && "Unknown pSrbDataPacket->Frame->Status");
  421. }
  422. // For VidOnly which uses VideoInfoHeader and has
  423. // an extended frame information (KS_FRAME_INFO) appended to KSSTREAM_HEADER
  424. if( pDevExt->idxStreamNumber == 0 &&
  425. (pStrmHeader->Size >= (sizeof(KSSTREAM_HEADER) + sizeof(PKS_FRAME_INFO)))
  426. ) {
  427. pFrameInfo = (PKS_FRAME_INFO) (pStrmHeader + 1);
  428. pFrameInfo->ExtendedHeaderSize = sizeof(KS_FRAME_INFO);
  429. pFrameInfo->PictureNumber = pStrmExt->PictureNumber;
  430. pFrameInfo->DropCount = pStrmExt->FramesDropped;
  431. pFrameInfo->dwFrameFlags =
  432. KS_VIDEO_FLAG_FRAME | // Complete frame
  433. KS_VIDEO_FLAG_I_FRAME; // Every DV frame is an I frame
  434. }
  435. #if DBG
  436. // Validate that the data is return in the right sequence
  437. if(pSrbDataPacket->FrameNumber != pStrmExt->FramesProcessed) {
  438. TRACE(TL_STRM_WARNING|TL_CIP_ERROR,("\'pSrbDataPacket:%x; Status:%x; Out of Sequence %d != %d; (Dropped:%x)\n",
  439. pSrbDataPacket, pSrbDataPacket->Frame->Status,
  440. (DWORD) pSrbDataPacket->FrameNumber, (DWORD) pStrmExt->FramesProcessed,
  441. (DWORD) pStrmExt->FramesDropped
  442. ));
  443. };
  444. #endif
  445. #if DBG
  446. // Collect transmit buffer statistics
  447. if(pStrmExt->ulStatEntries < MAX_XMT_FRAMES_TRACED) {
  448. pXmtStat = pStrmExt->paXmtStat + pStrmExt->ulStatEntries;
  449. pXmtStat->StreamState = pStrmExt->StreamState;
  450. pXmtStat->cntSRBReceived = (LONG) pStrmExt->cntSRBReceived;
  451. pXmtStat->cntSRBPending = (LONG) pStrmExt->cntSRBPending;
  452. pXmtStat->cntSRBQueued = (LONG) pStrmExt->cntSRBQueued;
  453. pXmtStat->cntDataAttached= pStrmExt->cntDataAttached;
  454. pXmtStat->FrameSlot = (DWORD) pStrmExt->PictureNumber;
  455. pXmtStat->tmStreamTime = pStrmExt->CurrentStreamTime;
  456. pXmtStat->DropCount = (DWORD) pStrmExt->FramesDropped;
  457. pXmtStat->FrameNumber = (DWORD) pSrbDataPacket->FrameNumber;
  458. pXmtStat->OptionsFlags = pSrb->CommandData.DataBufferArray->OptionsFlags;
  459. pXmtStat->tmPresentation = pSrb->CommandData.DataBufferArray->PresentationTime.Time;
  460. pXmtStat->tsTransmitted= pSrbDataPacket->Frame->Timestamp;
  461. pStrmExt->ulStatEntries++;
  462. }
  463. #endif
  464. //
  465. // Mark completion is called.
  466. //
  467. pSrbDataPacket->State |= DE_IRP_CALLBACK_COMPLETED;
  468. //
  469. // Attached->Completed or Completed->Attached.
  470. //
  471. if(IsStateSet(pSrbDataPacket->State, DE_IRP_ATTACHED_COMPLETED)) {
  472. //
  473. // Recycle it back to the detach list
  474. //
  475. RemoveEntryList(&pSrbDataPacket->ListEntry); pStrmExt->cntDataAttached--; ASSERT(pStrmExt->cntDataAttached >= 0);
  476. InsertTailList(&pStrmExt->DataDetachedListHead, &pSrbDataPacket->ListEntry); pStrmExt->cntDataDetached++;
  477. #if DBG
  478. // Detect if 61883 is starve. This cause discontinuity.
  479. // This can happen for many valid reasons (slow system).
  480. // An assert is added to detect other unknown reason.
  481. if(pStrmExt->cntDataAttached == 0 && pStrmExt->StreamState == KSSTATE_RUN) {
  482. TRACE(TL_STRM_WARNING|TL_CIP_WARNING,("\n**** 61883 starved in RUN state (read); AQD[%d:%d:%d]\n\n",
  483. pStrmExt->cntDataAttached, pStrmExt->cntSRBQueued, pStrmExt->cntDataDetached
  484. ));
  485. // ASSERT(pStrmExt->cntDataAttached > 0 && "61883 is starve at RUN state!!");
  486. }
  487. #endif
  488. //
  489. // Complete this Srb
  490. //
  491. StreamClassStreamNotification(StreamRequestComplete, pStrmExt->pStrmObject, pSrbDataPacket->pSrb );
  492. pSrbDataPacket->State |= DE_IRP_SRB_COMPLETED; pSrbDataPacket->pSrb = NULL;
  493. #if DBG
  494. pStrmExt->cntSRBPending--;
  495. #endif
  496. } else {
  497. TRACE(TL_STRM_WARNING,("CompleteSrbRead: pSrbDataPacket:%x; Completed before attach.\n", pSrbDataPacket));
  498. }
  499. KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);
  500. return 0;
  501. } // DVCompleteSrbRead
  502. NTSTATUS
  503. DVAttachFrameCR(
  504. IN PDEVICE_OBJECT DeviceObject,
  505. IN PIRP pIrp,
  506. IN PSRB_DATA_PACKET pSrbDataPacket
  507. )
  508. /*++
  509. Routine Description:
  510. Completion routine for attaching a frame for transmitting.
  511. Apply to attaching listen and talk frame.
  512. --*/
  513. {
  514. PHW_STREAM_REQUEST_BLOCK pSrb;
  515. PSTREAMEX pStrmExt;
  516. PLONG plSrbUseCount; // When this count is 0, it can be completed.
  517. KIRQL oldIrql;
  518. pStrmExt = pSrbDataPacket->pStrmExt;
  519. KeAcquireSpinLock(pStrmExt->DataListLock, &oldIrql);
  520. pSrb = pSrbDataPacket->pSrb;
  521. // This entry is be already attached before IoCallDriver.
  522. // This is done this way because this buffer could be filled and
  523. // completed before the attach completion routine (here) is called.
  524. // If it is completed and callback is called,
  525. // pSrbDataPacket->pSrb has been set to NULL.
  526. // In the error case, pSrbDataPacket->pSrb should not be NULL.
  527. if(!NT_SUCCESS(pIrp->IoStatus.Status)) {
  528. if(pSrbDataPacket->pSrb == NULL) {
  529. // PBinder told me that this cannot happen.
  530. // A buffer is completed (pSRb set to NULL), and still return with an error!
  531. ASSERT(pSrbDataPacket->pSrb);
  532. KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);
  533. return STATUS_MORE_PROCESSING_REQUIRED;
  534. }
  535. pSrbDataPacket->State |= DE_IRP_ERROR;
  536. plSrbUseCount = (PLONG) (pSrb->SRBExtension);
  537. (*plSrbUseCount) --; // -- for being remove from queue
  538. ASSERT(*plSrbUseCount >= 0);
  539. TRACE(TL_CIP_ERROR,("DVAttachFrameCR: pSrb:%x; pSrb->Status:%x; failed pIrp->Status %x; UseCnt:%d\n", pSrb, pSrb->Status, pIrp->IoStatus.Status, *plSrbUseCount));
  540. ASSERT(NT_SUCCESS(pIrp->IoStatus.Status) && "DVAttachFrameCR");
  541. // Complete this SRB only if the count is 0.
  542. if(*plSrbUseCount == 0 && pSrb->Status != STATUS_CANCELLED) {
  543. pSrb->Status = pIrp->IoStatus.Status;
  544. pSrb->CommandData.DataBufferArray->DataUsed = 0;
  545. // Complete SRB
  546. StreamClassStreamNotification(StreamRequestComplete, pSrb->StreamObject, pSrbDataPacket->pSrb);
  547. pSrbDataPacket->State |= DE_IRP_SRB_COMPLETED; pSrbDataPacket->pSrb = NULL;
  548. #if DBG
  549. pStrmExt->cntSRBPending--;
  550. #endif
  551. }
  552. // Recycle list
  553. RemoveEntryList(&pSrbDataPacket->ListEntry); pStrmExt->cntDataAttached--; ASSERT(pStrmExt->cntDataAttached >= 0);
  554. InsertTailList(&pStrmExt->DataDetachedListHead, &pSrbDataPacket->ListEntry); pStrmExt->cntDataDetached++;
  555. #if DBG
  556. // Detect if 61883 is starve. This cause discontinuity.
  557. // This can happen for many valid reasons (slow system).
  558. // An assert is added to detect other unknown reason.
  559. if(!pStrmExt->bEOStream && pStrmExt->cntDataAttached == 0 && pStrmExt->StreamState == KSSTATE_RUN) {
  560. TRACE(TL_STRM_WARNING|TL_CIP_WARNING,("\n**** 61883 starve in RUN state (AttachCR); AQD[%d:%d:%d]\n\n",
  561. pStrmExt->cntDataAttached, pStrmExt->cntSRBQueued, pStrmExt->cntDataDetached
  562. ));
  563. if (pStrmExt->pStrmInfo->DataFlow == KSPIN_DATAFLOW_IN) {
  564. // ASSERT(pStrmExt->cntDataAttached > 0 && "61883 is starve at RUN state!!");
  565. }
  566. }
  567. #endif
  568. KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);
  569. return STATUS_MORE_PROCESSING_REQUIRED;
  570. }
  571. //
  572. // Mark attached buffer completed.
  573. //
  574. pSrbDataPacket->State |= DE_IRP_ATTACHED_COMPLETED;
  575. //
  576. // Special case: Completed and then Attached.
  577. //
  578. if(IsStateSet(pSrbDataPacket->State, DE_IRP_CALLBACK_COMPLETED)) {
  579. //
  580. // Recycle it back to the detach list
  581. //
  582. RemoveEntryList(&pSrbDataPacket->ListEntry); pStrmExt->cntDataAttached--; ASSERT(pStrmExt->cntDataAttached >= 0);
  583. InsertTailList(&pStrmExt->DataDetachedListHead, &pSrbDataPacket->ListEntry); pStrmExt->cntDataDetached++;
  584. #if DBG
  585. // Detect if 61883 is starve. This cause discontinuity.
  586. // This can happen for many valid reasons (slow system).
  587. // An assert is added to detect other unknown reason.
  588. if(!pStrmExt->bEOStream && pStrmExt->cntDataAttached == 0 && pStrmExt->StreamState == KSSTATE_RUN) {
  589. TRACE(TL_STRM_WARNING|TL_CIP_WARNING,("\n**** 61883 starve in RUN state (AttachCR); AQD[%d:%d:%d]\n\n",
  590. pStrmExt->cntDataAttached, pStrmExt->cntSRBQueued, pStrmExt->cntDataDetached
  591. ));
  592. if (pStrmExt->pStrmInfo->DataFlow == KSPIN_DATAFLOW_IN) {
  593. // ASSERT(pStrmExt->cntDataAttached > 0 && "61883 is starve at RUN state!!");
  594. }
  595. }
  596. #endif
  597. //
  598. // Complete this Srb
  599. //
  600. StreamClassStreamNotification(StreamRequestComplete, pStrmExt->pStrmObject, pSrbDataPacket->pSrb);
  601. pSrbDataPacket->State |= DE_IRP_SRB_COMPLETED; pSrbDataPacket->pSrb = NULL;
  602. #if DBG
  603. pStrmExt->cntSRBPending--;
  604. #endif
  605. TRACE(TL_STRM_WARNING,("AttachFrameCR: pSrbDataPacket:%x; completed before DttachFrameCR.\n", pSrbDataPacket));
  606. }
  607. KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);
  608. TRACE(TL_CIP_INFO,("\'DVAttachFrameCR: pSrb:%x; AttachCnt:%d\n", pSrb, pStrmExt->cntDataAttached));
  609. return STATUS_MORE_PROCESSING_REQUIRED;
  610. }
  611. VOID
  612. DVSRBRead(
  613. IN PKSSTREAM_HEADER pStrmHeader,
  614. IN ULONG ulFrameSize,
  615. IN PDVCR_EXTENSION pDevExt,
  616. IN PSTREAMEX pStrmExt,
  617. IN PHW_STREAM_REQUEST_BLOCK pSrb // needs Srb->Status
  618. )
  619. /*++
  620. Routine Description:
  621. Called when an Read Data Srb request is received
  622. --*/
  623. {
  624. KIRQL oldIrql;
  625. NTSTATUS Status;
  626. PSRB_DATA_PACKET pSrbDataPacket;
  627. PAV_61883_REQUEST pAVReq;
  628. PLONG plSrbUseCount;
  629. PIO_STACK_LOCATION NextIrpStack;
  630. ULONG ulSrcPktLen; // Packet length in bytes
  631. PVOID pFrameBuffer;
  632. PAGED_CODE();
  633. //
  634. // Some validation
  635. //
  636. if(pStrmHeader->FrameExtent < ulFrameSize) {
  637. TRACE(TL_CIP_WARNING,("\'SRBRead: FrmExt %d < FrmSz %d\n", pStrmHeader->FrameExtent, ulFrameSize));
  638. #ifdef SUPPORT_NEW_AVC
  639. if(pStrmExt->bDV2DVConnect) {
  640. pSrb->Status = STATUS_SUCCESS; // Testing...
  641. } else {
  642. #endif
  643. ASSERT(pStrmHeader->FrameExtent >= ulFrameSize);
  644. pSrb->Status = STATUS_INVALID_PARAMETER;
  645. #ifdef SUPPORT_NEW_AVC
  646. }
  647. #endif
  648. goto ExitReadStreamError;
  649. }
  650. //
  651. // Make sure that there is enough entry
  652. //
  653. KeAcquireSpinLock(pStrmExt->DataListLock, &oldIrql);
  654. if(IsListEmpty(&pStrmExt->DataDetachedListHead)) {
  655. //
  656. // This can happen only if the upper layer send down more than what we preallocated.
  657. // In this case, we will expand the list.
  658. //
  659. if(!(pSrbDataPacket = ExAllocatePool(NonPagedPool, sizeof(SRB_DATA_PACKET)))) {
  660. KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);
  661. pSrb->Status = STATUS_INSUFFICIENT_RESOURCES;
  662. goto ExitReadStreamError;
  663. }
  664. RtlZeroMemory(pSrbDataPacket, sizeof(SRB_DATA_PACKET));
  665. if(!(pSrbDataPacket->Frame = ExAllocatePool(NonPagedPool, sizeof(CIP_FRAME)))) {
  666. KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);
  667. ExFreePool(pSrbDataPacket);
  668. pSrb->Status = STATUS_INSUFFICIENT_RESOURCES;
  669. goto ExitReadStreamError;
  670. }
  671. if(!(pSrbDataPacket->pIrp = IoAllocateIrp(pDevExt->pBusDeviceObject->StackSize, FALSE))) {
  672. KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);
  673. ExFreePool(pSrbDataPacket->Frame); pSrbDataPacket->Frame = 0;
  674. ExFreePool(pSrbDataPacket); pSrbDataPacket = 0;
  675. pSrb->Status = STATUS_INSUFFICIENT_RESOURCES;
  676. goto ExitReadStreamError;
  677. }
  678. InsertTailList(&pStrmExt->DataDetachedListHead, &pSrbDataPacket->ListEntry); pStrmExt->cntDataDetached++;
  679. TRACE(TL_CIP_WARNING,("\'Add one node to DetachList\n"));
  680. }
  681. // Get a a nonpaged system-space virtual address for the buffer
  682. // This could fail it there is not enough system resource (MDL).
  683. #ifdef USE_WDM110 // Win2000
  684. //
  685. // Driver verifier flag to use this but if this is used, this driver will not load for Millen!!!
  686. //
  687. pFrameBuffer = MmGetSystemAddressForMdlSafe(pSrb->Irp->MdlAddress, NormalPagePriority);
  688. #else // Win9x
  689. pFrameBuffer = MmGetSystemAddressForMdl (pSrb->Irp->MdlAddress);
  690. #endif
  691. if(pFrameBuffer == NULL) {
  692. KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);
  693. pSrb->Status = STATUS_INSUFFICIENT_RESOURCES;
  694. ASSERT(FALSE && "DVFormatAttachFrame() insufficient resource!");
  695. goto ExitReadStreamError;
  696. }
  697. pSrbDataPacket = (PSRB_DATA_PACKET) RemoveHeadList(&pStrmExt->DataDetachedListHead); pStrmExt->cntDataDetached--;
  698. plSrbUseCount = (PLONG) (pSrb->SRBExtension); (*plSrbUseCount) = 0; // Not in a queue so 0.
  699. pAVReq = &pSrbDataPacket->AVReq;
  700. ulSrcPktLen = \
  701. (DVFormatInfoTable[pDevExt->VideoFormatIndex].DataBlockSize << 2) * \
  702. (1 << DVFormatInfoTable[pDevExt->VideoFormatIndex].FractionNumber);
  703. //
  704. // Format an attach frame request
  705. //
  706. DVFormatAttachFrame(
  707. pStrmExt->pStrmInfo->DataFlow,
  708. pStrmExt,
  709. pAVReq,
  710. pSrb,
  711. pSrbDataPacket,
  712. ulSrcPktLen,
  713. ulFrameSize,
  714. pFrameBuffer
  715. );
  716. // Completion callback can be called before the attach frame completion routine;
  717. // Add this to the attached list now; if it ever failed, it will be removed in the completion routine.
  718. InsertTailList(&pStrmExt->DataAttachedListHead, &pSrbDataPacket->ListEntry); pStrmExt->cntDataAttached++;
  719. (*plSrbUseCount) ++; // ++ for being in queue
  720. ASSERT(*plSrbUseCount > 0);
  721. KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);
  722. NextIrpStack = IoGetNextIrpStackLocation(pSrbDataPacket->pIrp);
  723. NextIrpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  724. NextIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_61883_CLASS;
  725. NextIrpStack->Parameters.Others.Argument1 = &pSrbDataPacket->AVReq;
  726. IoSetCompletionRoutine(
  727. pSrbDataPacket->pIrp,
  728. DVAttachFrameCR,
  729. pSrbDataPacket,
  730. TRUE,
  731. TRUE,
  732. TRUE
  733. );
  734. // Must set to _PENDING or MediaSample will return empty KSSTREAM_HEADER
  735. pSrb->Status = STATUS_PENDING;
  736. pSrbDataPacket->pIrp->IoStatus.Status = STATUS_SUCCESS; // Initialize it
  737. Status = IoCallDriver( pStrmExt->pDevExt->pBusDeviceObject, pSrbDataPacket->pIrp);
  738. ASSERT(Status == STATUS_PENDING || Status == STATUS_SUCCESS);
  739. return;
  740. ExitReadStreamError:
  741. StreamClassStreamNotification(
  742. StreamRequestComplete,
  743. pSrb->StreamObject,
  744. pSrb
  745. );
  746. #if DBG
  747. pStrmExt->cntSRBPending--;
  748. #endif
  749. }
  750. ULONG
  751. DVCompleteSrbWrite(
  752. PCIP_NOTIFY_INFO pInfo
  753. )
  754. /*++
  755. Routine Description:
  756. This fucntion is called when 61883 has completed transmitting a frame.
  757. --*/
  758. {
  759. PSRB_DATA_PACKET pSrbDataPacket ;
  760. PHW_STREAM_REQUEST_BLOCK pSrb;
  761. NTSTATUS Status = STATUS_SUCCESS;
  762. PDVCR_EXTENSION pDevExt;
  763. PSTREAMEX pStrmExt;
  764. PLONG plSrbUseCount; // When this count is 0, it can be completed.
  765. KIRQL oldIrql;
  766. #if DBG
  767. LONG lCycleCountElapsed;
  768. PXMT_FRAME_STAT pXmtStat;
  769. #endif
  770. // Callback and in DISPATCH_LEVEL
  771. // Caller might have acquired SpinLock as well!
  772. pSrbDataPacket = pInfo->Context;
  773. if(!pSrbDataPacket) {
  774. ASSERT(pSrbDataPacket);
  775. return 1;
  776. }
  777. pStrmExt = pSrbDataPacket->pStrmExt;
  778. ASSERT(pStrmExt);
  779. KeAcquireSpinLock(pStrmExt->DataListLock, &oldIrql);
  780. ASSERT(pSrbDataPacket->pSrb);
  781. pSrb = pSrbDataPacket->pSrb;
  782. pDevExt = pStrmExt->pDevExt;
  783. plSrbUseCount = (PLONG) pSrb->SRBExtension;
  784. // Check return Status
  785. if(!NT_SUCCESS(pSrbDataPacket->Frame->Status)) {
  786. TRACE(TL_CIP_ERROR,("\'DVCompleteSrbWrite: %d: Frame->Status %x\n", (DWORD) pSrbDataPacket->FrameNumber, pSrbDataPacket->Frame->Status));
  787. ASSERT(NT_SUCCESS(pSrbDataPacket->Frame->Status));
  788. pSrb->Status = STATUS_UNSUCCESSFUL;
  789. }
  790. else {
  791. pSrb->Status = STATUS_SUCCESS;
  792. }
  793. (*plSrbUseCount) --; // This count need to be 0 before the SRB is completed.
  794. ASSERT(*plSrbUseCount >= 0);
  795. #if DBG
  796. if(pSrbDataPacket->StreamState == KSSTATE_PAUSE) {
  797. pStrmExt->lPrevCycleCount = pSrbDataPacket->Frame->Timestamp.CL_CycleCount;
  798. pStrmExt->lTotalCycleCount = 0;
  799. pStrmExt->lFramesAccumulatedRun = 0;
  800. pStrmExt->lFramesAccumulatedPaused++;
  801. } else if(pSrbDataPacket->StreamState == KSSTATE_RUN) {
  802. if((LONG) pSrbDataPacket->Frame->Timestamp.CL_CycleCount > pStrmExt->lPrevCycleCount)
  803. lCycleCountElapsed = pSrbDataPacket->Frame->Timestamp.CL_CycleCount - pStrmExt->lPrevCycleCount;
  804. else
  805. lCycleCountElapsed = pSrbDataPacket->Frame->Timestamp.CL_CycleCount + 8000 - pStrmExt->lPrevCycleCount;
  806. if(lCycleCountElapsed <= (LONG) DVFormatInfoTable[pDevExt->VideoFormatIndex].ulSrcPackets) {
  807. TRACE(TL_CIP_WARNING, ("\'#### CycleCounts between frames %d <= expected %d + empty pkt?\n",
  808. lCycleCountElapsed,
  809. DVFormatInfoTable[pDevExt->VideoFormatIndex].ulSrcPackets
  810. ));
  811. }
  812. pStrmExt->lTotalCycleCount += lCycleCountElapsed;
  813. pStrmExt->lFramesAccumulatedRun++;
  814. TRACE(TL_CIP_TRACE,("\'%d) Attached:%d; pSrb:%x; FmSt:%x; CyTm:[SC:%d:CC:%d]; CyclElaps:%d; fps:%d/%d\n",
  815. (DWORD) pSrbDataPacket->FrameNumber,
  816. pStrmExt->cntDataAttached,
  817. pSrb,
  818. pSrbDataPacket->Frame->Status,
  819. pSrbDataPacket->Frame->Timestamp.CL_SecondCount,
  820. pSrbDataPacket->Frame->Timestamp.CL_CycleCount,
  821. lCycleCountElapsed,
  822. pStrmExt->lTotalCycleCount,
  823. (DWORD) pStrmExt->lFramesAccumulatedRun
  824. ));
  825. pStrmExt->lPrevCycleCount = pSrbDataPacket->Frame->Timestamp.CL_CycleCount;
  826. } else {
  827. TRACE(TL_CIP_ERROR,("\'This data was attached at %d state ?????\n", pSrbDataPacket->StreamState));
  828. }
  829. #endif
  830. TRACE(TL_CIP_INFO,("\'%d) FmSt %x; Cnt %d; CyTm:[%d:%d:%d]; PrevCyclCnt:%d\n",
  831. (DWORD) pSrbDataPacket->FrameNumber,
  832. pSrbDataPacket->Frame->Status,
  833. *plSrbUseCount,
  834. pSrbDataPacket->Frame->Timestamp.CL_SecondCount,
  835. pSrbDataPacket->Frame->Timestamp.CL_CycleCount,
  836. pSrbDataPacket->Frame->Timestamp.CL_CycleOffset,
  837. pStrmExt->lPrevCycleCount
  838. ));
  839. TRACE(TL_CIP_INFO,("\'DVCompleteSrbWrite: Frm:%d; Attached:%d; cntUse:%d, Srb:%x; FrmSt:%x; CyclElaps:%d\n",
  840. (DWORD) pSrbDataPacket->FrameNumber,
  841. pStrmExt->cntDataAttached,
  842. *plSrbUseCount,
  843. pSrb,
  844. pSrbDataPacket->Frame->Status,
  845. lCycleCountElapsed
  846. ));
  847. //
  848. // Mark completion is called.
  849. //
  850. pSrbDataPacket->State |= DE_IRP_CALLBACK_COMPLETED;
  851. //
  852. // Attached->Completed or Completed->Attached.
  853. //
  854. if(IsStateSet(pSrbDataPacket->State, DE_IRP_ATTACHED_COMPLETED)) {
  855. //
  856. // Recycle it back to the detach list
  857. //
  858. RemoveEntryList(&pSrbDataPacket->ListEntry); pStrmExt->cntDataAttached--; ASSERT(pStrmExt->cntDataAttached >= 0);
  859. InsertTailList(&pStrmExt->DataDetachedListHead, &pSrbDataPacket->ListEntry); pStrmExt->cntDataDetached++;
  860. #if DBG
  861. // Detect if 61883 is starve. This cause discontinuity.
  862. // This can happen for many valid reasons (slow system).
  863. // An assert is added to detect other unknown reason.
  864. if(!pStrmExt->bEOStream && pStrmExt->cntDataAttached == 0 && pStrmExt->StreamState == KSSTATE_RUN) {
  865. TRACE(TL_STRM_WARNING|TL_CIP_WARNING,("\n**** 61883 starve in RUN state (write);AQD[%d:%d:%d]\n\n",
  866. pStrmExt->cntDataAttached, pStrmExt->cntSRBQueued, pStrmExt->cntDataDetached
  867. ));
  868. if (pStrmExt->pStrmInfo->DataFlow == KSPIN_DATAFLOW_IN) {
  869. // ASSERT(pStrmExt->cntDataAttached > 0 && "61883 is starve at RUN state!!");
  870. }
  871. }
  872. #endif
  873. // Complete this SRB only if the count is 0.
  874. if(*plSrbUseCount == 0) {
  875. TRACE(TL_CIP_TRACE,("\'------------ Srb:%x completing..----------------\n", pSrb));
  876. // Frame that possibly made it to the device
  877. pStrmExt->FramesProcessed++;
  878. pSrb->CommandData.DataBufferArray->DataUsed = DVFormatInfoTable[pDevExt->VideoFormatIndex].ulFrameSize;
  879. StreamClassStreamNotification(StreamRequestComplete, pStrmExt->pStrmObject, pSrbDataPacket->pSrb );
  880. pSrbDataPacket->State |= DE_IRP_SRB_COMPLETED; pSrbDataPacket->pSrb = NULL;
  881. #if DBG
  882. pStrmExt->cntSRBPending--;
  883. #endif
  884. }
  885. } else {
  886. TRACE(TL_STRM_WARNING,("CompleteSrbWrite: pSrbDataPacket:%x; Completed before attach.\n", pSrbDataPacket));
  887. }
  888. #if DBG
  889. // Collect transmit buffer statistics
  890. if((pStrmExt->lFramesAccumulatedPaused + pStrmExt->lFramesAccumulatedRun) <= MAX_XMT_FRAMES_TRACED) {
  891. pXmtStat = pStrmExt->paXmtStat + (pStrmExt->lFramesAccumulatedPaused + pStrmExt->lFramesAccumulatedRun - 1);
  892. pXmtStat->tsTransmitted = pSrbDataPacket->Frame->Timestamp;
  893. if(pSrbDataPacket->Frame->Timestamp.CL_CycleCount == 0) {
  894. TRACE(TL_CIP_WARNING,("\'PAUSE:%d; RUN:%d; %d:%d\n", pStrmExt->lFramesAccumulatedPaused, pStrmExt->lFramesAccumulatedRun,
  895. pSrbDataPacket->Frame->Timestamp.CL_SecondCount, pSrbDataPacket->Frame->Timestamp.CL_CycleCount));
  896. }
  897. }
  898. #endif
  899. // Signal that all SRBs have been attached and transmitted.
  900. if(pStrmExt->bEOStream) {
  901. if(pStrmExt->cntDataAttached == 0 && pStrmExt->cntSRBQueued == 0) {
  902. //
  903. // Signal any pending clock events
  904. //
  905. DVSignalClockEvent(0, pStrmExt, 0, 0);
  906. //
  907. // No data request queued or pending; it is time to signal EOStream to
  908. // trigger EC_COMPLETE.
  909. //
  910. StreamClassStreamNotification(
  911. SignalMultipleStreamEvents,
  912. pStrmExt->pStrmObject,
  913. (GUID *)&KSEVENTSETID_Connection_Local,
  914. KSEVENT_CONNECTION_ENDOFSTREAM
  915. );
  916. TRACE(TL_CIP_WARNING,("\'*-*-* EOStream Signalled: pSrb:%x completed; AQD [%d:%d:%d]; Took %d msec;\n",
  917. pSrb, pStrmExt->cntDataAttached, pStrmExt->cntSRBQueued, pStrmExt->cntDataDetached,
  918. (DWORD) ((GetSystemTime() - pStrmExt->tmStreamStart)/(ULONGLONG) 10000)));
  919. }
  920. else {
  921. TRACE(TL_CIP_TRACE,("\' *EOStream: pSrb:%x completed; cntAttached:%d; cntSRBQ:%d\n", pSrb, (DWORD) pStrmExt->cntDataAttached, (DWORD) pStrmExt->cntSRBQueued));
  922. }
  923. }
  924. //
  925. // If we are not in the ending situtation (EOS pr Stop state) and number of
  926. // attach data request is below a threashold, we singal an event to the
  927. // code that does "throttle" to quickly attach another frame.
  928. //
  929. if(!pStrmExt->bEOStream ||
  930. (pStrmExt->bEOStream && pStrmExt->cntSRBQueued > 0)) {
  931. if(pStrmExt->StreamState != KSSTATE_STOP &&
  932. pStrmExt->cntDataAttached < NUM_BUF_ATTACHED_THEN_ISOCH) {
  933. KeSetEvent(&pStrmExt->hSrbArriveEvent, 0, FALSE);
  934. TRACE(TL_CIP_WARNING,("Threadshold:.AQD:[%d %d %d] < %d\n",
  935. pStrmExt->cntDataAttached,
  936. pStrmExt->cntSRBQueued,
  937. pStrmExt->cntDataDetached,
  938. NUM_BUF_ATTACHED_THEN_ISOCH
  939. ));
  940. }
  941. }
  942. KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);
  943. return 0;
  944. } // DVCompleteSrbWrite
  945. NTSTATUS
  946. DVAttachWriteFrame(
  947. IN PSTREAMEX pStrmExt
  948. )
  949. /*++
  950. Routine Description:
  951. Prepare and submit a frame to 61883 for transmit.
  952. --*/
  953. {
  954. KIRQL oldIrql;
  955. PSRB_DATA_PACKET pSrbDataPacket;
  956. PSRB_ENTRY pSrbEntry;
  957. #if DBG
  958. ULONG SrbNumCache; // Cache the SRB number of tracking purpose
  959. PXMT_FRAME_STAT pXmtStat;
  960. #endif
  961. PHW_STREAM_REQUEST_BLOCK pSrb;
  962. PHW_STREAM_REQUEST_BLOCK pSrbNext;
  963. PVOID pFrameBuffer;
  964. PIO_STACK_LOCATION NextIrpStack;
  965. NTSTATUS Status;
  966. PLONG plSrbUseCount; // When this count is 0, it can be completed.
  967. ULONG ulSrcPktLen;
  968. LARGE_INTEGER Timeout;
  969. PAGED_CODE();
  970. // Serialize setting state to STOP
  971. if(pStrmExt->StreamState != KSSTATE_PAUSE &&
  972. pStrmExt->StreamState != KSSTATE_RUN) {
  973. TRACE(TL_CIP_WARNING,("\'DVAttachWriteFrame: StreamState:%d; no attach! Wait!\n", pStrmExt->StreamState));
  974. Timeout.HighPart = -1;
  975. Timeout.LowPart = (ULONG)(-1 * DVFormatInfoTable[pStrmExt->pDevExt->VideoFormatIndex].ulAvgTimePerFrame);
  976. KeDelayExecutionThread(KernelMode, FALSE, &Timeout);
  977. return STATUS_SUCCESS;
  978. }
  979. KeAcquireSpinLock(pStrmExt->DataListLock, &oldIrql);
  980. if(IsListEmpty(&pStrmExt->SRBQueuedListHead) ||
  981. IsListEmpty(&pStrmExt->DataDetachedListHead) ) {
  982. KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);
  983. #if DBG
  984. if(!pStrmExt->bEOStream) {
  985. TRACE(TL_CIP_WARNING,("\'StrmSt:%d; DetachList or SrbQ empty: EOStream:%d; AQD [%d:%d:%d]; Wait one frame time.\n",
  986. pStrmExt->StreamState,
  987. pStrmExt->bEOStream,
  988. pStrmExt->cntDataAttached,
  989. pStrmExt->cntSRBQueued,
  990. pStrmExt->cntDataDetached
  991. ));
  992. }
  993. #endif
  994. Timeout.HighPart = -1;
  995. Timeout.LowPart = (ULONG)(-1 * DVFormatInfoTable[pStrmExt->pDevExt->VideoFormatIndex].ulAvgTimePerFrame);
  996. KeDelayExecutionThread(KernelMode, FALSE, &Timeout);
  997. // SRB is queued so it is OK. We will process that later.
  998. // This is usually cause by receiving more than what we pre-allocate.
  999. return STATUS_SUCCESS;
  1000. }
  1001. // KSSTATE_PAUSE: "reuse" head of the SrbQ.
  1002. // KSSTATE_RUN: "remove" a Srb from the queue.
  1003. // Get NEXT(SrbQ) and determine if it needs to be removed.
  1004. pSrbEntry = (PSRB_ENTRY) pStrmExt->SRBQueuedListHead.Flink; pSrb = pSrbEntry->pSrb; plSrbUseCount = (PLONG) pSrb->SRBExtension;
  1005. ASSERT(*plSrbUseCount >= 0);
  1006. #if DBG
  1007. SrbNumCache = pSrbEntry->SrbNum;
  1008. #endif
  1009. // Get a a nonpaged system-space virtual address for the buffer
  1010. // This could fail it there is not enough system resource (MDL).
  1011. #ifdef USE_WDM110 // Win2000
  1012. //
  1013. // Driver verifier flag to use this but if this is used, this driver will not load for Millen!!!
  1014. //
  1015. pFrameBuffer = MmGetSystemAddressForMdlSafe(pSrb->Irp->MdlAddress, NormalPagePriority);
  1016. #else
  1017. pFrameBuffer = MmGetSystemAddressForMdl (pSrb->Irp->MdlAddress);
  1018. #endif
  1019. if(pFrameBuffer == NULL) {
  1020. KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);
  1021. ASSERT(FALSE && "Insufficient MDL\n");
  1022. return STATUS_INSUFFICIENT_RESOURCES;
  1023. }
  1024. // Only in RUN state, the stream time in the Srb is considered and Srbs in the SrbQ will be dequeued.
  1025. if(pStrmExt->StreamState == KSSTATE_RUN) {
  1026. #define ALLOWABLE_TIMING_LATENCY TIME_PER_CYCLE
  1027. // Presentation time is honor only if we are the master clock.
  1028. if(pStrmExt->hMasterClock) {
  1029. LONGLONG tmExpectedFrame;
  1030. if( pStrmExt->pDevExt->VideoFormatIndex == FMT_IDX_SD_DVCR_PAL
  1031. || pStrmExt->pDevExt->VideoFormatIndex == FMT_IDX_SDL_DVCR_PAL
  1032. )
  1033. tmExpectedFrame = pStrmExt->PictureNumber * (LONGLONG) FRAME_TIME_PAL;
  1034. else {
  1035. tmExpectedFrame = (pStrmExt->PictureNumber * (LONGLONG) 1000 * (LONGLONG) 1001 ) / (LONGLONG) 3; // trouble NTSC!
  1036. // Adjustment for rounding
  1037. if((pStrmExt->PictureNumber % 3) == 1)
  1038. tmExpectedFrame++;
  1039. }
  1040. // Use to adjust the querued stream time.
  1041. pStrmExt->LastSystemTime = GetSystemTime();
  1042. // There are three situations about the NEXT(SrbQ) comparing with tmExpectedFrame:
  1043. // 1. Early; 2. OnTime; 3.Late
  1044. //
  1045. // tmExpectedFrame
  1046. // |
  1047. // 3>------------2>-----------------1>---------------
  1048. // 3.Late | 2.On Time | 1.Early
  1049. // | x | x |
  1050. // where "x" is the allowable latency (for calculation rounding)
  1051. //
  1052. // Note: allow TIME_PER_CYCLE latency
  1053. /*Early*/
  1054. /*N+1/++*/ if((tmExpectedFrame + ALLOWABLE_TIMING_LATENCY) <= pSrb->CommandData.DataBufferArray->PresentationTime.Time) {
  1055. // FUTURE: if a frame arrive sooner than expected, do not remove SrbQ;
  1056. // instead, repeat until passing its "scheduled departure".
  1057. // Remove NEXT(SrbQ) only if bEOStream
  1058. if(pStrmExt->bEOStream) {
  1059. TRACE(TL_CIP_TRACE,("\'EOStream=== Srb:%x; (SrbNum:%d ?= PicNum:%d) cntSrbQ:%d; Attach:%d ===\n",
  1060. pSrb, pSrbEntry->SrbNum, (DWORD) pStrmExt->PictureNumber, (DWORD) pStrmExt->cntSRBQueued, (DWORD) pStrmExt->cntDataAttached));
  1061. RemoveEntryList(&pSrbEntry->ListEntry); pStrmExt->cntSRBQueued--; (*plSrbUseCount)--;
  1062. ExFreePool(pSrbEntry); pSrbEntry = NULL; // Removed so free it!
  1063. }
  1064. TRACE(TL_CIP_TRACE,("\'** Repeat: pSrb:%x; RefCnt:%d; cntSrbQ:%d; PicNum:%d; Drp:%d; PresTime:%d >= CurTime:%d\n",
  1065. pSrb, *plSrbUseCount, pStrmExt->cntSRBQueued, (DWORD) pStrmExt->PictureNumber, (DWORD) pStrmExt->FramesDropped,
  1066. (DWORD) (pSrb->CommandData.DataBufferArray->PresentationTime.Time/10000), (DWORD) tmExpectedFrame/10000));
  1067. /*OnTime*/ } else
  1068. /* N */ if((tmExpectedFrame - ALLOWABLE_TIMING_LATENCY) <= pSrb->CommandData.DataBufferArray->PresentationTime.Time) {
  1069. // ON-TIME: may exactly matching or due to integer calculation, within one frame time.
  1070. // Dequeue if there are more than one Srb in the queue.
  1071. #if DBG
  1072. // Detect if a pSrb is used more than once
  1073. if((*plSrbUseCount) > 1) {
  1074. TRACE(TL_CIP_TRACE,("\'* Go: pSrb:%x; RefCnt:%d; cntSrbQ:%d; PicNum:%d; Drp:%d; PresTime:%d >= CurTime:%d\n",
  1075. pSrb, *plSrbUseCount, pStrmExt->cntSRBQueued, (DWORD) pStrmExt->PictureNumber, (DWORD) pStrmExt->FramesDropped,
  1076. (DWORD) (pSrb->CommandData.DataBufferArray->PresentationTime.Time/10000), (DWORD) tmExpectedFrame/10000));
  1077. }
  1078. #endif
  1079. if(pStrmExt->bEOStream) {
  1080. // Remove NEXT(SrbQ) only if there are more than one SRB or bEOStream
  1081. TRACE(TL_CIP_TRACE,("\'EOStream=== Srb:%x; (SrbNum:%d ?= PicNum:%d) cntSrbQ:%d; Attach:%d ===\n",
  1082. pSrb, pSrbEntry->SrbNum, (DWORD) pStrmExt->PictureNumber, (DWORD) pStrmExt->cntSRBQueued, (DWORD) pStrmExt->cntDataAttached));
  1083. RemoveEntryList(&pSrbEntry->ListEntry); pStrmExt->cntSRBQueued--; (*plSrbUseCount)--;
  1084. ExFreePool(pSrbEntry); pSrbEntry = NULL; // Removed so free it!
  1085. // Remove SRB if more than one SRBs in Q and there is not a discontinuity, or end of stream.
  1086. } else if(pStrmExt->cntSRBQueued > 1) {
  1087. LONGLONG tmExpectedNextFrame = tmExpectedFrame + DVFormatInfoTable[pStrmExt->pDevExt->VideoFormatIndex].ulAvgTimePerFrame;
  1088. pSrbNext = ((SRB_ENTRY *) (pSrbEntry->ListEntry.Flink))->pSrb;
  1089. // Next SRB has the next presentation time
  1090. // May add this check as well: (but check Presentation time is more reliable)
  1091. // pSrb->CommandData.DataBufferArray->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY
  1092. /* N,N+1 */ if((tmExpectedNextFrame + ALLOWABLE_TIMING_LATENCY) > pSrbNext->CommandData.DataBufferArray->PresentationTime.Time) {
  1093. TRACE(TL_CIP_TRACE,("\'=== Srb:%x; (SrbNum:%d ?= PicNum:%d) cntSrbQ:%d; Attach:%d ===\n",
  1094. pSrb, pSrbEntry->SrbNum, (DWORD) pStrmExt->PictureNumber, (DWORD) pStrmExt->cntSRBQueued, (DWORD) pStrmExt->cntDataAttached));
  1095. RemoveEntryList(&pSrbEntry->ListEntry); pStrmExt->cntSRBQueued--; (*plSrbUseCount)--;
  1096. ExFreePool(pSrbEntry); pSrbEntry = NULL; // Removed so free it!
  1097. /* N, N+2/++ */ } else {
  1098. TRACE(TL_CIP_TRACE,("\'=== GO(Stale=TRUE) Srb:%x; (SrbNum:%d ?= PicNum:%d) Attach:%d ==\n",
  1099. pSrb, pSrbEntry->SrbNum, (DWORD) pStrmExt->PictureNumber, (DWORD) pStrmExt->cntDataAttached));
  1100. // Mark this stale and be remove as soon as another is attached.
  1101. }
  1102. }
  1103. else {
  1104. TRACE(TL_CIP_TRACE,("\'=== GO(Stale=TRUE) Srb:%x; (SrbNum:%d ?= PicNum:%d) Attach:%d ==\n",
  1105. pSrb, pSrbEntry->SrbNum, (DWORD) pStrmExt->PictureNumber, (DWORD) pStrmExt->cntDataAttached));
  1106. // Mark this stale and be remove as soon as another is attached.
  1107. pSrbEntry->bStale = TRUE;
  1108. }
  1109. // CLOCK: tick when a frame is transmitted.
  1110. // LATE: this is dropped until there is only one Srb in the SrbQ.
  1111. // WORKITEM: we may need to implement IQualityManagement to inform application to read ahead.
  1112. /*Late*/ }
  1113. /*N-1*/ else {
  1114. if(pStrmExt->cntSRBQueued > 1) {
  1115. pSrbNext = ((SRB_ENTRY *) (pSrbEntry->ListEntry.Flink))->pSrb;
  1116. // Next SRB has the next presentation time; it can be:
  1117. // Current time is N
  1118. // Current frame is late (N-1 or N-2..) and we have more than one Srb in the queue;
  1119. // check next frame:
  1120. // (N?)
  1121. // N-2, N-1, N late more than one frame; (Next frame is also late; dequeu and not transmit; "catch up" case.)
  1122. // N-1, N late one frame; (Next frame is on time; dequeu this frame) <-- Normal case
  1123. // N-1, N+1 late one frame, but next frame is not N+1; (Next frame is early; *current frame will be repeated*)
  1124. //
  1125. // May add this check this as well: (but check Presentation time is more reliable)
  1126. // pSrb->CommandData.DataBufferArray->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY
  1127. //
  1128. // ******************************************************************************************************
  1129. // If next frame is earlier than current stream time, "repeat" current stale frame; else we need to "catch up"!
  1130. // ******************************************************************************************************
  1131. /* N-1++, N */ if((tmExpectedFrame + ALLOWABLE_TIMING_LATENCY) > pSrbNext->CommandData.DataBufferArray->PresentationTime.Time) {
  1132. TRACE(TL_CIP_TRACE,("\'*** Stale(not Sent): pSrb:%x; RefCnt:%d; cntSrbQ:%d; cntAtt:%d; PicNum:%d; Drp:%d; PTm:%d < ExpTm:%d\n",
  1133. pSrb, *plSrbUseCount, pStrmExt->cntSRBQueued, pStrmExt->cntDataAttached, (DWORD) pStrmExt->PictureNumber, (DWORD) pStrmExt->FramesDropped,
  1134. (DWORD) (pSrb->CommandData.DataBufferArray->PresentationTime.Time/10000), (DWORD) (tmExpectedFrame/10000) ));
  1135. // Never been attached; remove late entry
  1136. RemoveEntryList(&pSrbEntry->ListEntry); pStrmExt->cntSRBQueued--; (*plSrbUseCount)--;
  1137. ExFreePool(pSrbEntry); pSrbEntry = NULL; // Removed so free it!
  1138. if(*plSrbUseCount == 0) {
  1139. // If no reference to is, complete this.
  1140. pSrb->Status = STATUS_SUCCESS; // It is not a failure but late; maybe other status to indicate "non-fatal" late status..
  1141. pSrb->CommandData.DataBufferArray->DataUsed = 0;
  1142. StreamClassStreamNotification(StreamRequestComplete, pSrb->StreamObject, pSrb);
  1143. #if DBG
  1144. pStrmExt->cntSRBPending--;
  1145. #endif
  1146. }
  1147. KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);
  1148. // Since SrbQ is not empty and this is a stale frame, call recursively to get to next frame.
  1149. // Only possible error is if there is not sufficient resource (esp MDL)
  1150. // then, we bail out by self terminating this thread.
  1151. if(STATUS_INSUFFICIENT_RESOURCES ==
  1152. DVAttachWriteFrame(pStrmExt)) {
  1153. TRACE(TL_CIP_ERROR,("DVAttachWriteFrame: STATUS_INSUFFICIENT_RESOURCES\n"));
  1154. return STATUS_INSUFFICIENT_RESOURCES;
  1155. } else {
  1156. return STATUS_SUCCESS; // SUCESS unless there is another status to indicate "non-fatal" late.
  1157. }
  1158. /*N-2++, N-1++*/ } else {
  1159. pSrbEntry->bStale = TRUE;
  1160. }
  1161. }
  1162. else {
  1163. // EOStream and is a stale stream, it is the last element in SrbQ.
  1164. // Remove it.
  1165. if(pStrmExt->bEOStream) {
  1166. TRACE(TL_CIP_TRACE,("\'*** Stale(bEOStream): pSrb:%x; RefCnt:%d; cntSrbQ:%d; cntAtt:%d; PicNum:%d; Drp:%d; PTm:%d < ExpTm:%d\n",
  1167. pSrb, *plSrbUseCount, pStrmExt->cntSRBQueued, pStrmExt->cntDataAttached, (DWORD) pStrmExt->PictureNumber, (DWORD) pStrmExt->FramesDropped,
  1168. (DWORD) (pSrb->CommandData.DataBufferArray->PresentationTime.Time/10000), (DWORD) (tmExpectedFrame/10000) ));
  1169. RemoveEntryList(&pSrbEntry->ListEntry); pStrmExt->cntSRBQueued--; (*plSrbUseCount)--;
  1170. ExFreePool(pSrbEntry); pSrbEntry = NULL; // Removed so free it!
  1171. if(*plSrbUseCount == 0) {
  1172. // If no reference to is, complete this.
  1173. pSrb->Status = STATUS_SUCCESS; // It is not a failure but late; maybe other status to indicate "non-fatal" late status..
  1174. pSrb->CommandData.DataBufferArray->DataUsed = 0;
  1175. StreamClassStreamNotification(StreamRequestComplete, pSrb->StreamObject, pSrb);
  1176. #if DBG
  1177. pStrmExt->cntSRBPending--;
  1178. #endif
  1179. }
  1180. KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);
  1181. // Update current stream time
  1182. pStrmExt->CurrentStreamTime = tmExpectedFrame;
  1183. return STATUS_SUCCESS; // SUCESS unless there is another status to indicate "non-fatal" late.
  1184. }
  1185. TRACE(TL_CIP_TRACE,("\'*** Stale(Sent): pSrb:%x; RefCnt:%d; cntSrbQ:%d; cntAtt:%d; PicNum:%d; Drp:%d; PTm:%d < ExpTm:%d\n",
  1186. pSrb, *plSrbUseCount, pStrmExt->cntSRBQueued, pStrmExt->cntDataAttached, (DWORD) pStrmExt->PictureNumber, (DWORD) pStrmExt->FramesDropped,
  1187. (DWORD) (pSrb->CommandData.DataBufferArray->PresentationTime.Time/10000), (DWORD) (tmExpectedFrame/10000) ));
  1188. // If this is stale and this is the only frame in SrbQ, Xmt it
  1189. }
  1190. // If late, this frame is always drop.
  1191. pStrmExt->FramesDropped++;
  1192. }
  1193. // Update current stream time
  1194. pStrmExt->CurrentStreamTime = tmExpectedFrame;
  1195. } // if(pStrmExt->hMasterClock)
  1196. else {
  1197. // Not the master clock, no "pacing" so always dequeu (SrbQ) and transmit
  1198. // as long as there is one Srb in the queue.
  1199. if(pStrmExt->cntSRBQueued > 1 || pStrmExt->bEOStream) {
  1200. RemoveEntryList(&pSrbEntry->ListEntry); pStrmExt->cntSRBQueued--; (*plSrbUseCount)--;
  1201. ExFreePool(pSrbEntry); pSrbEntry = NULL; // Removed so free it!
  1202. }
  1203. TRACE(TL_CIP_TRACE,("\'* GO: (NoClock) pSrb:%x; RefCnt:%d; cntSrbQ:%d; PicNum:%d;\n", pSrb, *plSrbUseCount, pStrmExt->cntSRBQueued, (DWORD) pStrmExt->PictureNumber));
  1204. } // if(pStrmExt->hMasterClock)
  1205. // pStrmExt->FramesProcessed is updated when a frame has been transmitted in the notify routine.
  1206. // **** THIS IS THE CLOCK TICK ****
  1207. pStrmExt->PictureNumber++; // After tmExpectedFrame is calculated; Another frame to be attached
  1208. if(pStrmExt->hMasterClock) {
  1209. #ifdef SUPPORT_QUALITY_CONTROL
  1210. // +: late; -: early
  1211. pStrmExt->KSQuality.DeltaTime = pStrmExt->CurrentStreamTime - pSrb->CommandData.DataBufferArray->PresentationTime.Time;
  1212. // Percentage * 10 of frame transmitted
  1213. pStrmExt->KSQuality.Proportion = (ULONG)
  1214. ((pStrmExt->PictureNumber - pStrmExt->FramesDropped) * 1000 / pStrmExt->PictureNumber);
  1215. pStrmExt->KSQuality.Context = /* NOT USED */ 0;
  1216. #define MIN_ATTACH_BUFFER 3
  1217. // This is where we may want to signal that we are near Famine!!
  1218. if (pStrmExt->KSQuality.DeltaTime >
  1219. (DV_NUM_OF_XMT_BUFFERS - MIN_ATTACH_BUFFER) * DVFormatInfoTable[pStrmExt->pDevExt->VideoFormatIndex].ulAvgTimePerFrame) {
  1220. TRACE(TL_CIP_TRACE,("\'QualityControl: pic#%d; drop:%d; Prop:%d; DeltaTime:%d (Srb.tmPres:%d, tmStream:%d)\n",
  1221. (DWORD) pStrmExt->PictureNumber,
  1222. (DWORD) pStrmExt->FramesDropped,
  1223. pStrmExt->KSQuality.Proportion,
  1224. (DWORD) pStrmExt->KSQuality.DeltaTime/10000,
  1225. (DWORD) pSrb->CommandData.DataBufferArray->PresentationTime.Time/10000,
  1226. (DWORD) pStrmExt->CurrentStreamTime/10000
  1227. ));
  1228. }
  1229. #endif
  1230. }
  1231. } // KSSTATE_RUN
  1232. #if DBG
  1233. // Collect transmit buffer statistics
  1234. if(pStrmExt->ulStatEntries < MAX_XMT_FRAMES_TRACED) {
  1235. pXmtStat = pStrmExt->paXmtStat + pStrmExt->ulStatEntries;
  1236. pXmtStat->StreamState = pStrmExt->StreamState;
  1237. pXmtStat->cntSRBReceived = (LONG) pStrmExt->cntSRBReceived;
  1238. pXmtStat->cntSRBPending = (LONG) pStrmExt->cntSRBPending;
  1239. pXmtStat->cntSRBQueued = (LONG) pStrmExt->cntSRBQueued;
  1240. pXmtStat->cntDataAttached= pStrmExt->cntDataAttached;
  1241. pXmtStat->FrameSlot = (DWORD) pStrmExt->PictureNumber;
  1242. pXmtStat->tmStreamTime = pStrmExt->CurrentStreamTime;
  1243. pXmtStat->DropCount = (DWORD) pStrmExt->FramesDropped;
  1244. pXmtStat->FrameNumber = SrbNumCache;
  1245. pXmtStat->OptionsFlags = pSrb->CommandData.DataBufferArray->OptionsFlags;
  1246. pXmtStat->tmPresentation = pSrb->CommandData.DataBufferArray->PresentationTime.Time;
  1247. // get the actual CyclTime when the frame is transmitted in the completion routine.
  1248. pStrmExt->ulStatEntries++;
  1249. }
  1250. #endif
  1251. #ifdef MSDV_SUPPORT_MUTE_AUDIO
  1252. // pSrbEntry could have been freed; if it has not and useCnt>1, then it could be a repeat frame.
  1253. if(pSrbEntry && (*plSrbUseCount) > 1) {
  1254. // Set it only once
  1255. if(!pSrbEntry->bAudioMute)
  1256. pSrbEntry->bAudioMute =
  1257. DVMuteDVFrame(pStrmExt->pDevExt, pFrameBuffer, TRUE);
  1258. }
  1259. #endif
  1260. // Get a data packet node as the context and list node
  1261. pSrbDataPacket = (PSRB_DATA_PACKET) RemoveHeadList(&pStrmExt->DataDetachedListHead); pStrmExt->cntDataDetached--;
  1262. ulSrcPktLen = \
  1263. (DVFormatInfoTable[pStrmExt->pDevExt->VideoFormatIndex].DataBlockSize << 2) * \
  1264. (1 << DVFormatInfoTable[pStrmExt->pDevExt->VideoFormatIndex].FractionNumber);
  1265. // Format an attach frame request
  1266. DVFormatAttachFrame(
  1267. pStrmExt->pStrmInfo->DataFlow,
  1268. pStrmExt,
  1269. &pSrbDataPacket->AVReq,
  1270. pSrb,
  1271. pSrbDataPacket,
  1272. ulSrcPktLen,
  1273. DVFormatInfoTable[pStrmExt->pDevExt->VideoFormatIndex].ulFrameSize,
  1274. pFrameBuffer
  1275. );
  1276. TRACE(TL_CIP_INFO,("\'------ New>> UseCnt:%d; pAVReq:%x; Srb:%x; DtaPkt:%x; AQD [%d:%d:%d]\n",
  1277. *plSrbUseCount,
  1278. &pSrbDataPacket->AVReq,
  1279. pSrb,
  1280. pSrbDataPacket,
  1281. pStrmExt->cntDataAttached,
  1282. pStrmExt->cntSRBQueued,
  1283. pStrmExt->cntDataDetached
  1284. ));
  1285. // Add this to the attached list
  1286. InsertTailList(&pStrmExt->DataAttachedListHead, &pSrbDataPacket->ListEntry); pStrmExt->cntDataAttached++;
  1287. (*plSrbUseCount) ++; // ++ for being in queue
  1288. ASSERT(*plSrbUseCount > 0);
  1289. KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);
  1290. NextIrpStack = IoGetNextIrpStackLocation(pSrbDataPacket->pIrp);
  1291. NextIrpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  1292. NextIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_61883_CLASS;
  1293. NextIrpStack->Parameters.Others.Argument1 = &pSrbDataPacket->AVReq;
  1294. IoSetCompletionRoutine(
  1295. pSrbDataPacket->pIrp,
  1296. DVAttachFrameCR,
  1297. pSrbDataPacket,
  1298. TRUE,
  1299. TRUE,
  1300. TRUE
  1301. );
  1302. pSrbDataPacket->pIrp->IoStatus.Status = STATUS_SUCCESS; // Initialize it to something
  1303. Status = IoCallDriver( pStrmExt->pDevExt->pBusDeviceObject, pSrbDataPacket->pIrp);
  1304. ASSERT(Status == STATUS_PENDING || Status == STATUS_SUCCESS);
  1305. if(!NT_SUCCESS(Status)) {
  1306. // put the resource back!
  1307. TRACE(TL_CIP_ERROR,("DVAttachWriteFrame: Failed to attach; St:%x\n", Status));
  1308. ASSERT(FALSE && "Failed to attach a Xmt frame.");
  1309. }
  1310. //
  1311. // This is our throttle that regulate data attach to DV:
  1312. //
  1313. // This function is called by the attach thread which is running in an infinite loop.
  1314. // This function need to utilize the buffer that it receive and its repeat mechanism to
  1315. // regulate the incoming buffer from client and outgoing buffer attach to 1394 stadck for transmit.
  1316. // One way is to wait while there is certain number of frame already attach.
  1317. KeAcquireSpinLock(pStrmExt->DataListLock, &oldIrql);
  1318. if(!pStrmExt->bEOStream &&
  1319. // Need to keep NUM_BUF_ATTACHED_THEN_ISOCH buffer attached at all time to keep 61883 isoch xmt going.
  1320. (pStrmExt->StreamState == KSSTATE_RUN && pStrmExt->cntDataAttached > NUM_BUF_ATTACHED_THEN_ISOCH ||
  1321. pStrmExt->StreamState == KSSTATE_PAUSE && pStrmExt->cntDataAttached >= NUM_BUF_ATTACHED_THEN_ISOCH )
  1322. ) {
  1323. NTSTATUS StatusDelay = STATUS_SUCCESS;
  1324. #if DBG
  1325. ULONGLONG tmStart = GetSystemTime();
  1326. TRACE(TL_CIP_TRACE,("\'[Pic# %d]; SrbNum:%d; Dropped:%d; pSrb:%x; StrmSt:%d; EOS:%d; AQD:[%d;%d;%d]; ",
  1327. (DWORD) pStrmExt->PictureNumber, SrbNumCache, (DWORD) pStrmExt->FramesDropped, pSrb, pStrmExt->StreamState, pStrmExt->bEOStream,
  1328. pStrmExt->cntDataAttached, pStrmExt->cntSRBQueued, pStrmExt->cntDataDetached));
  1329. #endif
  1330. Timeout.HighPart = -1;
  1331. Timeout.LowPart = (ULONG)(-1 * DVFormatInfoTable[pStrmExt->pDevExt->VideoFormatIndex].ulAvgTimePerFrame * \
  1332. (pStrmExt->StreamState == KSSTATE_PAUSE ? 1 : (pStrmExt->cntDataAttached - NUM_BUF_ATTACHED_THEN_ISOCH))) ;
  1333. // Wait the full time until we are very low in SrbQ or Attached buffers.
  1334. if(pStrmExt->cntSRBQueued <= 1 && pStrmExt->cntDataAttached <= NUM_BUF_ATTACHED_THEN_ISOCH) {
  1335. // Signal (instead of delay thread) when a new frame arrive (or signal by CR when pipeline is low)
  1336. KeClearEvent(&pStrmExt->hSrbArriveEvent);
  1337. KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql); // Guard against pStrmExt->cntSRBQueued
  1338. // Down to one frame so we will wait for an event and will be signalled
  1339. // when a new frame has arrived, or
  1340. // when number of attach buffer is below the minimum.
  1341. StatusDelay =
  1342. KeWaitForSingleObject(
  1343. &pStrmExt->hSrbArriveEvent,
  1344. Executive,
  1345. KernelMode,
  1346. FALSE,
  1347. &Timeout
  1348. );
  1349. }
  1350. else {
  1351. KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);
  1352. // Wait for frame(s) to be delivered; this is our throttle..
  1353. // The timeout period can be one or up to
  1354. // (pStrmExt->cntDataAttached - NUM_BUF_ATTACHED_THEN_ISOCH) frames
  1355. KeDelayExecutionThread(KernelMode, FALSE, &Timeout);
  1356. }
  1357. #if DBG
  1358. TRACE(TL_CIP_TRACE,("\'Wait(ST:%x) %d nsec!\n", StatusDelay, (DWORD) ((GetSystemTime() - tmStart)/10)));
  1359. #endif
  1360. } else {
  1361. KeReleaseSpinLock(pStrmExt->DataListLock, oldIrql);
  1362. }
  1363. return Status;
  1364. }
  1365. VOID
  1366. DVFormatAttachFrame(
  1367. IN KSPIN_DATAFLOW DataFlow,
  1368. IN PSTREAMEX pStrmExt,
  1369. IN PAV_61883_REQUEST pAVReq,
  1370. IN PHW_STREAM_REQUEST_BLOCK pSrb,
  1371. IN PSRB_DATA_PACKET pSrbDataPacket,
  1372. IN ULONG ulSourceLength, // Packet length in bytes
  1373. IN ULONG ulFrameSize, // Buffer size; may contain one or multiple source packets
  1374. IN PVOID pFrameBuffer
  1375. )
  1376. /*++
  1377. Routine Description:
  1378. Format an attach frame request.
  1379. --*/
  1380. {
  1381. ASSERT(pSrb);
  1382. //
  1383. // Setup PSRB_DATA_PACKET, except its Frame structure (PCIP_APP_FRAME)
  1384. //
  1385. InitializeListHead(&pSrbDataPacket->ListEntry);
  1386. pSrbDataPacket->State = DE_PREPARED; // Initial state of a resued DataEntry (start over!)
  1387. pSrbDataPacket->pSrb = pSrb;
  1388. pSrbDataPacket->StreamState = pStrmExt->StreamState; // StreamState when this buffer is attached.
  1389. pSrbDataPacket->pStrmExt = pStrmExt;
  1390. pSrbDataPacket->FrameBuffer = pFrameBuffer;
  1391. ASSERT(pSrbDataPacket->FrameBuffer != NULL);
  1392. pSrbDataPacket->Frame->pNext = NULL;
  1393. pSrbDataPacket->Frame->Status = 0;
  1394. pSrbDataPacket->Frame->Packet = (PUCHAR) pFrameBuffer;
  1395. if(DataFlow == KSPIN_DATAFLOW_OUT) {
  1396. pSrbDataPacket->FrameNumber = pStrmExt->cntSRBReceived;
  1397. #ifdef NT51_61883
  1398. // This is needed since we have an old 61883.h in Lab06 (according to include path, anyway).
  1399. // Remove this when 61883.h is updated.
  1400. #ifndef CIP_RESET_FRAME_ON_DISCONTINUITY
  1401. #define CIP_RESET_FRAME_ON_DISCONTINUITY 0x00000040
  1402. #endif
  1403. //
  1404. // Set CIP_USE_SOURCE_HEADER_TIMESTAMP to get 25 bit CycleTime from source packet header (13CycleCount:12CycleOffset)
  1405. // Do not set this to get 16 bit CycleTime from isoch packet (3 SecondCount:13CycleCount)
  1406. //
  1407. pSrbDataPacket->Frame->Flags = CIP_VALIDATE_FIRST_SOURCE // Verify the start of a DV frame
  1408. | CIP_RESET_FRAME_ON_DISCONTINUITY; // No partial frame
  1409. #else
  1410. pSrbDataPacket->Frame->Flags = 0;
  1411. #endif
  1412. pSrbDataPacket->Frame->pfnValidate = DVReadFrameValidate; // use to validate the 1st source packet
  1413. pSrbDataPacket->Frame->ValidateContext = pSrbDataPacket;
  1414. pSrbDataPacket->Frame->pfnNotify = DVCompleteSrbRead;
  1415. }
  1416. else {
  1417. pSrbDataPacket->FrameNumber = pStrmExt->FramesProcessed;
  1418. pSrbDataPacket->Frame->Flags = CIP_DV_STYLE_SYT;
  1419. pSrbDataPacket->Frame->pfnValidate = NULL;
  1420. pSrbDataPacket->Frame->ValidateContext = NULL;
  1421. pSrbDataPacket->Frame->pfnNotify = DVCompleteSrbWrite;
  1422. }
  1423. pSrbDataPacket->Frame->NotifyContext = pSrbDataPacket;
  1424. //
  1425. // Av61883_AttachFrames
  1426. //
  1427. RtlZeroMemory(pAVReq, sizeof(AV_61883_REQUEST));
  1428. INIT_61883_HEADER(pAVReq, Av61883_AttachFrame);
  1429. pAVReq->AttachFrame.hConnect = pStrmExt->hConnect;
  1430. pAVReq->AttachFrame.FrameLength = ulFrameSize;
  1431. pAVReq->AttachFrame.SourceLength = ulSourceLength;
  1432. pAVReq->AttachFrame.Frame = pSrbDataPacket->Frame;
  1433. ASSERT(pStrmExt->hConnect);
  1434. ASSERT(pSrbDataPacket->Frame);
  1435. }
  1436. void
  1437. DVSetXmtThreadState(
  1438. PSTREAMEX pStrmExt,
  1439. XMT_THREAD_STATE RequestState
  1440. )
  1441. /*++
  1442. Routine Description:
  1443. Set to a new transmit thread state (running, halt, or terminate).
  1444. --*/
  1445. {
  1446. if(
  1447. pStrmExt->pStrmInfo->DataFlow == KSPIN_DATAFLOW_IN &&
  1448. !pStrmExt->bTerminateThread
  1449. ) {
  1450. if(pStrmExt->XmtState == RequestState) {
  1451. TRACE(TL_STRM_WARNING,("Same state %d -> %d\n", pStrmExt->XmtState, RequestState));
  1452. return;
  1453. }
  1454. //
  1455. // The thread could be parked at the halt state. In order to transitioning into
  1456. // run state, we need to signal the halt event and then terminate this thread.
  1457. //
  1458. if(pStrmExt->XmtState == THD_HALT &&
  1459. RequestState == THD_TERMINATE) {
  1460. //
  1461. // Mark that this thread will be terminated.
  1462. //
  1463. pStrmExt->bTerminateThread = TRUE;
  1464. //
  1465. // This thread might in the the halt state. Signal it so it can be terminated.
  1466. //
  1467. KeSetEvent(&pStrmExt->hRunThreadEvent, 0, FALSE);
  1468. pStrmExt->XmtState = THD_TERMINATE;
  1469. TRACE(TL_STRM_WARNING,("Halt -> TERMINATE\n"));
  1470. return;
  1471. }
  1472. //
  1473. // Synchonize attach frame with other externial requests. External thread should
  1474. // first acquire this mutext, set service request, and then release this mutex.
  1475. //
  1476. KeWaitForSingleObject( pStrmExt->XmtThreadMutex, Executive, KernelMode, FALSE, 0);
  1477. if(RequestState == THD_HALT) {
  1478. //
  1479. // Non-signal this event to put this thread in the Halt state
  1480. //
  1481. KeClearEvent(&pStrmExt->hRunThreadEvent);
  1482. pStrmExt->XmtState = THD_HALT;
  1483. TRACE(TL_STRM_WARNING,("-->HALTING\n"));
  1484. } else if (RequestState == THD_TERMINATE) {
  1485. //
  1486. // Mark that this thread will be terminated.
  1487. //
  1488. pStrmExt->bTerminateThread = TRUE;
  1489. pStrmExt->XmtState = THD_TERMINATE;
  1490. TRACE(TL_STRM_WARNING,("-->TERMINATE\n"));
  1491. } else {
  1492. ASSERT(FALSE && "Unexpected thread state change!");
  1493. }
  1494. //
  1495. // Release mutex so other thread can request service
  1496. //
  1497. KeReleaseMutex(pStrmExt->XmtThreadMutex, FALSE);
  1498. }
  1499. }
  1500. #define PREROLL_WAITTIME 2000000
  1501. VOID
  1502. DVAttachFrameThread(
  1503. IN PSTREAMEX pStrmExt
  1504. )
  1505. /*++
  1506. Routine Description:
  1507. This is a system thread to attach frame for transmit.
  1508. --*/
  1509. {
  1510. NTSTATUS Status;
  1511. PDVCR_EXTENSION pDevExt;
  1512. KIRQL OldIrql;
  1513. #ifdef SUPPORT_PREROLL_AT_RUN_STATE
  1514. NTSTATUS StatusWFSO; // return status for WaitForSingleObject()
  1515. LARGE_INTEGER PrerollTimeout; // Timeout for preroll
  1516. #endif
  1517. PAGED_CODE();
  1518. #ifdef SUPPORT_PREROLL_AT_RUN_STATE
  1519. PrerollTimeout = RtlConvertLongToLargeInteger(-((LONG) PREROLL_WAITTIME));
  1520. #endif
  1521. pDevExt = pStrmExt->pDevExt;
  1522. //
  1523. // Pump up the priority since we are dealing with real time data
  1524. //
  1525. KeSetPriorityThread(KeGetCurrentThread(),
  1526. #if 1
  1527. LOW_REALTIME_PRIORITY
  1528. #else
  1529. HIGH_PRIORITY
  1530. #endif
  1531. );
  1532. while (!pStrmExt->bTerminateThread) {
  1533. //
  1534. // Synchonize attach frame with other externial requests. External thread should
  1535. // first acquire this mutext, set service request, and then release this mutex.
  1536. //
  1537. KeWaitForSingleObject( pStrmExt->XmtThreadMutex, Executive, KernelMode, FALSE, 0);
  1538. //
  1539. // Requested to be terminated by other thread while in above WFSO()?
  1540. //
  1541. if(pStrmExt->bTerminateThread) {
  1542. KeReleaseMutex(pStrmExt->XmtThreadMutex, FALSE);
  1543. goto ThreadTherminating;
  1544. }
  1545. //
  1546. // Has other thread put in a request to put this thread in the HALT state?
  1547. //
  1548. KeWaitForSingleObject( &pStrmExt->hRunThreadEvent, Executive, KernelMode, FALSE, 0);
  1549. //
  1550. // Set (TRUE) this flag only once to indicate this thread has started.
  1551. //
  1552. if(!pStrmExt->bXmtThreadStarted)
  1553. pStrmExt->bXmtThreadStarted = TRUE;
  1554. //
  1555. // Requested to be terminated by other thread while in above WFSO() or HALT state?
  1556. //
  1557. if(pStrmExt->bTerminateThread) {
  1558. KeReleaseMutex(pStrmExt->XmtThreadMutex, FALSE);
  1559. goto ThreadTherminating;
  1560. }
  1561. //
  1562. // Update thread state
  1563. //
  1564. ASSERT(pStrmExt->XmtState != THD_TERMINATE); // Should terminate instead of coming here!
  1565. ASSERT(pStrmExt->cntSRBReceived > 0); // Cannot run without data!
  1566. #if DBG
  1567. if(pStrmExt->XmtState == THD_HALT) {
  1568. TRACE(TL_STRM_WARNING,("HALT to RUNNING\n"));
  1569. }
  1570. #endif
  1571. pStrmExt->XmtState = THD_RUNNING;
  1572. //
  1573. // Attach write frame(s)
  1574. //
  1575. Status =
  1576. DVAttachWriteFrame(
  1577. pStrmExt);
  1578. if(STATUS_INSUFFICIENT_RESOURCES == Status) {
  1579. TRACE(TL_STRM_ERROR,("STATUS_INSUFFICIENT_RESOURCES while attaching write frame.\n"));
  1580. pStrmExt->bTerminateThread = TRUE;
  1581. KeReleaseMutex(pStrmExt->XmtThreadMutex, FALSE);
  1582. goto ThreadTherminating;
  1583. }
  1584. //
  1585. // Start Isoch_Talk once we have enough buffers attached. This number of attached buffer
  1586. // will ensure that there are sufficent buffers for lower stack (61883.sys) to start
  1587. // isoch data transfer. It is simliar to the preroll that we are doing above.
  1588. // Note: for trasnmit, the data transmission can start in either PAUSE or RUN state.
  1589. //
  1590. if(
  1591. !pStrmExt->bIsochIsActive
  1592. && ( pStrmExt->StreamState == KSSTATE_PAUSE
  1593. || pStrmExt->StreamState == KSSTATE_RUN
  1594. )
  1595. && pStrmExt->cntDataAttached >= NUM_BUF_ATTACHED_THEN_ISOCH
  1596. ) {
  1597. Status =
  1598. DVStreamingStart(
  1599. pStrmExt->pStrmInfo->DataFlow,
  1600. pStrmExt,
  1601. pDevExt
  1602. );
  1603. }
  1604. //
  1605. // Release mutex so other thread can request service
  1606. //
  1607. KeReleaseMutex(pStrmExt->XmtThreadMutex, FALSE);
  1608. }
  1609. ThreadTherminating:
  1610. TRACE(TL_STRM_WARNING,("\'*** ThreadTerminating... AQD [%d:%d:%d]\n",
  1611. pStrmExt->cntDataAttached,
  1612. pStrmExt->cntSRBQueued,
  1613. pStrmExt->cntDataDetached
  1614. ));
  1615. KeSetEvent(&pStrmExt->hThreadEndEvent, 0, FALSE); // Signal it to inform requester that this thread is about to be terminated.
  1616. Status = PsTerminateSystemThread(STATUS_SUCCESS); // Must be called at PASSIVE_LEVEL
  1617. // End of this thread!
  1618. }
  1619. VOID
  1620. DVTerminateAttachFrameThread(
  1621. IN PSTREAMEX pStrmExt
  1622. )
  1623. /*++
  1624. Routine Description:
  1625. To terminate the system thread. It waits for an event that is triggered
  1626. right before PsTerminateSystemThread() is called.
  1627. --*/
  1628. {
  1629. PAGED_CODE();
  1630. TRACE(TL_CIP_WARNING,("\'DVTerminateAttachFrameThread enter\n"));
  1631. //
  1632. // Wake up the DataReady thread and terminate it if not already done so.
  1633. //
  1634. ASSERT(pStrmExt->bIsochIsActive == FALSE && "Terminate therad while IsochActive!");
  1635. //
  1636. // This function can be called from either CloseStrean or SurpriseRemoval;
  1637. // When a DV is surprise removal, this function may get called from both functions.
  1638. // Assuming StreamClass is serializing these two functions, no need to serialize it locally.
  1639. //
  1640. if(pStrmExt->bTerminateThread) {
  1641. TRACE(TL_CIP_ERROR,("DVTerminateAttachFrameThread: Thread already terminated. Was surprise removed?\n"));
  1642. return;
  1643. }
  1644. //
  1645. // Terminate this attach frame thread.
  1646. //
  1647. DVSetXmtThreadState(pStrmExt, THD_TERMINATE);
  1648. KeWaitForSingleObject(
  1649. &pStrmExt->hThreadEndEvent,
  1650. Executive,
  1651. KernelMode,
  1652. FALSE,
  1653. NULL
  1654. );
  1655. TRACE(TL_STRM_WARNING,("\'Thread terminated!\n"));
  1656. ObDereferenceObject(
  1657. &pStrmExt->pAttachFrameThreadObject
  1658. );
  1659. TRACE(TL_STRM_WARNING,("\'ObDereferenceObject done!\n"));
  1660. }