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.

3046 lines
94 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1999 - 2000
  3. Module Name:
  4. MsTpUtil.c
  5. Abstract:
  6. Provide utility functions for MSTAPE.
  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 "avc.h"
  20. #include "dbg.h"
  21. #include "MsTpFmt.h"
  22. #include "MsTpDef.h"
  23. #include "MsTpAvc.h"
  24. #include "MsTpUtil.h"
  25. #include "XPrtDefs.h"
  26. #if 0 // Enable later
  27. #ifdef ALLOC_PRAGMA
  28. #pragma alloc_text(PAGE, DVDelayExecutionThread)
  29. #pragma alloc_text(PAGE, DVGetUnitCapabilities)
  30. // Local variables might paged out but the called might use it in DISPATCH level!
  31. // #pragma alloc_text(PAGE, DVGetDevModeOfOperation)
  32. // #pragma alloc_text(PAGE, DVGetDevIsItDVCPro)
  33. // #pragma alloc_text(PAGE, DVGetDevSignalFormat)
  34. #pragma alloc_text(PAGE, DvAllocatePCResource)
  35. #pragma alloc_text(PAGE, DvFreePCResource)
  36. #pragma alloc_text(PAGE, DVGetPlugState)
  37. #endif
  38. #endif
  39. extern AVCSTRM_FORMAT_INFO AVCStrmFormatInfoTable[];
  40. VOID
  41. DVDelayExecutionThread(
  42. ULONG ulDelayMSec
  43. )
  44. /*
  45. Device might need a "wait" in between AV/C commands.
  46. */
  47. {
  48. PAGED_CODE();
  49. if (ulDelayMSec)
  50. {
  51. LARGE_INTEGER tmDelay;
  52. TRACE(TL_PNP_TRACE,("DelayExeThrd: %d MSec\n", ulDelayMSec));
  53. tmDelay.LowPart = (ULONG) (-1 * ulDelayMSec * 10000);
  54. tmDelay.HighPart = -1;
  55. KeDelayExecutionThread(KernelMode, FALSE, &tmDelay);
  56. }
  57. }
  58. NTSTATUS
  59. DVIrpSynchCR(
  60. IN PDEVICE_OBJECT DeviceObject,
  61. IN PIRP pIrp,
  62. IN PKEVENT Event
  63. )
  64. {
  65. KeSetEvent(Event, 0, FALSE);
  66. return STATUS_MORE_PROCESSING_REQUIRED;
  67. } // DVIrpSynchCR
  68. NTSTATUS
  69. DVSubmitIrpSynch(
  70. IN PDVCR_EXTENSION pDevExt,
  71. IN PIRP pIrp,
  72. IN PAV_61883_REQUEST pAVReq
  73. )
  74. {
  75. NTSTATUS Status;
  76. KEVENT Event;
  77. PIO_STACK_LOCATION NextIrpStack;
  78. Status = STATUS_SUCCESS;;
  79. NextIrpStack = IoGetNextIrpStackLocation(pIrp);
  80. NextIrpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  81. NextIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_61883_CLASS;
  82. NextIrpStack->Parameters.Others.Argument1 = pAVReq;
  83. KeInitializeEvent(&Event, NotificationEvent, FALSE);
  84. IoSetCompletionRoutine(
  85. pIrp,
  86. DVIrpSynchCR,
  87. &Event,
  88. TRUE,
  89. TRUE,
  90. TRUE
  91. );
  92. Status =
  93. IoCallDriver(
  94. pDevExt->pBusDeviceObject,
  95. pIrp
  96. );
  97. if (Status == STATUS_PENDING) {
  98. TRACE(TL_PNP_TRACE,("Irp is pending...\n"));
  99. if(KeGetCurrentIrql() < DISPATCH_LEVEL) {
  100. KeWaitForSingleObject(
  101. &Event,
  102. Executive,
  103. KernelMode,
  104. FALSE,
  105. NULL
  106. );
  107. TRACE(TL_PNP_TRACE,("Irp has completed; IoStatus.Status %x\n", pIrp->IoStatus.Status));
  108. Status = pIrp->IoStatus.Status; // Final status
  109. }
  110. else {
  111. ASSERT(FALSE && "Pending but in DISPATCH_LEVEL!");
  112. return Status;
  113. }
  114. }
  115. return Status;
  116. } // DVSubmitIrpSynchAV
  117. #ifdef SUPPORT_LOCAL_PLUGS
  118. BOOL
  119. AVCTapeCreateLocalPlug(
  120. IN PDVCR_EXTENSION pDevExt,
  121. IN AV_61883_REQUEST * pAVReq,
  122. IN CMP_PLUG_TYPE PlugType,
  123. IN AV_PCR *pPCR,
  124. OUT ULONG *pPlugNumber,
  125. OUT HANDLE *pPlugHandle
  126. )
  127. /*
  128. To be a compliant device, we need to have both input and output
  129. plugs in order to do isoch streaming. These plug is belong to
  130. the device and is part of the device extension. In theory, the
  131. lugs belong to the unit (ei.e. avc.sys) and not this subunit
  132. Driver; however, in this case, we create directly from 61883.sys.
  133. */
  134. {
  135. NTSTATUS Status = STATUS_SUCCESS;
  136. PIRP pIrp;
  137. pIrp = IoAllocateIrp(pDevExt->pBusDeviceObject->StackSize, FALSE);
  138. if(!pIrp)
  139. return FALSE;
  140. // Create a local oPCR
  141. // Need to correctly update Overhead_ID and payload fields of PC's own oPCR
  142. RtlZeroMemory(pAVReq, sizeof(AV_61883_REQUEST));
  143. INIT_61883_HEADER(pAVReq, Av61883_CreatePlug);
  144. pAVReq->CreatePlug.Context = NULL;
  145. pAVReq->CreatePlug.pfnNotify = NULL;
  146. pAVReq->CreatePlug.PlugType = PlugType;
  147. if(PlugType == CMP_PlugOut)
  148. pAVReq->CreatePlug.Pcr.oPCR = pPCR->oPCR;
  149. else
  150. pAVReq->CreatePlug.Pcr.iPCR = pPCR->iPCR;
  151. Status = DVSubmitIrpSynch(pDevExt, pIrp, pAVReq);
  152. if(!NT_SUCCESS(Status)) {
  153. *pPlugNumber = 0xffffffff;
  154. *pPlugHandle = 0;
  155. TRACE(TL_61883_ERROR,("Av61883_CreatePlug (%s) Failed:%x\n",
  156. PlugType == CMP_PlugOut ? "oPCR":"iPCR", Status));
  157. } else {
  158. *pPlugNumber = pAVReq->CreatePlug.PlugNum;
  159. *pPlugHandle = pAVReq->CreatePlug.hPlug;
  160. TRACE(TL_61883_TRACE,("Av61883_CreatePlug (%s): PlugNum:%d, hPlug:%x\n",
  161. PlugType == CMP_PlugOut ? "oPCR":"iPCR", *pPlugNumber, *pPlugHandle));
  162. #if DBG
  163. if(PlugType == CMP_PlugOut) {
  164. TRACE(TL_61883_WARNING,("Av61883_CreatePlug: oPCR DataRate:%d (%s); Payload:%d, Overhead_ID:0x%x\n",
  165. pPCR->oPCR.DataRate,
  166. (pPCR->oPCR.DataRate == CMP_SPEED_S100) ? "S100" :
  167. (pPCR->oPCR.DataRate == CMP_SPEED_S200) ? "S200" :
  168. (pPCR->oPCR.DataRate == CMP_SPEED_S400) ? "S400" : "Sxxx",
  169. pPCR->oPCR.Payload,
  170. pPCR->oPCR.OverheadID
  171. ));
  172. }
  173. #endif
  174. }
  175. IoFreeIrp(pIrp);
  176. pIrp = NULL;
  177. return NT_SUCCESS(Status);
  178. }
  179. BOOL
  180. AVCTapeDeleteLocalPlug(
  181. IN PDVCR_EXTENSION pDevExt,
  182. IN AV_61883_REQUEST * pAVReq,
  183. OUT ULONG *pPlugNumber,
  184. OUT HANDLE *pPlugHandle
  185. )
  186. /*
  187. Delete a local plug.
  188. */
  189. {
  190. NTSTATUS Status = STATUS_SUCCESS;
  191. PIRP pIrp;
  192. TRACE(TL_61883_TRACE,("Deleting hPlug[%d]:%x\n", *pPlugNumber, *pPlugHandle));
  193. pIrp = IoAllocateIrp(pDevExt->pBusDeviceObject->StackSize, FALSE);
  194. if(!pIrp)
  195. return FALSE;
  196. RtlZeroMemory(pAVReq, sizeof(AV_61883_REQUEST));
  197. INIT_61883_HEADER(pAVReq, Av61883_DeletePlug);
  198. pAVReq->DeletePlug.hPlug = *pPlugHandle;
  199. Status = DVSubmitIrpSynch(pDevExt, pIrp, pAVReq);
  200. if(!NT_SUCCESS(Status)) {
  201. TRACE(TL_61883_ERROR,("Av61883_DeletePlug Failed; ST:%x\n", Status));
  202. // Do not care if this result in error.
  203. } else {
  204. *pPlugNumber = 0xffffffff;
  205. *pPlugHandle = 0;
  206. TRACE(TL_61883_TRACE,("Av61883_DeltePlug suceeded.\n"));
  207. }
  208. IoFreeIrp(pIrp);
  209. pIrp = NULL;
  210. return NT_SUCCESS(Status);
  211. }
  212. BOOL
  213. AVCTapeSetLocalPlug(
  214. IN PDVCR_EXTENSION pDevExt,
  215. IN AV_61883_REQUEST * pAVReq,
  216. IN HANDLE *pPlugHandle,
  217. IN AV_PCR *pPCR
  218. )
  219. /*
  220. Set the content of a local plug.
  221. */
  222. {
  223. NTSTATUS Status = STATUS_SUCCESS;
  224. PIRP pIrp;
  225. pIrp = IoAllocateIrp(pDevExt->pBusDeviceObject->StackSize, FALSE);
  226. if(!pIrp)
  227. return FALSE;
  228. RtlZeroMemory(pAVReq, sizeof(AV_61883_REQUEST));
  229. INIT_61883_HEADER(pAVReq, Av61883_SetPlug);
  230. pAVReq->SetPlug.hPlug = *pPlugHandle;
  231. pAVReq->SetPlug.Pcr = *pPCR;
  232. TRACE(TL_61883_TRACE,("Av61883_SetPlug hPlug:%x to %x.\n", *pPlugHandle, pPCR->ulongData));
  233. Status = DVSubmitIrpSynch(pDevExt, pIrp, pAVReq);
  234. #if DBG
  235. if(!NT_SUCCESS(Status)) {
  236. TRACE(TL_61883_ERROR,("Av61883_SetPlug to %x Failed; ST:%x\n", pPCR->ulongData, Status));
  237. }
  238. #endif
  239. IoFreeIrp(pIrp);
  240. pIrp = NULL;
  241. return NT_SUCCESS(Status);
  242. }
  243. #endif // SUPPORT_LOCAL_PLUGS
  244. //
  245. // Get device plug and query its state
  246. //
  247. NTSTATUS
  248. AVCDevGetDevPlug(
  249. IN PDVCR_EXTENSION pDevExt,
  250. IN CMP_PLUG_TYPE PlugType,
  251. IN ULONG PlugNum,
  252. OUT HANDLE *pPlugHandle
  253. )
  254. /*++
  255. Routine Description:
  256. Get the targe device's plug handle
  257. Arguments:
  258. Return Value:
  259. STATUS_SUCCESS
  260. STATUS_INSUFFICIENT_RESOURCES
  261. status return from 61883.
  262. --*/
  263. {
  264. PIRP pIrp;
  265. PAV_61883_REQUEST pAVReq;
  266. NTSTATUS Status = STATUS_SUCCESS;
  267. PAGED_CODE();
  268. if(!(pIrp = IoAllocateIrp(pDevExt->pBusDeviceObject->StackSize, FALSE)))
  269. return STATUS_INSUFFICIENT_RESOURCES;
  270. if(!(pAVReq = (AV_61883_REQUEST *) ExAllocatePool(NonPagedPool, sizeof(AV_61883_REQUEST)))) {
  271. IoFreeIrp(pIrp); pIrp = NULL;
  272. return STATUS_INSUFFICIENT_RESOURCES;
  273. }
  274. RtlZeroMemory(pAVReq, sizeof(AV_61883_REQUEST));
  275. INIT_61883_HEADER(pAVReq, Av61883_GetPlugHandle);
  276. pAVReq->GetPlugHandle.PlugNum = PlugNum;
  277. pAVReq->GetPlugHandle.hPlug = 0;
  278. pAVReq->GetPlugHandle.Type = PlugType;
  279. if(NT_SUCCESS(
  280. Status = DVSubmitIrpSynch(
  281. pDevExt,
  282. pIrp,
  283. pAVReq
  284. ))) {
  285. *pPlugHandle = pAVReq->GetPlugHandle.hPlug;
  286. TRACE(TL_61883_WARNING,("Created h%sPlugDV[%d]=%x\n", PlugType == CMP_PlugIn ? "I" : "O", PlugNum, *pPlugHandle));
  287. } else {
  288. TRACE(TL_61883_ERROR,("Created h%sPlugDV[%d] failed; Status:%x\n", PlugType == CMP_PlugIn ? "I" : "O", PlugNum, Status));
  289. Status = STATUS_INSUFFICIENT_RESOURCES;
  290. }
  291. IoFreeIrp(pIrp); pIrp = NULL;
  292. ExFreePool(pAVReq); pAVReq = NULL;
  293. return Status;
  294. }
  295. NTSTATUS
  296. AVCDevGetPlugState(
  297. IN PDVCR_EXTENSION pDevExt,
  298. IN HANDLE hPlug,
  299. OUT CMP_GET_PLUG_STATE *pPlugState
  300. )
  301. /*++
  302. Routine Description:
  303. Ask 61883.sys for the plug state.
  304. Arguments:
  305. Return Value:
  306. Nothing
  307. --*/
  308. {
  309. PIRP pIrp;
  310. PAV_61883_REQUEST pAVReq;
  311. NTSTATUS Status = STATUS_SUCCESS;
  312. PAGED_CODE();
  313. if(!hPlug || !pPlugState)
  314. return STATUS_INVALID_PARAMETER;
  315. if(!(pIrp = IoAllocateIrp(pDevExt->pBusDeviceObject->StackSize, FALSE)))
  316. return STATUS_INSUFFICIENT_RESOURCES;
  317. if(!(pAVReq = (AV_61883_REQUEST *) ExAllocatePool(NonPagedPool, sizeof(AV_61883_REQUEST)))) {
  318. IoFreeIrp(pIrp); pIrp = NULL;
  319. return STATUS_INSUFFICIENT_RESOURCES;
  320. }
  321. RtlZeroMemory(pAVReq, sizeof(AV_61883_REQUEST));
  322. INIT_61883_HEADER(pAVReq, Av61883_GetPlugState);
  323. pAVReq->GetPlugState.hPlug = hPlug;
  324. if(NT_SUCCESS(
  325. Status = DVSubmitIrpSynch(
  326. pDevExt,
  327. pIrp,
  328. pAVReq
  329. ))) {
  330. //
  331. // Transfer plug state (note: these are dynamic values)
  332. //
  333. *pPlugState = pAVReq->GetPlugState;
  334. TRACE(TL_61883_WARNING,("GetPlugState: ST %x; State %x; DRate %d (%s); Payld %d; BCCnt %d; PPCnt %d\n",
  335. pAVReq->Flags ,
  336. pAVReq->GetPlugState.State,
  337. pAVReq->GetPlugState.DataRate,
  338. (pAVReq->GetPlugState.DataRate == CMP_SPEED_S100) ? "S100" :
  339. (pAVReq->GetPlugState.DataRate == CMP_SPEED_S200) ? "S200" :
  340. (pAVReq->GetPlugState.DataRate == CMP_SPEED_S400) ? "S400" : "Sxxx",
  341. pAVReq->GetPlugState.Payload,
  342. pAVReq->GetPlugState.BC_Connections,
  343. pAVReq->GetPlugState.PP_Connections
  344. ));
  345. }
  346. else {
  347. TRACE(TL_61883_ERROR,("GetPlugState Failed %x\n", Status));
  348. }
  349. IoFreeIrp(pIrp); pIrp = NULL;
  350. ExFreePool(pAVReq); pAVReq = NULL;
  351. return Status;
  352. }
  353. #ifndef NT51_61883
  354. NTSTATUS
  355. AVCDevSubmitIrpSynch1394(
  356. IN PDEVICE_OBJECT pDevObj,
  357. IN PIRP pIrp,
  358. IN PIRB pIrb
  359. )
  360. {
  361. NTSTATUS Status;
  362. KEVENT Event;
  363. PIO_STACK_LOCATION NextIrpStack;
  364. Status = STATUS_SUCCESS;;
  365. NextIrpStack = IoGetNextIrpStackLocation(pIrp);
  366. NextIrpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  367. NextIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_1394_CLASS;
  368. NextIrpStack->Parameters.Others.Argument1 = pIrb;
  369. KeInitializeEvent(&Event, NotificationEvent, FALSE);
  370. IoSetCompletionRoutine(
  371. pIrp,
  372. DVIrpSynchCR,
  373. &Event,
  374. TRUE,
  375. TRUE,
  376. TRUE
  377. );
  378. Status =
  379. IoCallDriver(
  380. pDevObj,
  381. pIrp
  382. );
  383. if (Status == STATUS_PENDING) {
  384. TRACE(TL_PNP_TRACE,("Irp is pending...\n"));
  385. if(KeGetCurrentIrql() < DISPATCH_LEVEL) {
  386. KeWaitForSingleObject(
  387. &Event,
  388. Executive,
  389. KernelMode,
  390. FALSE,
  391. NULL
  392. );
  393. TRACE(TL_PNP_TRACE,("Irp has completed; IoStatus.Status %x\n", pIrp->IoStatus.Status));
  394. Status = pIrp->IoStatus.Status; // Final status
  395. }
  396. else {
  397. ASSERT(FALSE && "Pending but in DISPATCH_LEVEL!");
  398. return Status;
  399. }
  400. }
  401. return Status;
  402. } // AVCDevSubmitIrpSynch1394
  403. NTSTATUS
  404. Av1394_GetGenerationCount(
  405. IN PDVCR_EXTENSION pDevExt,
  406. OUT PULONG pGenerationCount
  407. )
  408. {
  409. NTSTATUS ntStatus = STATUS_SUCCESS;
  410. PIRP pIrp = NULL;
  411. PIRB p1394Irb = NULL;
  412. CCHAR StackSize;
  413. PAGED_CODE();
  414. StackSize = pDevExt->pBusDeviceObject->StackSize;
  415. pIrp = IoAllocateIrp(StackSize, FALSE);
  416. p1394Irb = ExAllocatePool(NonPagedPool, sizeof(IRB));
  417. if ((pIrp == NULL) || (p1394Irb == NULL)) {
  418. TRACE(TL_PNP_ERROR, ("Failed to allocate pIrp (%x) or p1394Irb (%x)", pIrp, p1394Irb));
  419. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  420. goto Exit_GetGenerationCount;
  421. }
  422. //
  423. // Get the current generation count first
  424. //
  425. p1394Irb->FunctionNumber = REQUEST_GET_GENERATION_COUNT;
  426. p1394Irb->Flags = 0;
  427. ntStatus = AVCDevSubmitIrpSynch1394(pDevExt->pBusDeviceObject, pIrp, p1394Irb);
  428. if (!NT_SUCCESS(ntStatus)) {
  429. TRACE(TL_PNP_ERROR, ("REQUEST_GET_GENERATION_COUNT Failed %x", ntStatus));
  430. goto Exit_GetGenerationCount;
  431. }
  432. *pGenerationCount = p1394Irb->u.GetGenerationCount.GenerationCount;
  433. Exit_GetGenerationCount:
  434. if(pIrp) {
  435. IoFreeIrp(pIrp); pIrp = NULL;
  436. }
  437. if(p1394Irb) {
  438. ExFreePool(p1394Irb); p1394Irb = NULL;
  439. }
  440. return(ntStatus);
  441. } // Av1394_GetGenerationCount
  442. #define RETRY_COUNT 4
  443. //
  444. // IEEE 1212 Directory definition
  445. //
  446. typedef struct _DIRECTORY_INFO {
  447. union {
  448. USHORT DI_CRC;
  449. USHORT DI_Saved_Length;
  450. } u;
  451. USHORT DI_Length;
  452. } DIRECTORY_INFO, *PDIRECTORY_INFO;
  453. //
  454. // IEEE 1212 Immediate entry definition
  455. //
  456. typedef struct _IMMEDIATE_ENTRY {
  457. ULONG IE_Value:24;
  458. ULONG IE_Key:8;
  459. } IMMEDIATE_ENTRY, *PIMMEDIATE_ENTRY;
  460. NTSTATUS
  461. Av1394_QuadletRead(
  462. IN PDVCR_EXTENSION pDevExt,
  463. IN OUT PULONG pData,
  464. IN ULONG Address
  465. )
  466. {
  467. NTSTATUS ntStatus = STATUS_SUCCESS;
  468. PIRP pIrp;
  469. PIRB p1394Irb;
  470. PMDL Mdl = NULL;
  471. ULONG Retries = RETRY_COUNT;
  472. CCHAR StackSize;
  473. PAGED_CODE();
  474. StackSize = pDevExt->pBusDeviceObject->StackSize;
  475. pIrp = IoAllocateIrp(StackSize, FALSE);
  476. p1394Irb = ExAllocatePool(NonPagedPool, sizeof(IRB));
  477. if ((pIrp == NULL) || (p1394Irb == NULL)) {
  478. TRACE(TL_PNP_ERROR, ("Failed to allocate Irp (0x%x) or Irb (0x%x)", pIrp, p1394Irb));
  479. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  480. goto Exit_Av1394_QuadletRead;
  481. }
  482. Mdl = IoAllocateMdl(pData, sizeof(ULONG), FALSE, FALSE, NULL);
  483. if (!Mdl) {
  484. TRACE(TL_PNP_ERROR, ("Failed to allocate Mdl!"));
  485. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  486. goto Exit_Av1394_QuadletRead;
  487. }
  488. MmBuildMdlForNonPagedPool(Mdl);
  489. do {
  490. p1394Irb->FunctionNumber = REQUEST_ASYNC_READ;
  491. p1394Irb->Flags = 0;
  492. p1394Irb->u.AsyncRead.DestinationAddress.IA_Destination_Offset.Off_High = (USHORT)0xffff;
  493. p1394Irb->u.AsyncRead.DestinationAddress.IA_Destination_Offset.Off_Low = Address;
  494. p1394Irb->u.AsyncRead.nNumberOfBytesToRead = 4;
  495. p1394Irb->u.AsyncRead.nBlockSize = 0;
  496. p1394Irb->u.AsyncRead.fulFlags = 0;
  497. p1394Irb->u.AsyncRead.Mdl = Mdl;
  498. p1394Irb->u.AsyncRead.ulGeneration = pDevExt->GenerationCount;
  499. p1394Irb->u.AsyncRead.chPriority = 0;
  500. p1394Irb->u.AsyncRead.nSpeed = 0;
  501. p1394Irb->u.AsyncRead.tCode = 0;
  502. p1394Irb->u.AsyncRead.Reserved = 0;
  503. ntStatus = AVCDevSubmitIrpSynch1394(pDevExt->pBusDeviceObject, pIrp, p1394Irb);
  504. if (ntStatus == STATUS_INVALID_GENERATION) {
  505. TRACE(TL_PNP_WARNING, ("QuadletRead: Invalid GenerationCount = %d", pDevExt->GenerationCount));
  506. Av1394_GetGenerationCount(pDevExt, &pDevExt->GenerationCount);
  507. }
  508. else if (!NT_SUCCESS(ntStatus)) {
  509. TRACE(TL_PNP_ERROR, ("Av1394_QuadletRead Failed = 0x%x Address = 0x%x", ntStatus, Address));
  510. }
  511. else {
  512. goto Exit_Av1394_QuadletRead;
  513. }
  514. } while ((ntStatus == STATUS_INVALID_GENERATION) || (Retries--));
  515. Exit_Av1394_QuadletRead:
  516. if(pIrp) {
  517. IoFreeIrp(pIrp); pIrp = NULL;
  518. }
  519. if(p1394Irb) {
  520. ExFreePool(p1394Irb); p1394Irb = NULL;
  521. }
  522. if(Mdl) {
  523. IoFreeMdl(Mdl); Mdl = NULL;
  524. }
  525. return(ntStatus);
  526. } // Av1394_QuadletRead
  527. #define KEY_ModuleVendorId (0x03)
  528. #define KEY_ModuleHwVersion (0x04)
  529. #define KEY_UnitSwVersion (0x13)
  530. #define KEY_ModelId (0x17)
  531. #define DEVICE_NAME_MAX_CHARS 100*sizeof(WCHAR)
  532. NTSTATUS
  533. Av1394_ReadTextualDescriptor(
  534. IN PDVCR_EXTENSION pDevExt,
  535. IN OUT PUNICODE_STRING uniString,
  536. IN ULONG Address
  537. )
  538. {
  539. NTSTATUS ntStatus = STATUS_SUCCESS;
  540. PULONG pData = NULL;
  541. ULONG DataLength, i, n;
  542. ULONG ulUnicode;
  543. ULONG ulQuadlet;
  544. union {
  545. ULONG asUlong;
  546. UCHAR asUchar[4];
  547. DIRECTORY_INFO DirectoryHeader;
  548. } u;
  549. PAGED_CODE();
  550. TRACE(TL_PNP_TRACE, ("Address = 0x%x", Address));
  551. // read the first quadlet of leaf, this is the header
  552. ntStatus = Av1394_QuadletRead(pDevExt, &ulQuadlet, Address);
  553. if (!NT_SUCCESS(ntStatus)) {
  554. TRACE(TL_PNP_ERROR, ("GetUnitInfo: QuadletRead Error = 0x%x", ntStatus));
  555. goto Exit_Av1394_ReadTextualDescriptor;
  556. }
  557. // number of entries
  558. u.asUlong = bswap(ulQuadlet);
  559. DataLength = u.DirectoryHeader.DI_Length-2; // one extra for the header
  560. // read the second quadlet of leaf to determine unicode
  561. Address += 4;
  562. ntStatus = Av1394_QuadletRead(pDevExt, &ulQuadlet, Address);
  563. if (!NT_SUCCESS(ntStatus)) {
  564. TRACE(TL_PNP_ERROR, ("GetUnitInfo: QuadletRead Error = 0x%x", ntStatus));
  565. goto Exit_Av1394_ReadTextualDescriptor;
  566. }
  567. // save spec type
  568. ulUnicode = bswap(ulQuadlet);
  569. pData = ExAllocatePool(NonPagedPool, DataLength*sizeof(ULONG)+2);
  570. if (pData == NULL) {
  571. TRACE(TL_PNP_ERROR, ("Failed to allocate pData"));
  572. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  573. goto Exit_Av1394_ReadTextualDescriptor;
  574. }
  575. RtlZeroMemory(pData, DataLength*sizeof(ULONG)+2);
  576. // lets read in each quad
  577. Address += 8;
  578. for (i=0; i<DataLength; i++) {
  579. ntStatus = Av1394_QuadletRead(pDevExt, &u.asUlong, Address+(sizeof(ULONG)*i));
  580. if (!NT_SUCCESS(ntStatus)) {
  581. TRACE(TL_PNP_ERROR, ("GetUnitInfo: QuadletRead Error = 0x%x", ntStatus));
  582. goto Exit_Av1394_ReadTextualDescriptor;
  583. }
  584. // need to make sure we have valid characters...
  585. for (n=0; n<4; n++) {
  586. // we should be done if the char equals 0x00
  587. if (u.asUchar[n] == 0x00)
  588. break;
  589. if ((u.asUchar[n] == 0x2C) || (u.asUchar[n] < 0x20) || (u.asUchar[n] > 0x7F)) {
  590. TRACE(TL_PNP_WARNING, ("Invalid Character = 0x%x", u.asUchar[n]));
  591. // set it to space
  592. u.asUchar[n] = 0x20;
  593. }
  594. if (ulUnicode & 0x80000000)
  595. n++;
  596. }
  597. RtlCopyMemory((PULONG)pData+i, &u.asUlong, sizeof(ULONG));
  598. }
  599. // if there's a vendor leaf, then convert it to unicode
  600. {
  601. ANSI_STRING ansiString;
  602. uniString->Length = 0;
  603. uniString->MaximumLength = DEVICE_NAME_MAX_CHARS;
  604. uniString->Buffer = ExAllocatePool(NonPagedPool, uniString->MaximumLength);
  605. if (!uniString->Buffer) {
  606. TRACE(TL_PNP_ERROR, ("Failed to allocate uniString.Buffer!"));
  607. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  608. goto Exit_Av1394_ReadTextualDescriptor;
  609. }
  610. RtlZeroMemory(uniString->Buffer, uniString->MaximumLength);
  611. // unicode??
  612. if (ulUnicode & 0x80000000) {
  613. RtlAppendUnicodeToString(uniString, ((PWSTR)pData));
  614. }
  615. else {
  616. RtlInitAnsiString(&ansiString, (PUCHAR)pData);
  617. RtlAnsiStringToUnicodeString(uniString, &ansiString, FALSE);
  618. }
  619. }
  620. Exit_Av1394_ReadTextualDescriptor:
  621. if (pData)
  622. ExFreePool(pData);
  623. return(ntStatus);
  624. } // ReadTextualLeaf
  625. NTSTATUS
  626. AVCDevGetModelText(
  627. IN PDVCR_EXTENSION pDevExt,
  628. PUNICODE_STRING pUniRootModelString,
  629. PUNICODE_STRING pUniUnitModelString
  630. )
  631. {
  632. CCHAR StackSize;
  633. PIRP pIrp = NULL;
  634. PIRB p1394Irb = NULL;
  635. NTSTATUS ntStatus = STATUS_SUCCESS;
  636. CONFIG_ROM ConfigRom;
  637. ULONG ulQuadlet = 0;
  638. ULONG CurrAddress;
  639. PULONG UnitDir = NULL, UnitDirToFree = NULL;
  640. ULONG i;
  641. ULONG LastKey;
  642. union {
  643. ULONG asUlong;
  644. DIRECTORY_INFO DirInfo;
  645. IMMEDIATE_ENTRY Entry;
  646. } u, u2; //, u3;
  647. PAGED_CODE();
  648. StackSize = pDevExt->pBusDeviceObject->StackSize;
  649. pIrp = IoAllocateIrp(StackSize, FALSE);
  650. p1394Irb = ExAllocatePool(NonPagedPool, sizeof(IRB));
  651. if ((pIrp == NULL) || (p1394Irb == NULL)) {
  652. TRACE(TL_PNP_ERROR, ("Failed to allocate pIrp (%x) or p1394Irb (%x)", pIrp, p1394Irb));
  653. return STATUS_INSUFFICIENT_RESOURCES;
  654. }
  655. //
  656. // Get the current generation count (used to read config rom)
  657. //
  658. Av1394_GetGenerationCount(pDevExt, &pDevExt->GenerationCount);
  659. //
  660. // Get Model Text from the Root directory
  661. //
  662. CurrAddress = 0xF0000414;
  663. // root directory
  664. ntStatus = Av1394_QuadletRead(pDevExt, &ulQuadlet, CurrAddress);
  665. if (!NT_SUCCESS(ntStatus)) {
  666. TRACE(TL_PNP_ERROR, ("GetUnitInfo: QuadletRead Error = 0x%x", ntStatus));
  667. goto Exit_GetUnitInfo;
  668. }
  669. u.asUlong = bswap(ulQuadlet);
  670. TRACE(TL_PNP_TRACE, ("RootDir: Length = %d", u.DirInfo.DI_Length));
  671. // process the root directory
  672. for (i=0; i<u.DirInfo.DI_Length; i++) {
  673. CurrAddress += sizeof(ULONG);
  674. ntStatus = Av1394_QuadletRead(pDevExt, &ulQuadlet, CurrAddress);
  675. if (!NT_SUCCESS(ntStatus)) {
  676. TRACE(TL_PNP_ERROR, ("GetUnitInfo: QuadletRead Error = 0x%x", ntStatus));
  677. goto Exit_GetUnitInfo;
  678. }
  679. u2.asUlong = bswap(ulQuadlet);
  680. TRACE(TL_PNP_TRACE, ("CurrAddress = 0x%x Key = 0x%x Value = 0x%x",
  681. CurrAddress, u2.Entry.IE_Key, u2.Entry.IE_Value));
  682. // ModelId Textual Descriptor
  683. if ((u2.Entry.IE_Key == 0x81) && (LastKey == KEY_ModelId)) {
  684. // get the first entry of the textual descriptor
  685. Av1394_ReadTextualDescriptor( pDevExt,
  686. pUniRootModelString,
  687. CurrAddress+(u2.Entry.IE_Value*sizeof(ULONG))
  688. );
  689. }
  690. #if 0
  691. // ModelId Textual Descriptor Layer
  692. if ((u2.Entry.IE_Key == 0xC1) && (LastKey == KEY_ModelId)) {
  693. ULONG DescAddress;
  694. DescAddress = CurrAddress+(u2.Entry.IE_Value*sizeof(ULONG));
  695. Av1394_QuadletRead(pDevExt, &ulQuadlet, DescAddress);
  696. u3.asUlong = bswap(ulQuadlet);
  697. // get the first entry of the textual descriptor
  698. Av1394_ReadTextualDescriptor( pDevExt,
  699. pUniRootModelString,
  700. DescAddress+(u3.Entry.IE_Value*sizeof(ULONG))
  701. );
  702. }
  703. #endif
  704. LastKey = u2.Entry.IE_Key;
  705. }
  706. //
  707. // Get Configuration Info
  708. //
  709. p1394Irb->FunctionNumber = REQUEST_GET_CONFIGURATION_INFO;
  710. p1394Irb->Flags = 0;
  711. p1394Irb->u.GetConfigurationInformation.ConfigRom = NULL;
  712. p1394Irb->u.GetConfigurationInformation.UnitDirectoryBufferSize = 0;
  713. p1394Irb->u.GetConfigurationInformation.UnitDirectory = NULL;
  714. p1394Irb->u.GetConfigurationInformation.UnitDependentDirectoryBufferSize = 0;
  715. p1394Irb->u.GetConfigurationInformation.UnitDependentDirectory = NULL;
  716. p1394Irb->u.GetConfigurationInformation.VendorLeafBufferSize = 0;
  717. p1394Irb->u.GetConfigurationInformation.VendorLeaf = NULL;
  718. p1394Irb->u.GetConfigurationInformation.ModelLeafBufferSize = 0;
  719. p1394Irb->u.GetConfigurationInformation.ModelLeaf = NULL;
  720. ntStatus = AVCDevSubmitIrpSynch1394(pDevExt->pBusDeviceObject, pIrp, p1394Irb);
  721. if (!NT_SUCCESS(ntStatus)) {
  722. TRACE(TL_PNP_ERROR, ("REQUEST_GET_CONFIGURATION_INFO Failed %x", ntStatus));
  723. goto Exit_GetUnitInfo;
  724. }
  725. //
  726. // Allocate buffer in order retrieve unit directory of a config rom
  727. //
  728. if (p1394Irb->u.GetConfigurationInformation.UnitDirectoryBufferSize) {
  729. UnitDir = UnitDirToFree =
  730. p1394Irb->u.GetConfigurationInformation.UnitDirectory =
  731. ExAllocatePool(NonPagedPool, p1394Irb->u.GetConfigurationInformation.UnitDirectoryBufferSize);
  732. if (!p1394Irb->u.GetConfigurationInformation.UnitDirectory) {
  733. TRACE(TL_PNP_ERROR, ("Couldn't allocate memory for the UnitDirectory"));
  734. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  735. goto Exit_GetUnitInfo;
  736. }
  737. }
  738. else {
  739. TRACE(TL_PNP_ERROR, ("No Unit directory. Bad Device."));
  740. ntStatus = STATUS_BAD_DEVICE_TYPE;
  741. goto Exit_GetUnitInfo;
  742. }
  743. p1394Irb->u.GetConfigurationInformation.ConfigRom = &ConfigRom;
  744. p1394Irb->u.GetConfigurationInformation.UnitDependentDirectoryBufferSize = 0;
  745. p1394Irb->u.GetConfigurationInformation.VendorLeafBufferSize = 0;
  746. p1394Irb->u.GetConfigurationInformation.ModelLeafBufferSize = 0;
  747. ntStatus = AVCDevSubmitIrpSynch1394(pDevExt->pBusDeviceObject, pIrp, p1394Irb);
  748. if (!NT_SUCCESS(ntStatus)) {
  749. TRACE(TL_PNP_ERROR, ("2nd REQUEST_GET_CONFIGURATION_INFO Failed = 0x%x", ntStatus));
  750. goto Exit_GetUnitInfo;
  751. }
  752. //
  753. // Process unit directory; see this doc for detail:
  754. // 1394TA specification: Configuration ROM for AV/C device 1.0 (AVWG)
  755. //
  756. u.asUlong = bswap(*UnitDir++); // Get length, and dkip first quadlet
  757. TRACE(TL_PNP_TRACE, ("UnitDir: Length = %d", u.DirInfo.DI_Length));
  758. CurrAddress = p1394Irb->u.GetConfigurationInformation.UnitDirectoryLocation.IA_Destination_Offset.Off_Low;
  759. for (i=0; i<u.DirInfo.DI_Length; i++) {
  760. TRACE(TL_PNP_TRACE, ("i = %d UnitDir = 0x%x *UnitDir = 0x%x", i, UnitDir, *UnitDir));
  761. u2.asUlong = bswap(*UnitDir++);
  762. CurrAddress += sizeof(ULONG);
  763. TRACE(TL_PNP_TRACE, ("UnitDir Quadlet = 0x%x", u2.asUlong));
  764. //
  765. // ModelId Textual Descriptor
  766. //
  767. if ((u2.Entry.IE_Key == 0x81) && (LastKey == KEY_ModelId)) {
  768. // get the first entry of the textual descriptor
  769. Av1394_ReadTextualDescriptor(
  770. pDevExt,
  771. pUniUnitModelString,
  772. CurrAddress+(u2.Entry.IE_Value*sizeof(ULONG))
  773. );
  774. }
  775. #if 0
  776. //
  777. // UnitModelId Textual Descriptor Layer
  778. //
  779. if ((u2.Entry.IE_Key == 0xC1) && (LastKey == KEY_ModelId)) {
  780. ULONG DescAddress;
  781. DescAddress = CurrAddress+(u2.Entry.IE_Value*sizeof(ULONG));
  782. Av1394_QuadletRead(pDevExt, &ulQuadlet, DescAddress);
  783. u3.asUlong = bswap(ulQuadlet);
  784. // get the first entry of the textual descriptor
  785. Av1394_ReadTextualDescriptor(
  786. pDevExt,
  787. pUniUnitModelString,
  788. DescAddress+(u3.Entry.IE_Value*sizeof(ULONG))
  789. );
  790. }
  791. #endif
  792. LastKey = u2.Entry.IE_Key;
  793. }
  794. Exit_GetUnitInfo:
  795. if (UnitDirToFree) {
  796. ExFreePool(UnitDirToFree); UnitDirToFree = NULL;
  797. }
  798. if(pIrp) {
  799. IoFreeIrp(pIrp); pIrp = NULL;
  800. }
  801. if(p1394Irb) {
  802. ExFreePool(p1394Irb); p1394Irb = NULL;
  803. }
  804. return ntStatus;
  805. }
  806. #endif
  807. NTSTATUS
  808. DVGetUnitCapabilities(
  809. IN PDVCR_EXTENSION pDevExt,
  810. IN PIRP pIrp,
  811. IN PAV_61883_REQUEST pAVReq
  812. )
  813. {
  814. NTSTATUS Status;
  815. GET_UNIT_IDS * pUnitIds;
  816. GET_UNIT_CAPABILITIES * pUnitCaps;
  817. PAGED_CODE();
  818. //
  819. // Query device's capability
  820. //
  821. pUnitCaps = (GET_UNIT_CAPABILITIES *) ExAllocatePool(NonPagedPool, sizeof(GET_UNIT_CAPABILITIES));
  822. if(!pUnitCaps) {
  823. TRACE(TL_61883_ERROR,("DVGetUnitCapabilities: Allocate pUnitCaps (%d bytes) failed\n", sizeof(GET_UNIT_CAPABILITIES)));
  824. return STATUS_INSUFFICIENT_RESOURCES;
  825. }
  826. // UnitIDS is cached in DevExt.
  827. pUnitIds = &pDevExt->UnitIDs;
  828. RtlZeroMemory(pAVReq, sizeof(AV_61883_REQUEST));
  829. INIT_61883_HEADER(pAVReq, Av61883_GetUnitInfo);
  830. pAVReq->GetUnitInfo.nLevel = GET_UNIT_INFO_IDS;
  831. RtlZeroMemory(pUnitIds, sizeof(GET_UNIT_IDS)); // Initialize pointers.
  832. pAVReq->GetUnitInfo.Information = (PVOID) pUnitIds;
  833. Status =
  834. DVSubmitIrpSynch(
  835. pDevExt,
  836. pIrp,
  837. pAVReq
  838. );
  839. if(!NT_SUCCESS(Status)) {
  840. TRACE(TL_61883_ERROR,("Av61883_GetUnitCapabilities Failed = 0x%x\n", Status));
  841. pDevExt->UniqueID.QuadPart = 0;
  842. pDevExt->ulVendorID = 0;
  843. pDevExt->ulModelID = 0;
  844. }
  845. else {
  846. pDevExt->UniqueID = pUnitIds->UniqueID;
  847. pDevExt->ulVendorID = pUnitIds->VendorID;
  848. pDevExt->ulModelID = pUnitIds->ModelID;
  849. TRACE(TL_61883_TRACE,("UniqueId:(Low)%x:(High)%x; VendorID:%x; ModelID:%x\n",
  850. pDevExt->UniqueID.LowPart, pDevExt->UniqueID.HighPart, pDevExt->ulVendorID, pDevExt->ulModelID));
  851. //
  852. // Allocate memory needed for the text string for VendorText,
  853. // ModelText and UntiModelText.
  854. //
  855. if(pUnitIds->ulVendorLength) {
  856. pUnitIds->VendorText = (PWSTR) ExAllocatePool(NonPagedPool, pUnitIds->ulVendorLength);
  857. if(!pUnitIds->VendorText)
  858. goto AbortGetUnitCapabilities;
  859. }
  860. if(pUnitIds->ulModelLength) {
  861. pUnitIds->ModelText = (PWSTR) ExAllocatePool(NonPagedPool, pUnitIds->ulModelLength);
  862. if(!pUnitIds->ModelText)
  863. goto AbortGetUnitCapabilities;
  864. }
  865. #ifdef NT51_61883
  866. if(pUnitIds->ulUnitModelLength) {
  867. pUnitIds->UnitModelText = (PWSTR) ExAllocatePool(NonPagedPool, pUnitIds->ulUnitModelLength);
  868. if(!pUnitIds->UnitModelText)
  869. goto AbortGetUnitCapabilities;
  870. }
  871. #else
  872. //
  873. // 1st version of 61883.sys does not retrieve Root and Unit model text
  874. // the same way as in WinXP; so we retieve them directly using 1394 API
  875. //
  876. if(!NT_SUCCESS(AVCDevGetModelText(
  877. pDevExt,
  878. &pDevExt->UniRootModelString,
  879. &pDevExt->UniUnitModelString
  880. ))) {
  881. goto AbortGetUnitCapabilities;
  882. }
  883. #endif
  884. Status =
  885. DVSubmitIrpSynch(
  886. pDevExt,
  887. pIrp,
  888. pAVReq
  889. );
  890. }
  891. RtlZeroMemory(pAVReq, sizeof(AV_61883_REQUEST));
  892. INIT_61883_HEADER(pAVReq, Av61883_GetUnitInfo);
  893. pAVReq->GetUnitInfo.nLevel = GET_UNIT_INFO_CAPABILITIES;
  894. RtlZeroMemory(pUnitCaps, sizeof(GET_UNIT_CAPABILITIES)); // Initialize pointers.
  895. pAVReq->GetUnitInfo.Information = (PVOID) pUnitCaps;
  896. Status =
  897. DVSubmitIrpSynch(
  898. pDevExt,
  899. pIrp,
  900. pAVReq
  901. );
  902. if(!NT_SUCCESS(Status)) {
  903. TRACE(TL_61883_ERROR,("Av61883_GetUnitCapabilities Failed = 0x%x\n", Status));
  904. pDevExt->pDevOutPlugs->MaxDataRate = 0;
  905. pDevExt->pDevOutPlugs->NumPlugs = 0;
  906. pDevExt->pDevInPlugs->MaxDataRate = 0;
  907. pDevExt->pDevInPlugs->NumPlugs = 0;
  908. }
  909. else {
  910. //
  911. // There can never be more than MAX_NUM_PCR (= 31) of plugs
  912. //
  913. ASSERT(pUnitCaps->NumOutputPlugs <= MAX_NUM_PCR);
  914. ASSERT(pUnitCaps->NumInputPlugs <= MAX_NUM_PCR);
  915. pDevExt->pDevOutPlugs->MaxDataRate = pUnitCaps->MaxDataRate;
  916. pDevExt->pDevOutPlugs->NumPlugs = (pUnitCaps->NumOutputPlugs > MAX_NUM_PCR ? MAX_NUM_PCR : pUnitCaps->NumOutputPlugs);
  917. pDevExt->pDevInPlugs->MaxDataRate = pUnitCaps->MaxDataRate;
  918. pDevExt->pDevInPlugs->NumPlugs = (pUnitCaps->NumInputPlugs > MAX_NUM_PCR ? MAX_NUM_PCR : pUnitCaps->NumInputPlugs);
  919. }
  920. TRACE(TL_61883_TRACE,("** UnitCaps: OutP:%d; InP:%d; MDRate:%s; CtsF:%x; HwF:%x; VID:%x; MID:%x\n",
  921. pUnitCaps->NumOutputPlugs,
  922. pUnitCaps->NumInputPlugs,
  923. pUnitCaps->MaxDataRate == 0 ? "S100": pUnitCaps->MaxDataRate == 1? "S200" : "S400 or +",
  924. pUnitCaps->CTSFlags,
  925. pUnitCaps->HardwareFlags,
  926. pUnitIds->VendorID,
  927. pUnitIds->ModelID
  928. ));
  929. AbortGetUnitCapabilities:
  930. if(pUnitIds->ulVendorLength && pUnitIds->VendorText) {
  931. TRACE(TL_61883_TRACE,("Vendor: Len:%d; \"%S\"\n", pUnitIds->ulVendorLength, pUnitIds->VendorText));
  932. if(!NT_SUCCESS(Status)) {
  933. ExFreePool(pUnitIds->VendorText); pUnitIds->VendorText = NULL;
  934. }
  935. }
  936. if(pUnitIds->ulModelLength && pUnitIds->ModelText) {
  937. TRACE(TL_61883_TRACE,("Model: Len:%d; \"%S\"\n", pUnitIds->ulModelLength, pUnitIds->ModelText));
  938. if(!NT_SUCCESS(Status)) {
  939. ExFreePool(pUnitIds->ModelText); pUnitIds->ModelText = NULL;
  940. }
  941. }
  942. #ifdef NT51_61883
  943. if(pUnitIds->ulUnitModelLength && pUnitIds->UnitModelText) {
  944. TRACE(TL_61883_TRACE,("UnitModel (61883): Len:%d; \"%S\"\n", pUnitIds->ulUnitModelLength, pUnitIds->UnitModelText));
  945. if(!NT_SUCCESS(Status)) {
  946. ExFreePool(pUnitIds->UnitModelText); pUnitIds->UnitModelText = NULL;
  947. }
  948. }
  949. #else
  950. if(pDevExt->UniRootModelString.Length && pDevExt->UniRootModelString.Buffer) {
  951. TRACE(TL_61883_TRACE,("RootModel (MSTape): Len:%d; \"%S\"\n", pDevExt->UniRootModelString.Length, pDevExt->UniRootModelString.Buffer));
  952. if(!NT_SUCCESS(Status)) {
  953. ExFreePool(pDevExt->UniRootModelString.Buffer); pDevExt->UniRootModelString.Buffer = NULL;
  954. }
  955. }
  956. if(pDevExt->UniUnitModelString.Length && pDevExt->UniUnitModelString.Buffer) {
  957. TRACE(TL_61883_TRACE,("UnitModel (MSTape): Len:%d; \"%S\"\n", pDevExt->UniUnitModelString.Length, pDevExt->UniUnitModelString.Buffer));
  958. if(!NT_SUCCESS(Status)) {
  959. ExFreePool(pDevExt->UniUnitModelString.Buffer); pDevExt->UniUnitModelString.Buffer = NULL;
  960. }
  961. }
  962. #endif
  963. ExFreePool(pUnitCaps); pUnitCaps = NULL;
  964. return Status;
  965. }
  966. #ifdef SUPPORT_NEW_AVC_CMD
  967. BOOL
  968. InitializeAVCCommand (
  969. PAVC_CMD pAVCCmd,
  970. AvcCommandType CmdType,
  971. AvcSubunitType SubunitType,
  972. UCHAR SubunitID,
  973. AVC_COMMAND_OP_CODE Opcode
  974. )
  975. {
  976. switch(Opcode) {
  977. case OPC_UNIT_CONNECT_AV_20:
  978. pAVCCmd->DataLen = 8;
  979. pAVCCmd->ConnectAV.AudSrc = 3;
  980. pAVCCmd->ConnectAV.VidSrc = 3;
  981. pAVCCmd->ConnectAV.AudDst = 0; // subunit
  982. pAVCCmd->ConnectAV.VidDst = 0; // subunit
  983. pAVCCmd->ConnectAV.VidSrc = 0xff;
  984. pAVCCmd->ConnectAV.AudSrc = 0xff;
  985. pAVCCmd->ConnectAV.VidDst = 0x20;
  986. pAVCCmd->ConnectAV.AudDst = 0x20;
  987. break;
  988. case OPC_TAPE_PLAY_C3:
  989. pAVCCmd->DataLen = 4;
  990. // pAVCCmd->TapePlay.PlaybackMode =
  991. break;
  992. default:
  993. return FALSE;
  994. }
  995. pAVCCmd->CmdFrame.CmdHeader.CTS = 0;
  996. pAVCCmd->CmdFrame.CmdHeader.CmdType = CmdType;
  997. pAVCCmd->CmdFrame.CmdHeader.SubunitTypeID.SubunitType = SubunitType;
  998. pAVCCmd->CmdFrame.CmdHeader.SubunitTypeID.SubunitID = SubunitID;
  999. pAVCCmd->CmdFrame.CmdHeader.Opcode = Opcode;
  1000. return TRUE;
  1001. }
  1002. #endif // SUPPORT_NEW_AVC_CMD
  1003. BOOL
  1004. DVGetDevModeOfOperation(
  1005. IN PDVCR_EXTENSION pDevExt
  1006. )
  1007. {
  1008. NTSTATUS Status;
  1009. BYTE bAvcBuf[MAX_FCP_PAYLOAD_SIZE];
  1010. #ifdef SUPPORT_NEW_AVC_CMD
  1011. AVC_CMD AVCCmd;
  1012. #endif
  1013. PAGED_CODE();
  1014. #ifdef SUPPORT_NEW_AVC_CMD
  1015. InitializeAVCCommand(&AVCCmd, AVC_CTYPE_STATUS, AVC_SUBUNITTYPE_UNIT, 0, OPC_UNIT_CONNECT_AV_20);
  1016. InitializeAVCCommand(&AVCCmd, AVC_CTYPE_CONTROL, AVC_SUBUNITTYPE_TAPE_PLAYER, 0, OPC_TAPE_PLAY_C3);
  1017. AVCCmd.TapePlay.PlaybackMode = NEXT_FRAME; // Testing...
  1018. #endif
  1019. //
  1020. // Use ConnectAV STATUS cmd to determine mode of operation,
  1021. // except for some Canon DVs that it requires its vendor specific command
  1022. //
  1023. Status = DVIssueAVCCommand(pDevExt, AVC_CTYPE_STATUS, DV_CONNECT_AV_MODE, (PVOID) bAvcBuf);
  1024. TRACE(TL_61883_TRACE,("GetDevModeOfOperation(DV_CONNECT_AV_MODE): Status %x, %x %x %x %x : %x %x %x %x\n",
  1025. Status, bAvcBuf[0], bAvcBuf[1], bAvcBuf[2], bAvcBuf[3], bAvcBuf[4], bAvcBuf[5], bAvcBuf[6], bAvcBuf[7]));
  1026. if(Status == STATUS_SUCCESS) {
  1027. if(bAvcBuf[0] == 0x0c) {
  1028. if(bAvcBuf[1] == 0x00 &&
  1029. bAvcBuf[2] == 0x38 &&
  1030. bAvcBuf[3] == 0x38) {
  1031. pDevExt->ulDevType = ED_DEVTYPE_CAMERA;
  1032. } else
  1033. if(bAvcBuf[1] == 0xa0 &&
  1034. bAvcBuf[2] == 0x00 &&
  1035. bAvcBuf[3] == 0x00) {
  1036. pDevExt->ulDevType = ED_DEVTYPE_VCR;
  1037. }
  1038. }
  1039. } else if(pDevExt->ulVendorID == VENDORID_CANON) {
  1040. // If this is a Canon, we can try this:
  1041. Status = DVIssueAVCCommand(pDevExt, AVC_CTYPE_STATUS, DV_VEN_DEP_CANON_MODE, (PVOID) bAvcBuf);
  1042. TRACE(TL_61883_TRACE,("GetDevModeOfOperation(DV_VEN_DEP_CANON_MODE): Status %x, %x %x %x %x : %x %x %x %x\n",
  1043. Status, bAvcBuf[0], bAvcBuf[1], bAvcBuf[2], bAvcBuf[3], bAvcBuf[4], bAvcBuf[5], bAvcBuf[6], bAvcBuf[7]));
  1044. if(Status == STATUS_SUCCESS) {
  1045. if(bAvcBuf[0] == 0x0c) {
  1046. if(bAvcBuf[7] == 0x38) {
  1047. pDevExt->ulDevType = ED_DEVTYPE_CAMERA;
  1048. } else
  1049. if(bAvcBuf[7] == 0x20) {
  1050. pDevExt->ulDevType = ED_DEVTYPE_VCR;
  1051. }
  1052. }
  1053. }
  1054. }
  1055. //
  1056. // Connect AV is an optional command, a device may not support it.
  1057. // If this device support a tape subunit, we will assume we are in that device type.
  1058. //
  1059. if(Status != STATUS_SUCCESS) {
  1060. // We are the subunit driver so if any of the device type is a
  1061. // tape subunit, we are in that device type.
  1062. if( pDevExt->Subunit_Type[0] == AVC_DEVICE_TAPE_REC
  1063. || pDevExt->Subunit_Type[1] == AVC_DEVICE_TAPE_REC
  1064. || pDevExt->Subunit_Type[2] == AVC_DEVICE_TAPE_REC
  1065. || pDevExt->Subunit_Type[3] == AVC_DEVICE_TAPE_REC) {
  1066. pDevExt->ulDevType = ED_DEVTYPE_VCR;
  1067. } else {
  1068. pDevExt->ulDevType = ED_DEVTYPE_UNKNOWN; // Such as MediaConverter box.
  1069. }
  1070. TRACE(TL_PNP_ERROR|TL_FCP_ERROR,("GetDevModeOfOperation: failed but we choose DevType:%x\n", pDevExt->ulDevType));
  1071. }
  1072. TRACE(TL_61883_TRACE,("** Mode of operation: %s (%x); NumOPlg:%d; NumIPlg:%d\n",
  1073. pDevExt->ulDevType == ED_DEVTYPE_CAMERA ? "Camera" : pDevExt->ulDevType == ED_DEVTYPE_VCR ? "Tape" : "Unknown",
  1074. pDevExt->ulDevType, pDevExt->pDevOutPlugs->NumPlugs, pDevExt->pDevInPlugs->NumPlugs));
  1075. return TRUE;
  1076. }
  1077. BOOL
  1078. DVGetDevIsItDVCPro(
  1079. IN PDVCR_EXTENSION pDevExt
  1080. )
  1081. {
  1082. NTSTATUS Status;
  1083. BYTE bAvcBuf[MAX_FCP_PAYLOAD_SIZE];
  1084. PAGED_CODE();
  1085. //
  1086. // Use Panasnoic's vendor dependent command to determine if the system support DVCPro
  1087. //
  1088. Status = DVIssueAVCCommand(pDevExt, AVC_CTYPE_STATUS, DV_VEN_DEP_DVCPRO, (PVOID) bAvcBuf);
  1089. pDevExt->bDVCPro = (Status == STATUS_SUCCESS);
  1090. TRACE(TL_61883_TRACE,("GetDevIsItDVCPro? %s; Status %x, %x %x %x %x : %x %x %x %x\n",
  1091. pDevExt->bDVCPro ? "Yes":"No",
  1092. Status, bAvcBuf[0], bAvcBuf[1], bAvcBuf[2], bAvcBuf[3], bAvcBuf[4], bAvcBuf[5], bAvcBuf[6], bAvcBuf[7]));
  1093. return pDevExt->bDVCPro;
  1094. }
  1095. #define GET_MEDIA_FMT_MAX_RETRIES 10 // AVC.sys will retry so we may rey just once.
  1096. BOOL
  1097. DVGetDevSignalFormat(
  1098. IN PDVCR_EXTENSION pDevExt,
  1099. IN KSPIN_DATAFLOW DataFlow,
  1100. IN PSTREAMEX pStrmExt
  1101. )
  1102. {
  1103. NTSTATUS Status;
  1104. BYTE bAvcBuf[MAX_FCP_PAYLOAD_SIZE];
  1105. LONG lRetries = GET_MEDIA_FMT_MAX_RETRIES;
  1106. PAGED_CODE();
  1107. //
  1108. // Respone of Input/output signal mode is used to determine plug signal format:
  1109. //
  1110. // FMT:
  1111. // DVCR 10:00 0000 = 0x80; Canon returns 00:100000 (0x20)
  1112. // 50/60: 0:NTSC/60; 1:PAL/50
  1113. // STYPE:
  1114. // SD: 00000 (DVCPRO:11110)
  1115. // HD: 00010
  1116. // SDL:00001
  1117. // 00:
  1118. // SYT:
  1119. // MPEG 10:10 0000 = 0xa0
  1120. // TSF:0:NotTimeShifted; 1:Time shifted
  1121. // 000 0000 0000 0000 0000 0000
  1122. //
  1123. // If this command failed, we can use Input/Output Signal Mode subunit command
  1124. // to determine signal format.
  1125. //
  1126. do {
  1127. RtlZeroMemory(bAvcBuf, sizeof(bAvcBuf));
  1128. Status =
  1129. DVIssueAVCCommand(
  1130. pDevExt,
  1131. AVC_CTYPE_STATUS,
  1132. pStrmExt == NULL ? DV_OUT_PLUG_SIGNAL_FMT : pStrmExt->pStrmInfo->DataFlow == KSPIN_DATAFLOW_OUT ? DV_OUT_PLUG_SIGNAL_FMT : DV_IN_PLUG_SIGNAL_FMT,
  1133. (PVOID) bAvcBuf
  1134. );
  1135. --lRetries;
  1136. //
  1137. // Camcorders that has problem with this command:
  1138. //
  1139. // Panasonic's DVCPRO: if power on while connected to PC, it will
  1140. // reject this command with (STATUS_REQUEST_NOT_ACCEPTED)
  1141. // so we will retry up to 10 time with .5 second wait between tries.
  1142. //
  1143. // JVC: returns STATUS_NOT_SUPPORTED.
  1144. //
  1145. // SONY DV Decoder Box: return STATUS_TIMEOUT
  1146. //
  1147. if(Status == STATUS_SUCCESS ||
  1148. Status == STATUS_NOT_SUPPORTED ||
  1149. Status == STATUS_TIMEOUT) {
  1150. break; // No need to retry
  1151. } else
  1152. if(Status == STATUS_REQUEST_NOT_ACCEPTED) {
  1153. if(lRetries >= 0)
  1154. DVDelayExecutionThread(DV_AVC_CMD_DELAY_DVCPRO);
  1155. }
  1156. // else retry.
  1157. } while (lRetries >= 0);
  1158. if(NT_SUCCESS(Status)) {
  1159. switch(bAvcBuf[0]) {
  1160. case FMT_DVCR:
  1161. case FMT_DVCR_CANON: // Workaround for buggy Canon Camcorders
  1162. switch(bAvcBuf[1] & FDF0_STYPE_MASK) {
  1163. case FDF0_STYPE_SD_DVCR:
  1164. case FDF0_STYPE_SD_DVCPRO:
  1165. pDevExt->VideoFormatIndex = ((bAvcBuf[1] & FDF0_50_60_MASK) ? AVCSTRM_FORMAT_SDDV_PAL : AVCSTRM_FORMAT_SDDV_NTSC);
  1166. break;
  1167. case FDF0_STYPE_HD_DVCR:
  1168. pDevExt->VideoFormatIndex = ((bAvcBuf[1] & FDF0_50_60_MASK) ? AVCSTRM_FORMAT_HDDV_PAL : AVCSTRM_FORMAT_HDDV_NTSC);
  1169. break;
  1170. case FDF0_STYPE_SDL_DVCR:
  1171. pDevExt->VideoFormatIndex = ((bAvcBuf[1] & FDF0_50_60_MASK) ? AVCSTRM_FORMAT_SDLDV_PAL : AVCSTRM_FORMAT_SDLDV_NTSC);
  1172. break;
  1173. default: // Unknown format
  1174. Status = STATUS_UNSUCCESSFUL;
  1175. break;
  1176. }
  1177. break;
  1178. case FMT_MPEG:
  1179. pDevExt->VideoFormatIndex = AVCSTRM_FORMAT_MPEG2TS;
  1180. break;
  1181. default:
  1182. Status = STATUS_UNSUCCESSFUL;
  1183. }
  1184. if(NT_SUCCESS(Status)) {
  1185. TRACE(TL_PNP_ERROR|TL_FCP_ERROR,("ST:%x; PlugSignal:FMT[%x %x %x %x]; VideoFormatIndex;%d\n", Status, bAvcBuf[0], bAvcBuf[1], bAvcBuf[2] , bAvcBuf[3], pDevExt->VideoFormatIndex));
  1186. return TRUE; // Success
  1187. }
  1188. }
  1189. TRACE(TL_FCP_TRACE,("ST:%x; PlugSignal:FMT[%x %x %x %x]\n", Status, bAvcBuf[0], bAvcBuf[1], bAvcBuf[2] , bAvcBuf[3], pDevExt->VideoFormatIndex));
  1190. //
  1191. // If "recommended" unit input/output plug signal status command fails,
  1192. // try "manadatory" input/output signal mode status command.
  1193. // This command may failed some device if its tape is not playing for
  1194. // output signal mode command.
  1195. //
  1196. RtlZeroMemory(bAvcBuf, sizeof(bAvcBuf));
  1197. Status =
  1198. DVIssueAVCCommand(
  1199. pDevExt,
  1200. AVC_CTYPE_STATUS,
  1201. DataFlow == KSPIN_DATAFLOW_OUT ? VCR_OUTPUT_SIGNAL_MODE : VCR_INPUT_SIGNAL_MODE,
  1202. (PVOID) bAvcBuf
  1203. );
  1204. if(STATUS_SUCCESS == Status) {
  1205. PKSPROPERTY_EXTXPORT_S pXPrtProperty;
  1206. pXPrtProperty = (PKSPROPERTY_EXTXPORT_S) bAvcBuf;
  1207. TRACE(TL_STRM_TRACE|TL_FCP_TRACE,("** MediaFormat: Retry %d mSec; ST:%x; SignalMode:%dL\n",
  1208. (GET_MEDIA_FMT_MAX_RETRIES - lRetries) * DV_AVC_CMD_DELAY_DVCPRO, Status, pXPrtProperty->u.SignalMode - ED_BASE));
  1209. switch(pXPrtProperty->u.SignalMode) {
  1210. case ED_TRANSBASIC_SIGNAL_525_60_SD:
  1211. pDevExt->VideoFormatIndex = AVCSTRM_FORMAT_SDDV_NTSC;
  1212. if(pStrmExt) {
  1213. pStrmExt->cipQuad2[0] = FMT_DVCR; // 0x80
  1214. if(pDevExt->bDVCPro)
  1215. pStrmExt->cipQuad2[1] = FDF0_50_60_NTSC | FDF0_STYPE_SD_DVCPRO; // 0x78 = NTSC(0):STYPE(11110):RSV(00)
  1216. else
  1217. pStrmExt->cipQuad2[1] = FDF0_50_60_NTSC | FDF0_STYPE_SD_DVCR; // 0x00 = NTSC(0):STYPE(00000):RSV(00)
  1218. }
  1219. break;
  1220. case ED_TRANSBASIC_SIGNAL_625_50_SD:
  1221. pDevExt->VideoFormatIndex = AVCSTRM_FORMAT_SDDV_PAL;
  1222. if(pStrmExt) {
  1223. pStrmExt->cipQuad2[0] = FMT_DVCR; // 0x80
  1224. if(pDevExt->bDVCPro)
  1225. pStrmExt->cipQuad2[1] = FDF0_50_60_PAL | FDF0_STYPE_SD_DVCPRO; // 0xf8 = PAL(1):STYPE(11110):RSV(00)
  1226. else
  1227. pStrmExt->cipQuad2[1] = FDF0_50_60_PAL | FDF0_STYPE_SD_DVCR; // 0x80 = PAL(1):STYPE(00000):RSV(00)
  1228. }
  1229. break;
  1230. case ED_TRANSBASIC_SIGNAL_MPEG2TS:
  1231. pDevExt->VideoFormatIndex = AVCSTRM_FORMAT_MPEG2TS;
  1232. break;
  1233. default:
  1234. TRACE(TL_PNP_ERROR|TL_FCP_ERROR,("Unsupported SignalMode:%dL", pXPrtProperty->u.SignalMode - ED_BASE));
  1235. ASSERT(FALSE && "Unsupported IoSignal! Refuse to load.");
  1236. return FALSE;
  1237. break;
  1238. }
  1239. }
  1240. // WORKITEM Sony HW CODEC does not response to any AVC command.
  1241. // We are making an exception here to load it.
  1242. if(Status == STATUS_TIMEOUT) {
  1243. Status = STATUS_SUCCESS;
  1244. }
  1245. // We must know the signal format!! If this failed, the driver will either:
  1246. // fail to load, or fail to open an stream
  1247. ASSERT(Status == STATUS_SUCCESS && "Failed to get media signal format!\n");
  1248. #if DBG
  1249. if(pStrmExt) {
  1250. // Note: bAvcBuf[0] is operand[1] == 10:fmt
  1251. TRACE(TL_STRM_TRACE|TL_CIP_TRACE,("** MediaFormat: St:%x; idx:%d; CIP:[FMT:%.2x(%s); FDF:[%.2x(%s,%s):SYT]\n",
  1252. Status,
  1253. pDevExt->VideoFormatIndex,
  1254. pStrmExt->cipQuad2[0],
  1255. pStrmExt->cipQuad2[0] == FMT_DVCR ? "DVCR" : pStrmExt->cipQuad2[0] == FMT_MPEG ? "MPEG" : "Fmt:???",
  1256. pStrmExt->cipQuad2[1],
  1257. (pStrmExt->cipQuad2[1] & FDF0_50_60_MASK) == FDF0_50_60_PAL ? "PAL" : "NTSC",
  1258. (pStrmExt->cipQuad2[1] & FDF0_STYPE_MASK) == FDF0_STYPE_SD_DVCR ? "SD" : \
  1259. (pStrmExt->cipQuad2[1] & FDF0_STYPE_MASK) == FDF0_STYPE_SDL_DVCR ? "SDL" : \
  1260. (pStrmExt->cipQuad2[1] & FDF0_STYPE_MASK) == FDF0_STYPE_HD_DVCR ? "HD" : \
  1261. (pStrmExt->cipQuad2[1] & FDF0_STYPE_MASK) == FDF0_STYPE_SD_DVCPRO ? "DVCPRO" : "DV:????"
  1262. ));
  1263. } else
  1264. TRACE(TL_STRM_TRACE|TL_CIP_TRACE,("** MediaFormat: St:%x; use idx:%d\n", Status, pDevExt->VideoFormatIndex));
  1265. #endif
  1266. return STATUS_SUCCESS == Status;
  1267. }
  1268. BOOL
  1269. DVCmpGUIDsAndFormatSize(
  1270. IN PKSDATARANGE pDataRange1,
  1271. IN PKSDATARANGE pDataRange2,
  1272. IN BOOL fCompareFormatSize
  1273. )
  1274. /*++
  1275. Routine Description:
  1276. Checks for a match on the three GUIDs and FormatSize
  1277. Arguments:
  1278. IN pDataRange1
  1279. IN pDataRange2
  1280. Return Value:
  1281. TRUE if all elements match
  1282. FALSE if any are different
  1283. --*/
  1284. {
  1285. return (
  1286. IsEqualGUID (
  1287. &pDataRange1->MajorFormat,
  1288. &pDataRange2->MajorFormat) &&
  1289. IsEqualGUID (
  1290. &pDataRange1->SubFormat,
  1291. &pDataRange2->SubFormat) &&
  1292. IsEqualGUID (
  1293. &pDataRange1->Specifier,
  1294. &pDataRange2->Specifier) &&
  1295. (fCompareFormatSize ?
  1296. (pDataRange1->FormatSize == pDataRange2->FormatSize) : TRUE ));
  1297. }
  1298. //
  1299. // GetSystemTime in 100 nS units
  1300. //
  1301. ULONGLONG GetSystemTime()
  1302. {
  1303. LARGE_INTEGER rate, ticks;
  1304. ticks = KeQueryPerformanceCounter(&rate);
  1305. return (KSCONVERT_PERFORMANCE_TIME(rate.QuadPart, ticks));
  1306. }
  1307. VOID
  1308. DvFreeTextualString(
  1309. PDVCR_EXTENSION pDevExt,
  1310. GET_UNIT_IDS * pUnitIds
  1311. )
  1312. {
  1313. if(pUnitIds->ulVendorLength && pUnitIds->VendorText) {
  1314. ExFreePool(pUnitIds->VendorText); pUnitIds->VendorText = NULL;
  1315. }
  1316. if(pUnitIds->ulModelLength && pUnitIds->ModelText) {
  1317. ExFreePool(pUnitIds->ModelText); pUnitIds->ModelText = NULL;
  1318. }
  1319. #ifdef NT51_61883
  1320. if(pUnitIds->ulUnitModelLength && pUnitIds->UnitModelText) {
  1321. ExFreePool(pUnitIds->UnitModelText); pUnitIds->UnitModelText = NULL;
  1322. }
  1323. #else
  1324. if(pDevExt->UniRootModelString.Length && pDevExt->UniRootModelString.Buffer) {
  1325. ExFreePool(pDevExt->UniRootModelString.Buffer); pDevExt->UniRootModelString.Buffer = NULL;
  1326. }
  1327. if(pDevExt->UniUnitModelString.Length && pDevExt->UniUnitModelString.Buffer) {
  1328. ExFreePool(pDevExt->UniUnitModelString.Buffer); pDevExt->UniUnitModelString.Buffer = NULL;
  1329. }
  1330. #endif
  1331. }
  1332. #define DIFBLK_SIZE 12000
  1333. #define PACK_NO_INFO 0xff
  1334. // Subcode header identifier
  1335. #define SC_HDR_TIMECODE 0x13
  1336. #define SC_HDR_BINARYGROUP 0x14
  1337. // header identifier
  1338. #define AAUX_HDR_SOURCE 0x50
  1339. #define AAUX_HDR_SOURCE_CONTROL 0x51
  1340. #define AAUX_HDR_REC_DATE 0x52
  1341. #define AAUX_HDR_REC_TIME 0x53
  1342. #define AAUX_HDR_BINARY_GROUP 0x54
  1343. #define AAUX_HDR_CC 0x55
  1344. #define AAUX_HDR_TR 0x56
  1345. #define VAUX_HDR_SOURCE 0x60
  1346. #define VAUX_HDR_SOURCE_CONTROL 0x61
  1347. #define VAUX_HDR_REC_DATE 0x62
  1348. #define VAUX_HDR_REC_TIME 0x63
  1349. #define VAUX_HDR_BINARY_GROUP 0x64
  1350. #define VAUX_HDR_CC 0x65
  1351. #define VAUX_HDR_TR 0x66
  1352. // Determine section type (MS 3 bits); Fig.66; Table 36.
  1353. #define ID0_SCT_MASK 0xe0
  1354. #define ID0_SCT_HEADER 0x00
  1355. #define ID0_SCT_SUBCODE 0x20
  1356. #define ID0_SCT_VAUX 0x40
  1357. #define ID0_SCT_AUDIO 0x60
  1358. #define ID0_SCT_VIDEO 0x80
  1359. // A pack is consisted of one byte of header identifier and 4 bytes of data; Part2, annex D.
  1360. typedef struct _DV_PACK {
  1361. UCHAR Header;
  1362. UCHAR Data[4];
  1363. } DV_PACK, *PDV_PACK;
  1364. typedef struct _DV_H0 {
  1365. UCHAR ID0;
  1366. UCHAR ID1;
  1367. UCHAR ID2;
  1368. UCHAR DSF;
  1369. UCHAR DFTIA;
  1370. UCHAR TF1;
  1371. UCHAR TF2;
  1372. UCHAR TF3;
  1373. UCHAR Reserved[72];
  1374. } DV_H0, *PDV_H0;
  1375. typedef struct _DV_SC {
  1376. UCHAR ID0;
  1377. UCHAR ID1;
  1378. UCHAR ID2;
  1379. struct {
  1380. UCHAR SID0;
  1381. UCHAR SID1;
  1382. UCHAR Reserved;
  1383. DV_PACK Pack;
  1384. } SSyb0;
  1385. struct {
  1386. UCHAR SID0;
  1387. UCHAR SID1;
  1388. UCHAR Reserved;
  1389. DV_PACK Pack;
  1390. } SSyb1;
  1391. struct {
  1392. UCHAR SID0;
  1393. UCHAR SID1;
  1394. UCHAR Reserved;
  1395. DV_PACK Pack;
  1396. } SSyb2;
  1397. struct {
  1398. UCHAR SID0;
  1399. UCHAR SID1;
  1400. UCHAR Reserved;
  1401. DV_PACK Pack;
  1402. } SSyb3;
  1403. struct {
  1404. UCHAR SID0;
  1405. UCHAR SID1;
  1406. UCHAR Reserved;
  1407. DV_PACK Pack;
  1408. } SSyb4;
  1409. struct {
  1410. UCHAR SID0;
  1411. UCHAR SID1;
  1412. UCHAR Reserved;
  1413. DV_PACK Pack;
  1414. } SSyb5;
  1415. UCHAR Reserved[29];
  1416. } DV_SC, *PDV_SC;
  1417. #define MAX_VAUX_PACK 15
  1418. typedef struct _DV_VAUX {
  1419. UCHAR ID0;
  1420. UCHAR ID1;
  1421. UCHAR ID2;
  1422. DV_PACK Pack[MAX_VAUX_PACK];
  1423. UCHAR Reserved[2];
  1424. } DV_VAUX, *PDV_VAUX;
  1425. typedef struct _DV_A {
  1426. UCHAR ID0;
  1427. UCHAR ID1;
  1428. UCHAR ID2;
  1429. DV_PACK Pack;
  1430. UCHAR Data[72];
  1431. } DV_A, *PDV_A;
  1432. typedef struct _DV_V {
  1433. UCHAR ID0;
  1434. UCHAR ID1;
  1435. UCHAR ID2;
  1436. UCHAR Data[77]; // 3..79
  1437. } DV_V, *PDV_V;
  1438. // Two source packets
  1439. #define V_BLOCKS 15
  1440. typedef struct _DV_AV {
  1441. DV_A A;
  1442. DV_V V[V_BLOCKS];
  1443. } DV_AV, *PDV_AV;
  1444. #define SC_SECTIONS 2
  1445. #define VAUX_SECTIONS 3
  1446. #define AV_SECTIONS 9
  1447. typedef struct _DV_DIF_SEQ {
  1448. DV_H0 H0;
  1449. DV_SC SC[SC_SECTIONS];
  1450. DV_VAUX VAux[VAUX_SECTIONS];
  1451. DV_AV AV[AV_SECTIONS];
  1452. } DV_DIF_SEQ, *PDV_DIF_SEQ;
  1453. typedef struct _DV_FRAME_NTSC {
  1454. DV_DIF_SEQ DifSeq[10];
  1455. } DV_FRAME_NTSC, *PDV_FRAME_NTSC;
  1456. typedef struct _DV_FRAME_PAL {
  1457. DV_DIF_SEQ DifSeq[12];
  1458. } DV_FRAME_PAL, *PDV_FRAME_PAL;
  1459. // By setting REC MODE to 111b (invalid recording) can
  1460. // cause DV to mute the audio
  1461. #define AAUX_REC_MODE_INVALID_MASK 0x38 // xx11:1xxx
  1462. #define AAUX_REC_MODE_ORIGINAL 0x08 // xx00:1xxx
  1463. #ifdef MSDV_SUPPORT_MUTE_AUDIO
  1464. BOOL
  1465. DVMuteDVFrame(
  1466. IN PDVCR_EXTENSION pDevExt,
  1467. IN OUT PUCHAR pFrameBuffer,
  1468. IN BOOL bMuteAudio
  1469. )
  1470. {
  1471. PDV_DIF_SEQ pDifSeq;
  1472. #if 0
  1473. PDV_VAUX pVAux;
  1474. ULONG k;
  1475. #endif
  1476. ULONG i, j;
  1477. #if 0
  1478. BOOL bFound1 = FALSE;
  1479. #endif
  1480. BOOL bFound2 = FALSE;
  1481. pDifSeq = (PDV_DIF_SEQ) pFrameBuffer;
  1482. // find the VVAX Source pack
  1483. for (i=0; i < AVCStrmFormatInfoTable[pDevExt->VideoFormatIndex].FrameSize/DIFBLK_SIZE; i++) {
  1484. // #define SHOW_ONE_FIELD_TWICE
  1485. #ifdef SHOW_ONE_FIELD_TWICE // Advise by Adobe that we may want to show bothj field but mute audio
  1486. // Make the field2 output twice, FrameChange to 0 (same as previous frame)
  1487. for (j=0; j < VAUX_SECTIONS; j++) {
  1488. pVAux = &pDifSeq->VAux[j];
  1489. if((pVAux->ID0 & ID0_SCT_MASK) != ID0_SCT_VAUX) {
  1490. TRACE(TL_CIP_TRACE,("Invalid ID0:%.2x for pVAUX:%x (Dif:%d;V%d;S%d)\n", pVAux->ID0, pVAux, i, j, k));
  1491. continue;
  1492. }
  1493. for (k=0; k< MAX_VAUX_PACK; k++) {
  1494. if(pVAux->Pack[k].Header == VAUX_HDR_SOURCE_CONTROL) {
  1495. if(bMuteAudio) {
  1496. TRACE(TL_CIP_TRACE,("Mute Audio; pDifSeq:%x; pVAux:%x; (Dif:%d,V%d,S%d); %.2x,[%.2x,%.2x,%.2x,%.2x]; pack[2]->%.2x\n", \
  1497. pDifSeq, pVAux, i, j, k, \
  1498. pVAux->Pack[k].Header, pVAux->Pack[k].Data[0], pVAux->Pack[k].Data[1], pVAux->Pack[k].Data[2], pVAux->Pack[k].Data[3], \
  1499. (pVAux->Pack[k].Data[2] & 0x1F) ));
  1500. pVAux->Pack[k].Data[2] &= 0x1f; // 0x1F; // set FF, FS and FC to 0
  1501. TRACE(TL_CIP_INFO,("pVAux->Pack[k].Data[2] = %.2x\n", pVAux->Pack[k].Data[2]));
  1502. } else {
  1503. TRACE(TL_CIP_INFO,("un-Mute Audio; pack[2]: %.2x ->%.2x\n", pVAux->Pack[k].Data[2], (pVAux->Pack[k].Data[2] | 0xc0) ));
  1504. pVAux->Pack[k].Data[2] |= 0xe0; // set FF, FS and FCto 1; Show both fields in field 1,2 order
  1505. }
  1506. bFound1 = TRUE;
  1507. break; // Set only the 1st occurrence
  1508. }
  1509. }
  1510. }
  1511. #endif
  1512. for (j=0; j < AV_SECTIONS; j++) {
  1513. if(pDifSeq->AV[j].A.Pack.Header == AAUX_HDR_SOURCE_CONTROL) {
  1514. TRACE(TL_CIP_INFO,("A0Aux %.2x,[%.2x,%.2x,%.2x,%.2x] %.2x->%.2x\n", \
  1515. pDifSeq->AV[j].A.Pack.Header, pDifSeq->AV[j].A.Pack.Data[0], \
  1516. pDifSeq->AV[j].A.Pack.Data[1], pDifSeq->AV[j].A.Pack.Data[2], pDifSeq->AV[j].A.Pack.Data[3], \
  1517. pDifSeq->AV[j].A.Pack.Data[1], pDifSeq->AV[j].A.Pack.Data[1] | AAUX_REC_MODE_INVALID_MASK
  1518. ));
  1519. if(bMuteAudio)
  1520. pDifSeq->AV[j].A.Pack.Data[1] |= AAUX_REC_MODE_INVALID_MASK; // Cause DV to mute this.
  1521. else
  1522. pDifSeq->AV[j].A.Pack.Data[1] = \
  1523. (pDifSeq->AV[j].A.Pack.Data[1] & ~AAUX_REC_MODE_INVALID_MASK) | AAUX_REC_MODE_ORIGINAL;
  1524. bFound2 = TRUE;
  1525. break; // Set only the 1st occurrence
  1526. }
  1527. }
  1528. // Must do the 1st occurance of all Dif sequences;
  1529. pDifSeq++; // Next DIF sequence
  1530. }
  1531. #if 0
  1532. return (bFound1 && bFound2);
  1533. #else
  1534. return bFound2;
  1535. #endif
  1536. }
  1537. #endif
  1538. #ifdef MSDV_SUPPORT_EXTRACT_SUBCODE_DATA
  1539. VOID
  1540. DVCRExtractTimecodeFromFrame(
  1541. IN PDVCR_EXTENSION pDevExt,
  1542. IN PSTREAMEX pStrmExt,
  1543. IN PUCHAR pFrameBuffer
  1544. )
  1545. {
  1546. PUCHAR pDIFBlk;
  1547. PUCHAR pS0, pS1, pSID0;
  1548. ULONG i, j;
  1549. BYTE LastTimecode[4], Timecode[4]; // hh:mm:ss,ff
  1550. DWORD LastAbsTrackNumber, AbsTrackNumber;
  1551. PUCHAR pSID1;
  1552. BYTE Timecode2[4]; // hh:mm:ss,ff
  1553. DWORD AbsTrackNumber2;
  1554. BOOL bGetAbsT = TRUE, bGetTimecode = TRUE;
  1555. // Can be called at DISPATCH_LEVEL
  1556. pDIFBlk = (PUCHAR) pFrameBuffer;
  1557. // Save the last timecode so we will now if it has
  1558. LastTimecode[0] = pStrmExt->Timecode[0];
  1559. LastTimecode[1] = pStrmExt->Timecode[1];
  1560. LastTimecode[2] = pStrmExt->Timecode[2];
  1561. LastTimecode[3] = pStrmExt->Timecode[3];
  1562. LastAbsTrackNumber = pStrmExt->AbsTrackNumber;
  1563. //
  1564. // Traverse thru every DIF BLOCK looking for VA0,1 and 2
  1565. for(i=0; i < AVCStrmFormatInfoTable[pDevExt->VideoFormatIndex].ulNumOfDIFSequences; i++) {
  1566. pS0 = pDIFBlk + 80;
  1567. pS1 = pS0 + 80;
  1568. //
  1569. // Is this Subcode source packet? See Table 36 (P.111) of the Blue Book
  1570. //
  1571. if ((pS0[0] & 0xe0) == 0x20 && (pS1[0] & 0xe0) == 0x20) {
  1572. if(bGetAbsT) {
  1573. //
  1574. // See Figure 42 (p. 94) of the Blue book
  1575. // SID0(Low nibble),1 (high nibble) of every three subcode sync block can form the ATN
  1576. //
  1577. pSID0 = &pS0[3];
  1578. AbsTrackNumber = 0;
  1579. for (j = 0 ; j < 3; j++) {
  1580. AbsTrackNumber = (( ( (pSID0[0] & 0x0f) << 4) | (pSID0[1] >> 4) ) << (j * 8)) | AbsTrackNumber;
  1581. pSID0 += 8;
  1582. bGetAbsT = FALSE;
  1583. }
  1584. pSID1 = &pS1[3];
  1585. AbsTrackNumber2 = 0;
  1586. for (j = 0 ; j < 3; j++) {
  1587. AbsTrackNumber2 = (( ( (pSID1[0] & 0x0f) << 4) | (pSID1[1] >> 4) ) << (j * 8)) | AbsTrackNumber2;
  1588. pSID1 += 8;
  1589. }
  1590. // Verify that the track number is the same!
  1591. if(AbsTrackNumber == AbsTrackNumber2) {
  1592. bGetAbsT = FALSE;
  1593. } else {
  1594. bGetAbsT = TRUE;
  1595. TRACE(TL_CIP_TRACE,("%d Sequence; AbsT (%d,%d) != AbsT2 (%d,%d)\n",
  1596. i,
  1597. AbsTrackNumber / 2, AbsTrackNumber & 0x01,
  1598. AbsTrackNumber2 / 2, AbsTrackNumber2 & 0x01
  1599. ));
  1600. }
  1601. }
  1602. if(bGetTimecode) {
  1603. // See Figure 68 (p. 114) of the Blue Book
  1604. // Subcode sync block number 3, 4 and 5
  1605. for(j = 3; j <= 5; j++) {
  1606. // 3 bytes of IDs and follow by sequence of 8 bytes SyncBlock (3:5);
  1607. // 0x13 == TIMECODE
  1608. if(pS0[3+3+j*8] == 0x13
  1609. && pS0[3+3+j*8+4] != 0xff
  1610. && pS0[3+3+j*8+3] != 0xff
  1611. && pS0[3+3+j*8+2] != 0xff
  1612. && pS0[3+3+j*8+1] != 0xff) {
  1613. Timecode[0] = pS0[3+3+j*8+4]&0x3f; // hh
  1614. Timecode[1] = pS0[3+3+j*8+3]&0x7f; // mm
  1615. Timecode[2] = pS0[3+3+j*8+2]&0x7f; // ss
  1616. Timecode[3] = pS0[3+3+j*8+1]&0x3f; // ff
  1617. bGetTimecode = FALSE;
  1618. break;
  1619. }
  1620. }
  1621. // Subcode sync block number 9, 10 and 11
  1622. for(j = 3; j <= 5; j++) {
  1623. // 3 bytes of IDs and follow by sequence of 8 bytes SyncBlock (3:5);
  1624. // 0x13 == TIMECODE
  1625. if(pS1[3+3+j*8] == 0x13
  1626. && pS1[3+3+j*8+4] != 0xff
  1627. && pS1[3+3+j*8+3] != 0xff
  1628. && pS1[3+3+j*8+2] != 0xff
  1629. && pS1[3+3+j*8+1] != 0xff) {
  1630. Timecode2[0] = pS1[3+3+j*8+4]&0x3f; // hh
  1631. Timecode2[1] = pS1[3+3+j*8+3]&0x7f; // mm
  1632. Timecode2[2] = pS1[3+3+j*8+2]&0x7f; // ss
  1633. Timecode2[3] = pS1[3+3+j*8+1]&0x3f; // ff
  1634. bGetTimecode = FALSE;
  1635. break;
  1636. }
  1637. }
  1638. //
  1639. // Verify
  1640. //
  1641. if(!bGetTimecode) {
  1642. if( Timecode[0] == Timecode2[0]
  1643. && Timecode[1] == Timecode2[1]
  1644. && Timecode[2] == Timecode2[2]
  1645. && Timecode[3] == Timecode2[3]) {
  1646. } else {
  1647. bGetTimecode = TRUE;
  1648. TRACE(TL_CIP_TRACE,("%d Sequence; %.2x:%.2x:%.2x,%.2x != %.2x:%.2x:%.2x,%.2x\n",
  1649. i,
  1650. Timecode[0], Timecode[1], Timecode[2], Timecode[3],
  1651. Timecode2[0], Timecode2[1], Timecode2[2], Timecode2[3]
  1652. ));
  1653. }
  1654. }
  1655. }
  1656. }
  1657. if(!bGetAbsT && !bGetTimecode)
  1658. break;
  1659. pDIFBlk += DIFBLK_SIZE; // Get to next block
  1660. }
  1661. if(!bGetAbsT && pStrmExt->AbsTrackNumber != AbsTrackNumber) {
  1662. pStrmExt->AbsTrackNumber = AbsTrackNumber; // BF is the LSB
  1663. pStrmExt->bATNUpdated = TRUE;
  1664. TRACE(TL_CIP_INFO,("Extracted TrackNum:%d; DicontBit:%d\n", AbsTrackNumber / 2, AbsTrackNumber & 0x01));
  1665. }
  1666. if(!bGetTimecode &&
  1667. (
  1668. Timecode[0] != LastTimecode[0] ||
  1669. Timecode[1] != LastTimecode[1] ||
  1670. Timecode[2] != LastTimecode[2] ||
  1671. Timecode[3] != LastTimecode[3]
  1672. )
  1673. ) {
  1674. pStrmExt->Timecode[0] = Timecode[0]; // hh
  1675. pStrmExt->Timecode[1] = Timecode[1]; // mm
  1676. pStrmExt->Timecode[2] = Timecode[2]; // mm
  1677. pStrmExt->Timecode[3] = Timecode[3]; // ff
  1678. pStrmExt->bTimecodeUpdated = TRUE;
  1679. TRACE(TL_CIP_INFO,("Extracted Timecode %.2x:%.2x:%.2x,%.2x\n", Timecode[0], Timecode[1], Timecode[2], Timecode[3]));
  1680. }
  1681. }
  1682. #endif // MSDV_SUPPORT_EXTRACT_SUBCODE_DATA
  1683. #ifdef MSDV_SUPPORT_EXTRACT_DV_DATE_TIME
  1684. VOID
  1685. DVCRExtractRecDateAndTimeFromFrame(
  1686. IN PDVCR_EXTENSION pDevExt,
  1687. IN PSTREAMEX pStrmExt,
  1688. IN PUCHAR pFrameBuffer
  1689. )
  1690. {
  1691. PUCHAR pDIFBlk;
  1692. PUCHAR pS0, pS1;
  1693. ULONG i, j;
  1694. BOOL bGetRecDate = TRUE, bGetRecTime = TRUE;
  1695. // Can be called at DISPATCH_LEVEL
  1696. pDIFBlk = (PUCHAR) pFrameBuffer + DIFBLK_SIZE * AVCStrmFormatInfoTable[pDevExt->VideoFormatIndex].ulNumOfDIFSequences/2;
  1697. //
  1698. // REC Data (VRD) and Time (VRT) on in the 2nd half oa a video frame
  1699. //
  1700. for(i=AVCStrmFormatInfoTable[pDevExt->VideoFormatIndex].ulNumOfDIFSequences/2; i < AVCStrmFormatInfoTable[pDevExt->VideoFormatIndex].ulNumOfDIFSequences; i++) {
  1701. pS0 = pDIFBlk + 80;
  1702. pS1 = pS0 + 80;
  1703. //
  1704. // Find SC0 and SC1. See Table 36 (P.111) of the Blue Book
  1705. //
  1706. // SC0/1: ID(0,1,2), Data (3,50), Reserved(51-79)
  1707. // SC0:Data: SSYB0(3..10), SSYB1(11..18), SSYB2(19..26), SSYB3(27..34), SSYB4(35..42), SSYB5(43..50)
  1708. // SC1:Data: SSYB6(3..10), SSYB7(11..18), SSYB8(19..26), SSYB9(27..34), SSYB10(35..42), SSYB11(43..50)
  1709. // SSYBx(SubCodeId0, SubcodeID1, Reserved, Pack(3,4,5,6,7))
  1710. //
  1711. // TTC are in the 1st half: SSYB0..11 (every)
  1712. // TTC are in the 2nd half: SSYB0,3,6,9
  1713. // VRD are in the 2nd half of a video frame, SSYB1,4,7,10
  1714. // VRT are in the 2nd half of a video frame, SSYB2,5,8,11
  1715. //
  1716. // Subcode data ?
  1717. if ((pS0[0] & 0xe0) == 0x20 && (pS1[0] & 0xe0) == 0x20) {
  1718. //
  1719. // RecDate: VRD
  1720. //
  1721. if(bGetRecDate) {
  1722. // go thru 6 sync blocks (8 bytes per block) per Subcode; idx 1(SSYB1),4(SSYB4) for SC0
  1723. for(j=0; j <= 5 ; j++) {
  1724. if(j == 1 || j == 4) {
  1725. // 0x62== RecDate
  1726. if(pS0[3+3+j*8] == 0x62) {
  1727. pStrmExt->RecDate[0] = pS0[3+3+j*8+4]; // Year
  1728. pStrmExt->RecDate[1] = pS0[3+3+j*8+3]&0x1f; // Month
  1729. pStrmExt->RecDate[2] = pS0[3+3+j*8+2]&0x3f; // Day
  1730. pStrmExt->RecDate[3] = pS0[3+3+j*8+1]&0x3f; // TimeZone
  1731. bGetRecDate = FALSE;
  1732. break;
  1733. }
  1734. }
  1735. }
  1736. }
  1737. if(bGetRecDate) {
  1738. // go thru 6 sync blocks (8 bytes per block) per Subcode; idx 1 (SSYB7),4(SSYB10) for SC1
  1739. for(j=0; j <= 5; j++) {
  1740. if(j == 1 || j == 4) {
  1741. // 0x62== RecDate
  1742. if(pS1[3+3+j*8] == 0x62) {
  1743. pStrmExt->RecDate[0] = pS1[3+3+j*8+4]; // Year
  1744. pStrmExt->RecDate[1] = pS1[3+3+j*8+3]&0x1f; // Month
  1745. pStrmExt->RecDate[2] = pS1[3+3+j*8+2]&0x3f; // Day
  1746. pStrmExt->RecDate[3] = pS1[3+3+j*8+1]&0x3f; // TimeZone
  1747. bGetRecDate = FALSE;
  1748. break;
  1749. }
  1750. }
  1751. }
  1752. }
  1753. //
  1754. // RecTime: VRT
  1755. //
  1756. if(bGetRecTime) {
  1757. // go thru 6 sync blocks (8 bytes per block) per Subcode; idx 2(SSYB2),5(SSYB5) for SC0
  1758. for(j=0; j <= 5 ; j++) {
  1759. if(j == 2 || j == 5) {
  1760. // 0x63== RecTime
  1761. if(pS0[3+3+j*8] == 0x63) {
  1762. pStrmExt->RecTime[0] = pS0[3+3+j*8+4]&0x3f;
  1763. pStrmExt->RecTime[1] = pS0[3+3+j*8+3]&0x7f;
  1764. pStrmExt->RecTime[2] = pS0[3+3+j*8+2]&0x7f;
  1765. pStrmExt->RecTime[3] = pS0[3+3+j*8+1]&0x3f;
  1766. bGetRecTime = FALSE;
  1767. break;
  1768. }
  1769. }
  1770. }
  1771. }
  1772. if(bGetRecTime) {
  1773. // go thru 6 sync blocks (8 bytes per block) per Subcode; idx 2 (SSYB8),5(SSYB11) for SC1
  1774. for(j=0; j <= 5; j++) {
  1775. if(j == 2 || j == 5) {
  1776. // 0x63== RecTime
  1777. if(pS1[3+3+j*8] == 0x63) {
  1778. pStrmExt->RecTime[0] = pS1[3+3+j*8+4]&0x3f;
  1779. pStrmExt->RecTime[1] = pS1[3+3+j*8+3]&0x7f;
  1780. pStrmExt->RecTime[2] = pS1[3+3+j*8+2]&0x7f;
  1781. pStrmExt->RecTime[3] = pS1[3+3+j*8+1]&0x3f;
  1782. bGetRecTime = FALSE;
  1783. break;
  1784. }
  1785. }
  1786. }
  1787. }
  1788. }
  1789. if(!bGetRecDate && !bGetRecTime)
  1790. break;
  1791. pDIFBlk += DIFBLK_SIZE; // Next sequence
  1792. }
  1793. TRACE(TL_PNP_TRACE,("Frame# %.5d, Date %s %x-%.2x-%.2x, Time %s %.2x:%.2x:%.2x,%.2x\n",
  1794. (ULONG) pStrmExt->FramesProcessed,
  1795. bGetRecDate ? "NF:" : "Found:", pStrmExt->RecDate[0], pStrmExt->RecDate[1] & 0x1f, pStrmExt->RecDate[2] & 0x3f,
  1796. bGetRecTime ? "NF:" : "Found:",pStrmExt->RecTime[0], pStrmExt->RecTime[1], pStrmExt->RecTime[2], pStrmExt->RecTime[3]
  1797. ));
  1798. }
  1799. #endif // MSDV_SUPPORT_EXTRACT_DV_DATE_TIME
  1800. #ifdef READ_CUTOMIZE_REG_VALUES
  1801. NTSTATUS
  1802. CreateRegistryKeySingle(
  1803. IN HANDLE hKey,
  1804. IN ACCESS_MASK desiredAccess,
  1805. PWCHAR pwszSection,
  1806. OUT PHANDLE phKeySection
  1807. )
  1808. {
  1809. NTSTATUS status;
  1810. UNICODE_STRING ustr;
  1811. OBJECT_ATTRIBUTES objectAttributes;
  1812. RtlInitUnicodeString(&ustr, pwszSection);
  1813. InitializeObjectAttributes(
  1814. &objectAttributes,
  1815. &ustr,
  1816. OBJ_CASE_INSENSITIVE,
  1817. hKey,
  1818. NULL
  1819. );
  1820. status =
  1821. ZwCreateKey(
  1822. phKeySection,
  1823. desiredAccess,
  1824. &objectAttributes,
  1825. 0,
  1826. NULL, /* optional*/
  1827. REG_OPTION_NON_VOLATILE,
  1828. NULL
  1829. );
  1830. return status;
  1831. }
  1832. NTSTATUS
  1833. CreateRegistrySubKey(
  1834. IN HANDLE hKey,
  1835. IN ACCESS_MASK desiredAccess,
  1836. PWCHAR pwszSection,
  1837. OUT PHANDLE phKeySection
  1838. )
  1839. {
  1840. UNICODE_STRING ustr;
  1841. USHORT usPos = 1; // Skip first backslash
  1842. static WCHAR wSep = '\\';
  1843. NTSTATUS status = STATUS_SUCCESS;
  1844. RtlInitUnicodeString(&ustr, pwszSection);
  1845. while(usPos < ustr.Length) {
  1846. if(ustr.Buffer[usPos] == wSep) {
  1847. // NULL terminate our partial string
  1848. ustr.Buffer[usPos] = UNICODE_NULL;
  1849. status =
  1850. CreateRegistryKeySingle(
  1851. hKey,
  1852. desiredAccess,
  1853. ustr.Buffer,
  1854. phKeySection
  1855. );
  1856. ustr.Buffer[usPos] = wSep;
  1857. if(NT_SUCCESS(status)) {
  1858. ZwClose(*phKeySection);
  1859. } else {
  1860. break;
  1861. }
  1862. }
  1863. usPos++;
  1864. }
  1865. // Create the full key
  1866. if(NT_SUCCESS(status)) {
  1867. status =
  1868. CreateRegistryKeySingle(
  1869. hKey,
  1870. desiredAccess,
  1871. ustr.Buffer,
  1872. phKeySection
  1873. );
  1874. }
  1875. return status;
  1876. }
  1877. NTSTATUS
  1878. GetRegistryKeyValue (
  1879. IN HANDLE Handle,
  1880. IN PWCHAR KeyNameString,
  1881. IN ULONG KeyNameStringLength,
  1882. IN PVOID Data,
  1883. IN PULONG DataLength
  1884. )
  1885. /*++
  1886. Routine Description:
  1887. This routine gets the specified value out of the registry
  1888. Arguments:
  1889. Handle - Handle to location in registry
  1890. KeyNameString - registry key we're looking for
  1891. KeyNameStringLength - length of registry key we're looking for
  1892. Data - where to return the data
  1893. DataLength - how big the data is
  1894. Return Value:
  1895. status is returned from ZwQueryValueKey
  1896. --*/
  1897. {
  1898. NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
  1899. UNICODE_STRING keyName;
  1900. ULONG length;
  1901. PKEY_VALUE_FULL_INFORMATION fullInfo;
  1902. RtlInitUnicodeString(&keyName, KeyNameString);
  1903. length = sizeof(KEY_VALUE_FULL_INFORMATION) +
  1904. KeyNameStringLength + *DataLength;
  1905. fullInfo = ExAllocatePool(PagedPool, length);
  1906. if (fullInfo) {
  1907. status = ZwQueryValueKey(
  1908. Handle,
  1909. &keyName,
  1910. KeyValueFullInformation,
  1911. fullInfo,
  1912. length,
  1913. &length
  1914. );
  1915. if (NT_SUCCESS(status)){
  1916. ASSERT(fullInfo->DataLength <= *DataLength);
  1917. RtlCopyMemory(
  1918. Data,
  1919. ((PUCHAR) fullInfo) + fullInfo->DataOffset,
  1920. fullInfo->DataLength
  1921. );
  1922. }
  1923. *DataLength = fullInfo->DataLength;
  1924. ExFreePool(fullInfo);
  1925. }
  1926. return (status);
  1927. }
  1928. NTSTATUS
  1929. SetRegistryKeyValue(
  1930. HANDLE hKey,
  1931. PWCHAR pwszEntry,
  1932. LONG nValue
  1933. )
  1934. {
  1935. NTSTATUS status;
  1936. UNICODE_STRING ustr;
  1937. RtlInitUnicodeString(&ustr, pwszEntry);
  1938. status =
  1939. ZwSetValueKey(
  1940. hKey,
  1941. &ustr,
  1942. 0, /* optional */
  1943. REG_DWORD,
  1944. &nValue,
  1945. sizeof(nValue)
  1946. );
  1947. return status;
  1948. }
  1949. //
  1950. // Registry subky and values wide character strings.
  1951. //
  1952. WCHAR wszSettings[] = L"Settings";
  1953. WCHAR wszATNSearch[] = L"bSupportATNSearch";
  1954. WCHAR wszSyncRecording[] = L"bSyncRecording";
  1955. WCHAR wszMaxDataSync[] = L"tmMaxDataSync";
  1956. WCHAR wszPlayPs2RecPs[] = L"fmPlayPause2RecPause";
  1957. WCHAR wszStop2RecPs[] = L"fmStop2RecPause";
  1958. WCHAR wszRecPs2Rec[] = L"tmRecPause2Rec";
  1959. BOOL
  1960. DVGetPropertyValuesFromRegistry(
  1961. IN PDVCR_EXTENSION pDevExt
  1962. )
  1963. {
  1964. NTSTATUS Status;
  1965. HANDLE hPDOKey, hKeySettings;
  1966. ULONG ulLength;
  1967. //
  1968. // Registry key:
  1969. // Windows 2000:
  1970. // HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\
  1971. // {6BDD1FC6-810F-11D0-BEC7-08002BE2092F\000x
  1972. //
  1973. // Win98:
  1974. // HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Class\Image\000x
  1975. //
  1976. Status =
  1977. IoOpenDeviceRegistryKey(
  1978. pDevExt->pPhysicalDeviceObject,
  1979. PLUGPLAY_REGKEY_DRIVER,
  1980. STANDARD_RIGHTS_READ,
  1981. &hPDOKey
  1982. );
  1983. // PDO might be deleted when it was removed.
  1984. if(! pDevExt->bDevRemoved) {
  1985. ASSERT(Status == STATUS_SUCCESS);
  1986. }
  1987. //
  1988. // loop through our table of strings,
  1989. // reading the registry for each.
  1990. //
  1991. if(NT_SUCCESS(Status)) {
  1992. // Create or open the settings key
  1993. Status =
  1994. CreateRegistrySubKey(
  1995. hPDOKey,
  1996. KEY_ALL_ACCESS,
  1997. wszSettings,
  1998. &hKeySettings
  1999. );
  2000. if(NT_SUCCESS(Status)) {
  2001. // Note: we can be more selective by checking
  2002. // pDevExt->ulDevType
  2003. // ATNSearch
  2004. ulLength = sizeof(LONG);
  2005. Status = GetRegistryKeyValue(
  2006. hKeySettings,
  2007. wszATNSearch,
  2008. sizeof(wszATNSearch),
  2009. (PVOID) &pDevExt->bATNSearch,
  2010. &ulLength);
  2011. TRACE(TL_PNP_TRACE,("GetRegVal: St:%x, Len:%d, bATNSearch:%d (1:Yes)\n", Status, ulLength, pDevExt->bATNSearch));
  2012. if(!NT_SUCCESS(Status)) pDevExt->bATNSearch = FALSE;
  2013. // bSyncRecording
  2014. ulLength = sizeof(LONG);
  2015. Status = GetRegistryKeyValue(
  2016. hKeySettings,
  2017. wszSyncRecording,
  2018. sizeof(wszSyncRecording),
  2019. (PVOID) &pDevExt->bSyncRecording,
  2020. &ulLength);
  2021. TRACE(TL_PNP_TRACE,("GetRegVal: St:%x, Len:%d, bSyncRecording:%d (1:Yes)\n", Status, ulLength, pDevExt->bSyncRecording));
  2022. if(!NT_SUCCESS(Status)) pDevExt->bSyncRecording = FALSE;
  2023. // tmMaxDataSync
  2024. ulLength = sizeof(LONG);
  2025. Status = GetRegistryKeyValue(
  2026. hKeySettings,
  2027. wszMaxDataSync,
  2028. sizeof(wszMaxDataSync),
  2029. (PVOID) &pDevExt->tmMaxDataSync,
  2030. &ulLength);
  2031. TRACE(TL_PNP_TRACE,("GetRegVal: St:%x, Len:%d, tmMaxDataSync:%d (msec)\n", Status, ulLength, pDevExt->tmMaxDataSync));
  2032. // fmPlayPs2RecPs
  2033. ulLength = sizeof(LONG);
  2034. Status = GetRegistryKeyValue(
  2035. hKeySettings,
  2036. wszPlayPs2RecPs,
  2037. sizeof(wszPlayPs2RecPs),
  2038. (PVOID) &pDevExt->fmPlayPs2RecPs,
  2039. &ulLength);
  2040. TRACE(TL_PNP_TRACE,("GetRegVal: St:%x, Len:%d, fmPlayPs2RecPs:%d (frames)\n", Status, ulLength, pDevExt->fmPlayPs2RecPs));
  2041. // fmStop2RecPs
  2042. ulLength = sizeof(LONG);
  2043. Status = GetRegistryKeyValue(
  2044. hKeySettings,
  2045. wszStop2RecPs,
  2046. sizeof(wszStop2RecPs),
  2047. (PVOID) &pDevExt->fmStop2RecPs,
  2048. &ulLength);
  2049. TRACE(TL_PNP_TRACE,("GetRegVal: St:%x, Len:%d, fmStop2RecPs:%d (frames)\n", Status, ulLength, pDevExt->fmStop2RecPs));
  2050. // tmRecPs2Rec
  2051. ulLength = sizeof(LONG);
  2052. Status = GetRegistryKeyValue(
  2053. hKeySettings,
  2054. wszRecPs2Rec,
  2055. sizeof(wszRecPs2Rec),
  2056. (PVOID) &pDevExt->tmRecPs2Rec,
  2057. &ulLength);
  2058. TRACE(TL_PNP_TRACE,("GetRegVal: St:%x, Len:%d, tmRecPs2Rec:%d (msec)\n", Status, ulLength, pDevExt->tmRecPs2Rec));
  2059. ZwClose(hKeySettings);
  2060. ZwClose(hPDOKey);
  2061. return TRUE;
  2062. } else {
  2063. TRACE(TL_PNP_ERROR,("GetPropertyValuesFromRegistry: CreateRegistrySubKey failed with Status=%x\n", Status));
  2064. }
  2065. ZwClose(hPDOKey);
  2066. } else {
  2067. TRACE(TL_PNP_ERROR,("GetPropertyValuesFromRegistry: IoOpenDeviceRegistryKey failed with Status=%x\n", Status));
  2068. }
  2069. // Not implemented so always return FALSE to use the defaults.
  2070. return FALSE;
  2071. }
  2072. BOOL
  2073. DVSetPropertyValuesToRegistry(
  2074. PDVCR_EXTENSION pDevExt
  2075. )
  2076. {
  2077. // Set the default to :
  2078. // HLM\Software\DeviceExtension->pchVendorName\1394DCam
  2079. NTSTATUS Status;
  2080. HANDLE hPDOKey, hKeySettings;
  2081. TRACE(TL_PNP_TRACE,("SetPropertyValuesToRegistry: pDevExt=%x; pDevExt->pBusDeviceObject=%x\n", pDevExt, pDevExt->pBusDeviceObject));
  2082. //
  2083. // Registry key:
  2084. // HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\
  2085. // {6BDD1FC6-810F-11D0-BEC7-08002BE2092F\000x
  2086. //
  2087. Status =
  2088. IoOpenDeviceRegistryKey(
  2089. pDevExt->pPhysicalDeviceObject,
  2090. PLUGPLAY_REGKEY_DRIVER,
  2091. STANDARD_RIGHTS_WRITE,
  2092. &hPDOKey);
  2093. // PDO might be deleted when it was removed.
  2094. if(! pDevExt->bDevRemoved) {
  2095. ASSERT(Status == STATUS_SUCCESS);
  2096. }
  2097. //
  2098. // loop through our table of strings,
  2099. // reading the registry for each.
  2100. //
  2101. if(NT_SUCCESS(Status)) {
  2102. // Create or open the settings key
  2103. Status =
  2104. CreateRegistrySubKey(
  2105. hPDOKey,
  2106. KEY_ALL_ACCESS,
  2107. wszSettings,
  2108. &hKeySettings
  2109. );
  2110. if(NT_SUCCESS(Status)) {
  2111. #if 0 // Note used, just an example:
  2112. // Brightness
  2113. Status = SetRegistryKeyValue(
  2114. hKeySettings,
  2115. wszBrightness,
  2116. pDevExt->XXXX);
  2117. TRACE(TL_PNP_TRACE,("SetPropertyValuesToRegistry: Status %x, Brightness %d\n", Status, pDevExt->Brightness));
  2118. #endif
  2119. ZwClose(hKeySettings);
  2120. ZwClose(hPDOKey);
  2121. return TRUE;
  2122. } else {
  2123. TRACE(TL_PNP_ERROR,("GetPropertyValuesToRegistry: CreateRegistrySubKey failed with Status=%x\n", Status));
  2124. }
  2125. ZwClose(hPDOKey);
  2126. } else {
  2127. TRACE(TL_PNP_TRACE,("GetPropertyValuesToRegistry: IoOpenDeviceRegistryKey failed with Status=%x\n", Status));
  2128. }
  2129. return FALSE;
  2130. }
  2131. #endif // READ_CUTOMIZE_REG_VALUES
  2132. #ifdef SUPPORT_ACCESS_DEVICE_INTERFACE
  2133. #if DBG
  2134. NTSTATUS
  2135. DVGetRegistryValue(
  2136. IN HANDLE Handle,
  2137. IN PWCHAR KeyNameString,
  2138. IN ULONG KeyNameStringLength,
  2139. IN PVOID Data,
  2140. IN ULONG DataLength
  2141. )
  2142. /*++
  2143. Routine Description:
  2144. Reads the specified registry value
  2145. Arguments:
  2146. Handle - handle to the registry key
  2147. KeyNameString - value to read
  2148. KeyNameStringLength - length of string
  2149. Data - buffer to read data into
  2150. DataLength - length of data buffer
  2151. Return Value:
  2152. NTSTATUS returned as appropriate
  2153. --*/
  2154. {
  2155. NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES;
  2156. UNICODE_STRING KeyName;
  2157. ULONG Length;
  2158. PKEY_VALUE_FULL_INFORMATION FullInfo;
  2159. PAGED_CODE();
  2160. RtlInitUnicodeString(&KeyName, KeyNameString);
  2161. Length = sizeof(KEY_VALUE_FULL_INFORMATION) +
  2162. KeyNameStringLength + DataLength;
  2163. FullInfo = ExAllocatePool(PagedPool, Length);
  2164. if (FullInfo) {
  2165. Status = ZwQueryValueKey(Handle,
  2166. &KeyName,
  2167. KeyValueFullInformation,
  2168. FullInfo,
  2169. Length,
  2170. &Length);
  2171. if (NT_SUCCESS(Status)) {
  2172. if (DataLength >= FullInfo->DataLength) {
  2173. RtlCopyMemory(Data, ((PUCHAR) FullInfo) + FullInfo->DataOffset, FullInfo->DataLength);
  2174. } else {
  2175. Status = STATUS_BUFFER_TOO_SMALL;
  2176. } // buffer right length
  2177. } // if success
  2178. else {
  2179. TRACE(TL_PNP_ERROR,("ReadRegValue failed; ST:%x\n", Status));
  2180. }
  2181. ExFreePool(FullInfo);
  2182. } // if fullinfo
  2183. return Status;
  2184. }
  2185. #endif
  2186. #ifdef NT51_61883
  2187. static const WCHAR DeviceTypeName[] = L"GLOBAL";
  2188. #endif
  2189. static const WCHAR UniqueID_Low[] = L"UniqueID_Low";
  2190. static const WCHAR UniqueID_High[] = L"UniqueID_High";
  2191. static const WCHAR VendorID[] = L"VendorID";
  2192. static const WCHAR ModelID[] = L"ModelID";
  2193. static const WCHAR VendorText[] = L"VendorText";
  2194. static const WCHAR ModelText[] = L"ModelText";
  2195. static const WCHAR UnitModelText[] = L"UnitModelText";
  2196. static const WCHAR DeviceOPcr0Payload[] = L"DeviceOPcr0Payload";
  2197. static const WCHAR DeviceOPcr0DataRate[] = L"DeviceOPcr0DataRate";
  2198. #if DBG
  2199. static const WCHAR FriendlyName[] = L"FriendlyName";
  2200. #endif
  2201. BOOL
  2202. DVAccessDeviceInterface(
  2203. IN PDVCR_EXTENSION pDevExt,
  2204. IN const ULONG ulNumCategories,
  2205. IN GUID DVCategories[]
  2206. )
  2207. /*++
  2208. Routine Description:
  2209. Access to the device's interface section and update the VendorText,
  2210. ModelText and UnitModelText.
  2211. --*/
  2212. {
  2213. NTSTATUS ntStatus = STATUS_SUCCESS;
  2214. HANDLE hDevIntfKey;
  2215. UNICODE_STRING *aSymbolicLinkNames,
  2216. #ifdef NT51_61883
  2217. RefString,
  2218. #endif
  2219. TempUnicodeString;
  2220. ULONG i;
  2221. #ifdef NT51_61883
  2222. #if DBG
  2223. WCHAR DataBuffer[MAX_PATH];
  2224. #endif
  2225. #endif
  2226. //
  2227. // allocate space for the array of catagory names
  2228. //
  2229. if (!(aSymbolicLinkNames = ExAllocatePool(PagedPool,
  2230. sizeof(UNICODE_STRING) * ulNumCategories))) {
  2231. return FALSE;
  2232. }
  2233. //
  2234. // zero the array in case we're unable to fill it in below. the Destroy
  2235. // routine below will then correctly handle this case.
  2236. //
  2237. RtlZeroMemory(aSymbolicLinkNames, sizeof(UNICODE_STRING) * ulNumCategories);
  2238. #ifdef NT51_61883
  2239. //
  2240. // loop through each of the catagory GUID's for each of the pins,
  2241. // creating a symbolic link for each one.
  2242. //
  2243. RtlInitUnicodeString(&RefString, DeviceTypeName);
  2244. #endif
  2245. for (i = 0; i < ulNumCategories; i++) {
  2246. // Register our Device Interface
  2247. ntStatus = IoRegisterDeviceInterface(
  2248. pDevExt->pPhysicalDeviceObject,
  2249. &DVCategories[i],
  2250. #ifdef NT51_61883
  2251. &RefString,
  2252. #else
  2253. NULL,
  2254. #endif
  2255. &aSymbolicLinkNames[i]
  2256. );
  2257. if(!NT_SUCCESS(ntStatus)) {
  2258. //
  2259. // Can't register device interface
  2260. //
  2261. TRACE(TL_PNP_WARNING,("Cannot register device interface! ST:%x\n", ntStatus));
  2262. goto Exit;
  2263. }
  2264. TRACE(TL_PNP_TRACE,("AccessDeviceInterface:%d) Cateogory (Len:%d; MaxLen:%d); Name:\n%S\n", i,
  2265. aSymbolicLinkNames[i].Length, aSymbolicLinkNames[i].MaximumLength, aSymbolicLinkNames[i].Buffer));
  2266. //
  2267. // Get deice interface
  2268. //
  2269. hDevIntfKey = 0;
  2270. ntStatus = IoOpenDeviceInterfaceRegistryKey(&aSymbolicLinkNames[i],
  2271. STANDARD_RIGHTS_ALL,
  2272. &hDevIntfKey);
  2273. if (NT_SUCCESS(ntStatus)) {
  2274. #ifdef NT51_61883
  2275. #if DBG
  2276. // Get DeviceInstance
  2277. ntStatus = DVGetRegistryValue(hDevIntfKey,
  2278. (PWCHAR) FriendlyName,
  2279. sizeof(FriendlyName),
  2280. &DataBuffer,
  2281. MAX_PATH);
  2282. if(NT_SUCCESS(ntStatus)) {
  2283. TRACE(TL_PNP_TRACE,("AccessDeviceInterface:%S:%S\n", FriendlyName, DataBuffer));
  2284. } else {
  2285. TRACE(TL_PNP_WARNING,("Get %S failed; ST:%x\n", FriendlyName, ntStatus));
  2286. }
  2287. #endif
  2288. #endif
  2289. //
  2290. // Update ConfigROM info read from an AV/C device:
  2291. // UniqueID, VendorID, ModelID,
  2292. // VendorText, ModelText and UnitModelText
  2293. //
  2294. if(pDevExt->UniqueID.LowPart || pDevExt->UniqueID.HighPart) {
  2295. RtlInitUnicodeString(&TempUnicodeString, UniqueID_High);
  2296. ZwSetValueKey(hDevIntfKey,
  2297. &TempUnicodeString,
  2298. 0,
  2299. REG_DWORD,
  2300. &pDevExt->UniqueID.HighPart,
  2301. sizeof(pDevExt->UniqueID.HighPart));
  2302. RtlInitUnicodeString(&TempUnicodeString, UniqueID_Low);
  2303. ZwSetValueKey(hDevIntfKey,
  2304. &TempUnicodeString,
  2305. 0,
  2306. REG_DWORD,
  2307. &pDevExt->UniqueID.LowPart,
  2308. sizeof(pDevExt->UniqueID.LowPart));
  2309. TRACE(TL_PNP_TRACE,("Reg: %S = (Low)%x:(High)%x\n", TempUnicodeString.Buffer, pDevExt->UniqueID.LowPart, pDevExt->UniqueID.HighPart));
  2310. }
  2311. if(pDevExt->ulVendorID) {
  2312. RtlInitUnicodeString(&TempUnicodeString, VendorID);
  2313. ZwSetValueKey(hDevIntfKey,
  2314. &TempUnicodeString,
  2315. 0,
  2316. REG_DWORD,
  2317. &pDevExt->ulVendorID,
  2318. sizeof(pDevExt->ulVendorID));
  2319. TRACE(TL_PNP_TRACE,("Reg: %S = %x\n", TempUnicodeString.Buffer, pDevExt->ulVendorID));
  2320. }
  2321. if(pDevExt->ulModelID) {
  2322. RtlInitUnicodeString(&TempUnicodeString, ModelID);
  2323. ZwSetValueKey(hDevIntfKey,
  2324. &TempUnicodeString,
  2325. 0,
  2326. REG_DWORD,
  2327. &pDevExt->ulModelID,
  2328. sizeof(pDevExt->ulModelID));
  2329. TRACE(TL_PNP_TRACE,("Reg: %S = %x\n", TempUnicodeString.Buffer, pDevExt->ulModelID));
  2330. }
  2331. if(pDevExt->UnitIDs.ulVendorLength && pDevExt->UnitIDs.VendorText) {
  2332. RtlInitUnicodeString(&TempUnicodeString, VendorText);
  2333. ZwSetValueKey(hDevIntfKey,
  2334. &TempUnicodeString,
  2335. 0,
  2336. REG_SZ,
  2337. pDevExt->UnitIDs.VendorText,
  2338. pDevExt->UnitIDs.ulVendorLength);
  2339. TRACE(TL_PNP_TRACE,("Reg: %S = %S\n", TempUnicodeString.Buffer, pDevExt->UnitIDs.VendorText));
  2340. }
  2341. #ifdef NT51_61883
  2342. if(pDevExt->UnitIDs.ulModelLength && pDevExt->UnitIDs.ModelText) {
  2343. RtlInitUnicodeString(&TempUnicodeString, ModelText);
  2344. ZwSetValueKey(hDevIntfKey,
  2345. &TempUnicodeString,
  2346. 0,
  2347. REG_SZ,
  2348. pDevExt->UnitIDs.ModelText,
  2349. pDevExt->UnitIDs.ulModelLength);
  2350. TRACE(TL_PNP_WARNING,("Reg: %S = %S\n", TempUnicodeString.Buffer, pDevExt->UnitIDs.ModelText));
  2351. }
  2352. #else
  2353. if(pDevExt->UniRootModelString.Length && pDevExt->UniRootModelString.Buffer) {
  2354. RtlInitUnicodeString(&TempUnicodeString, ModelText);
  2355. ZwSetValueKey(hDevIntfKey,
  2356. &TempUnicodeString,
  2357. 0,
  2358. REG_SZ,
  2359. pDevExt->UniRootModelString.Buffer,
  2360. pDevExt->UniRootModelString.Length);
  2361. TRACE(TL_PNP_WARNING,("Reg: %S = %S\n", TempUnicodeString.Buffer, pDevExt->UniRootModelString.Buffer));
  2362. }
  2363. #endif
  2364. #ifdef NT51_61883
  2365. if(pDevExt->UnitIDs.ulUnitModelLength && pDevExt->UnitIDs.UnitModelText) {
  2366. RtlInitUnicodeString(&TempUnicodeString, UnitModelText);
  2367. ZwSetValueKey(hDevIntfKey,
  2368. &TempUnicodeString,
  2369. 0,
  2370. REG_SZ,
  2371. pDevExt->UnitIDs.UnitModelText,
  2372. pDevExt->UnitIDs.ulUnitModelLength);
  2373. TRACE(TL_PNP_WARNING,("Reg: %S = %S\n", TempUnicodeString.Buffer, pDevExt->UnitIDs.UnitModelText));
  2374. }
  2375. #else
  2376. if(pDevExt->UniUnitModelString.Length && pDevExt->UniUnitModelString.Buffer) {
  2377. RtlInitUnicodeString(&TempUnicodeString, UnitModelText);
  2378. ZwSetValueKey(hDevIntfKey,
  2379. &TempUnicodeString,
  2380. 0,
  2381. REG_SZ,
  2382. pDevExt->UniUnitModelString.Buffer,
  2383. pDevExt->UniUnitModelString.Length);
  2384. TRACE(TL_PNP_WARNING,("Reg: %S = %S\n", TempUnicodeString.Buffer, pDevExt->UniUnitModelString.Buffer));
  2385. }
  2386. #endif
  2387. //
  2388. // Cache cache device's payload field of the oPCR[0];
  2389. // The valid range is 0 to 1023 where 0 is 1024.
  2390. // This value is needed for an application figure out
  2391. // max data rate. However, if this payload is
  2392. // dynamically changing, it will not be accurate.
  2393. //
  2394. if(pDevExt->pDevOutPlugs->NumPlugs) {
  2395. //
  2396. // 98 and 146 are two known valid payloads
  2397. //
  2398. ASSERT(pDevExt->pDevOutPlugs->DevPlug[0].PlugState.Payload <= MAX_PAYLOAD-1); // 0..MAX_PAYLOAD-1 is the valid range; "0" is MAX_PAYLOAD (1024) quadlets.
  2399. RtlInitUnicodeString(&TempUnicodeString, DeviceOPcr0Payload);
  2400. ZwSetValueKey(hDevIntfKey,
  2401. &TempUnicodeString,
  2402. 0,
  2403. REG_DWORD,
  2404. &pDevExt->pDevOutPlugs->DevPlug[0].PlugState.Payload,
  2405. sizeof(pDevExt->pDevOutPlugs->DevPlug[0].PlugState.Payload));
  2406. TRACE(TL_PNP_TRACE,("Reg: %S = %d quadlets\n", TempUnicodeString.Buffer, pDevExt->pDevOutPlugs->DevPlug[0].PlugState.Payload));
  2407. //
  2408. // 0 (S100), 1(S200) and 2(S400) are the only three valid data rates.
  2409. //
  2410. ASSERT(pDevExt->pDevOutPlugs->DevPlug[0].PlugState.DataRate <= CMP_SPEED_S400);
  2411. RtlInitUnicodeString(&TempUnicodeString, DeviceOPcr0DataRate);
  2412. ZwSetValueKey(hDevIntfKey,
  2413. &TempUnicodeString,
  2414. 0,
  2415. REG_DWORD,
  2416. &pDevExt->pDevOutPlugs->DevPlug[0].PlugState.DataRate,
  2417. sizeof(pDevExt->pDevOutPlugs->DevPlug[0].PlugState.DataRate));
  2418. TRACE(TL_PNP_TRACE,("Reg: %S = %d (0:S100,1:S200,2:S400)\n", TempUnicodeString.Buffer,
  2419. pDevExt->pDevOutPlugs->DevPlug[0].PlugState.DataRate));
  2420. }
  2421. ZwClose(hDevIntfKey);
  2422. } else {
  2423. TRACE(TL_PNP_ERROR,("IoOpenDeviceInterfaceRegistryKey failed; ST:%x\n", ntStatus));
  2424. }
  2425. RtlFreeUnicodeString(&aSymbolicLinkNames[i]);
  2426. }
  2427. Exit:
  2428. ExFreePool(aSymbolicLinkNames); aSymbolicLinkNames = NULL;
  2429. return ntStatus == STATUS_SUCCESS;
  2430. }
  2431. #endif