Source code of Windows XP (NT5)
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.

866 lines
26 KiB

  1. //===========================================================================
  2. //
  3. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  4. // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  5. // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  6. // PURPOSE.
  7. //
  8. // Copyright (c) 1996 - 2000 Microsoft Corporation. All Rights Reserved.
  9. //
  10. //===========================================================================
  11. /*++
  12. Module Name:
  13. sonydcam.c
  14. Abstract:
  15. Stream class based WDM driver for 1934 Desktop Camera.
  16. This driver fits under the WDM stream class.
  17. Author:
  18. Shaun Pierce 25-May-96
  19. Modified:
  20. Yee J. Wu 15-Oct-97
  21. Environment:
  22. Kernel mode only
  23. Revision History:
  24. --*/
  25. #include "strmini.h"
  26. #include "1394.h"
  27. #include "dbg.h"
  28. #include "ksmedia.h"
  29. #include "dcamdef.h"
  30. #include "sonydcam.h"
  31. #include "dcampkt.h"
  32. #include "capprop.h" // Video and camera property function prototype
  33. CHAR szUnknownVendorName[] = "UnknownVendor";
  34. #ifdef ALLOC_PRAGMA
  35. // #pragma alloc_text(INIT, DriverEntry)
  36. #pragma alloc_text(PAGE, DCamHwUnInitialize)
  37. #pragma alloc_text(PAGE, InitializeDeviceExtension)
  38. #pragma alloc_text(PAGE, DCamHwInitialize)
  39. #endif
  40. NTSTATUS
  41. DriverEntry(
  42. IN PDRIVER_OBJECT DriverObject,
  43. IN PUNICODE_STRING RegistryPath
  44. )
  45. /*++
  46. Routine Description:
  47. This where life begins for a driver. The stream class takes care
  48. of alot of stuff for us, but we still need to fill in an initialization
  49. structure for the stream class and call it.
  50. Arguments:
  51. DriverObject - Pointer to the driver object created by the system.
  52. RegistryPath - unused.
  53. Return Value:
  54. The function value is the final status from the initialization operation.
  55. --*/
  56. {
  57. HW_INITIALIZATION_DATA HwInitData;
  58. PAGED_CODE();
  59. DbgMsg1(("SonyDCam DriverEntry: DriverObject=%x; RegistryPath=%x\n",
  60. DriverObject, RegistryPath));
  61. ERROR_LOG(("<<<<<<< Sonydcam.sys: %s; %s; %x %x >>>>>>>>\n",
  62. __DATE__, __TIME__, DriverObject, RegistryPath));
  63. //
  64. // Fill in the HwInitData structure
  65. //
  66. RtlZeroMemory( &HwInitData, sizeof(HW_INITIALIZATION_DATA) );
  67. HwInitData.HwInitializationDataSize = sizeof(HwInitData);
  68. HwInitData.HwInterrupt = NULL;
  69. HwInitData.HwReceivePacket = DCamReceivePacket;
  70. HwInitData.HwCancelPacket = DCamCancelOnePacket;
  71. HwInitData.HwRequestTimeoutHandler = DCamTimeoutHandler;
  72. HwInitData.DeviceExtensionSize = sizeof(DCAM_EXTENSION);
  73. HwInitData.PerStreamExtensionSize = sizeof(STREAMEX);
  74. HwInitData.PerRequestExtensionSize = sizeof(IRB);
  75. HwInitData.FilterInstanceExtensionSize = 0;
  76. HwInitData.BusMasterDMA = FALSE;
  77. HwInitData.Dma24BitAddresses = FALSE;
  78. HwInitData.BufferAlignment = sizeof(ULONG) - 1;
  79. HwInitData.TurnOffSynchronization = TRUE;
  80. HwInitData.DmaBufferSize = 0;
  81. return (StreamClassRegisterAdapter(DriverObject, RegistryPath, &HwInitData));
  82. }
  83. #define DEQUEUE_SETTLE_TIME (ULONG)(-1 * MAX_BUFFERS_SUPPLIED * 10000)
  84. NTSTATUS
  85. DCamHwUnInitialize(
  86. IN PHW_STREAM_REQUEST_BLOCK Srb
  87. )
  88. /*++
  89. Routine Description:
  90. Device is asked to be unloaded.
  91. Note: this can be called BEFORE CloseStream in the situation when a DCam
  92. is unplugged while streaming in any state (RUN,PAUSE or STOP). So if we
  93. are here and the stream is not yet close, we will stop, close stream and then
  94. free resource.
  95. Arguments:
  96. Srb - Pointer to stream request block
  97. Return Value:
  98. Nothing
  99. --*/
  100. {
  101. NTSTATUS Status;
  102. PIRP pIrp;
  103. PIRB pIrb;
  104. PDCAM_EXTENSION pDevExt = (PDCAM_EXTENSION) Srb->HwDeviceExtension;
  105. PAGED_CODE();
  106. ASSERT(pDevExt->PendingReadCount == 0);
  107. //
  108. // Host controller could be disabled which will cause us to be uninitialized.
  109. //
  110. if(DCamAllocateIrbAndIrp(&pIrb, &pIrp, pDevExt->BusDeviceObject->StackSize)) {
  111. //
  112. // un-register a bus reset callback notification
  113. //
  114. pIrb->FunctionNumber = REQUEST_BUS_RESET_NOTIFICATION;
  115. pIrb->Flags = 0;
  116. pIrb->u.BusResetNotification.fulFlags = DEREGISTER_NOTIFICATION_ROUTINE;
  117. pIrb->u.BusResetNotification.ResetRoutine = (PBUS_BUS_RESET_NOTIFICATION) DCamBusResetNotification;
  118. pIrb->u.BusResetNotification.ResetContext = 0;
  119. Status = DCamSubmitIrpSynch(pDevExt, pIrp, pIrb);
  120. if(Status) {
  121. ERROR_LOG(("DCamHwUnInitialize: Error (Status %x) while trying to deregister nus reset callback routine.\n", Status));
  122. }
  123. DbgMsg1(("DCamHwUnInitialize: DeRegister bus reset notification done; status %x.\n", Status));
  124. DCamFreeIrbIrpAndContext(0, pIrb, pIrp);
  125. } else {
  126. ERROR_LOG(("DCamBusResetNotification: DcamAllocateIrbAndIrp has failed!!\n\n\n"));
  127. ASSERT(FALSE);
  128. }
  129. // Free resource (from below)
  130. if(pDevExt->UnitDirectory) {
  131. ExFreePool(pDevExt->UnitDirectory);
  132. pDevExt->UnitDirectory = 0;
  133. }
  134. if(pDevExt->UnitDependentDirectory) {
  135. ExFreePool(pDevExt->UnitDependentDirectory);
  136. pDevExt->UnitDependentDirectory = 0;
  137. }
  138. if(pDevExt->ModelLeaf) {
  139. ExFreePool(pDevExt->ModelLeaf);
  140. pDevExt->ModelLeaf = 0;
  141. }
  142. if (pDevExt->ConfigRom) {
  143. ExFreePool(pDevExt->ConfigRom);
  144. pDevExt->ConfigRom = 0;
  145. }
  146. if (pDevExt->VendorLeaf) {
  147. ExFreePool(pDevExt->VendorLeaf);
  148. pDevExt->VendorLeaf = 0;
  149. }
  150. return STATUS_SUCCESS;
  151. }
  152. VOID
  153. InitializeDeviceExtension(
  154. PPORT_CONFIGURATION_INFORMATION ConfigInfo
  155. )
  156. {
  157. PDCAM_EXTENSION pDevExt;
  158. pDevExt = (PDCAM_EXTENSION) ConfigInfo->HwDeviceExtension;
  159. pDevExt->SharedDeviceObject = ConfigInfo->ClassDeviceObject;
  160. pDevExt->BusDeviceObject = ConfigInfo->PhysicalDeviceObject; // Used in IoCallDriver()
  161. pDevExt->PhysicalDeviceObject = ConfigInfo->RealPhysicalDeviceObject; // Used in PnP API
  162. // In case sonydcam is used with old stream.sys,
  163. // which has not implemented RealPhysicalDeviceObject.
  164. if(!pDevExt->PhysicalDeviceObject)
  165. pDevExt->PhysicalDeviceObject = pDevExt->BusDeviceObject;
  166. ASSERT(pDevExt->PhysicalDeviceObject != 0);
  167. pDevExt->BaseRegister = 0;
  168. pDevExt->FrameRate = DEFAULT_FRAME_RATE;
  169. InitializeListHead(&pDevExt->IsochDescriptorList);
  170. KeInitializeSpinLock(&pDevExt->IsochDescriptorLock);
  171. pDevExt->bNeedToListen = FALSE;
  172. pDevExt->hResource = NULL;
  173. pDevExt->hBandwidth = NULL;
  174. pDevExt->IsochChannel = ISOCH_ANY_CHANNEL;
  175. pDevExt->PendingReadCount = 0;
  176. pDevExt->pStrmEx = 0;
  177. InitializeListHead(&pDevExt->IsochWaitingList);
  178. KeInitializeSpinLock(&pDevExt->IsochWaitingLock);
  179. pDevExt->bDevRemoved = FALSE;
  180. pDevExt->CurrentPowerState = PowerDeviceD0; // full power state.
  181. KeInitializeMutex( &pDevExt->hMutexProperty, 0); // Level 0 and in Signal state
  182. }
  183. NTSTATUS
  184. DCamHwInitialize(
  185. IN PHW_STREAM_REQUEST_BLOCK Srb
  186. )
  187. /*++
  188. Routine Description:
  189. This where we perform the necessary initialization tasks.
  190. Arguments:
  191. Srb - Pointer to stream request block
  192. Return Value:
  193. Nothing
  194. --*/
  195. {
  196. PIRB pIrb;
  197. PIRP pIrp;
  198. CCHAR StackSize;
  199. ULONG i;
  200. ULONG DirectoryLength;
  201. NTSTATUS status = STATUS_SUCCESS;
  202. PDCAM_EXTENSION pDevExt;
  203. PPORT_CONFIGURATION_INFORMATION ConfigInfo;
  204. PAGED_CODE();
  205. ConfigInfo = Srb->CommandData.ConfigInfo;
  206. pIrb = (PIRB) Srb->SRBExtension;
  207. pDevExt = (PDCAM_EXTENSION) ConfigInfo->HwDeviceExtension;
  208. //
  209. // Initialize DeviceExtension
  210. //
  211. InitializeDeviceExtension(ConfigInfo);
  212. StackSize = pDevExt->BusDeviceObject->StackSize;
  213. pIrp = IoAllocateIrp(StackSize, FALSE);
  214. if (!pIrp) {
  215. ASSERT(FALSE);
  216. return (STATUS_INSUFFICIENT_RESOURCES);
  217. }
  218. //
  219. // find what the host adaptor below us supports...
  220. //
  221. pIrb->FunctionNumber = REQUEST_GET_LOCAL_HOST_INFO;
  222. pIrb->Flags = 0;
  223. pIrb->u.GetLocalHostInformation.nLevel = GET_HOST_CAPABILITIES;
  224. pIrb->u.GetLocalHostInformation.Information = &pDevExt->HostControllerInfomation;
  225. status = DCamSubmitIrpSynch(pDevExt, pIrp, pIrb);
  226. if (status) {
  227. ERROR_LOG(("DCamHwInitialize: Error (Status=%x) while trying to get local hsot info.\n", status));
  228. status = STATUS_UNSUCCESSFUL;
  229. goto AbortLoading;
  230. }
  231. //
  232. // find what the max buffer size is supported by the host.
  233. //
  234. pIrb->FunctionNumber = REQUEST_GET_LOCAL_HOST_INFO;
  235. pIrb->Flags = 0;
  236. pIrb->u.GetLocalHostInformation.nLevel = GET_HOST_DMA_CAPABILITIES;
  237. pIrb->u.GetLocalHostInformation.Information = &pDevExt->HostDMAInformation;
  238. status = DCamSubmitIrpSynch(pDevExt, pIrp, pIrb);
  239. if (status) {
  240. ERROR_LOG(("DCamHwInitialize: Error (Status=%x) while trying to get GET_HOST_DMA_CAPABILITIES.\n", status));
  241. // May not supported in the ealier version of 1394
  242. // Set default.
  243. } else {
  244. ERROR_LOG(("\'GET_HOST_DMA_CAPABILITIES: HostDmaCapabilities;:%x; MaxDmaBufferSize:(Quad:%x; High:%x;Low:%x)\n",
  245. pDevExt->HostDMAInformation.HostDmaCapabilities,
  246. (DWORD) pDevExt->HostDMAInformation.MaxDmaBufferSize.QuadPart,
  247. pDevExt->HostDMAInformation.MaxDmaBufferSize.u.HighPart,
  248. pDevExt->HostDMAInformation.MaxDmaBufferSize.u.LowPart
  249. ));
  250. }
  251. //
  252. // Make a call to determine what the generation # is on the bus,
  253. // followed by a call to find out about ourself (config rom info)
  254. //
  255. //
  256. // Get the current generation count first
  257. //
  258. pIrb->FunctionNumber = REQUEST_GET_GENERATION_COUNT;
  259. pIrb->Flags = 0;
  260. status = DCamSubmitIrpSynch(pDevExt, pIrp, pIrb);
  261. if (status) {
  262. ERROR_LOG(("\'DCamHwInitialize: Error %x while trying to get generation number\n", status));
  263. status = STATUS_UNSUCCESSFUL;
  264. goto AbortLoading;
  265. }
  266. InterlockedExchange(&pDevExt->CurrentGeneration, pIrb->u.GetGenerationCount.GenerationCount);
  267. //
  268. // Now that we have the current generation count, find out how much
  269. // configuration space we need by setting lengths to zero.
  270. //
  271. pIrb->FunctionNumber = REQUEST_GET_CONFIGURATION_INFO;
  272. pIrb->Flags = 0;
  273. pIrb->u.GetConfigurationInformation.UnitDirectoryBufferSize = 0;
  274. pIrb->u.GetConfigurationInformation.UnitDependentDirectoryBufferSize = 0;
  275. pIrb->u.GetConfigurationInformation.VendorLeafBufferSize = 0;
  276. pIrb->u.GetConfigurationInformation.ModelLeafBufferSize = 0;
  277. status = DCamSubmitIrpSynch(pDevExt, pIrp, pIrb);
  278. if (status) {
  279. ERROR_LOG(("\'DCamHwInitialize: Error %x while trying to get configuration info (1)\n", status));
  280. status = STATUS_UNSUCCESSFUL;
  281. goto AbortLoading;
  282. }
  283. //
  284. // Now go thru and allocate what we need to so we can get our info.
  285. //
  286. pDevExt->ConfigRom = ExAllocatePoolWithTag(PagedPool, sizeof(CONFIG_ROM), 'macd');
  287. if (!pDevExt->ConfigRom) {
  288. ERROR_LOG(("\'DCamHwInitialize: Couldn't allocate memory for the Config Rom\n"));
  289. status = STATUS_INSUFFICIENT_RESOURCES;
  290. goto AbortLoading;
  291. }
  292. pDevExt->UnitDirectory = ExAllocatePoolWithTag(PagedPool, pIrb->u.GetConfigurationInformation.UnitDirectoryBufferSize, 'macd');
  293. if (!pDevExt->UnitDirectory) {
  294. ERROR_LOG(("\'DCamHwInitialize: Couldn't allocate memory for the UnitDirectory\n"));
  295. status = STATUS_INSUFFICIENT_RESOURCES;
  296. goto AbortLoading;
  297. }
  298. if (pIrb->u.GetConfigurationInformation.UnitDependentDirectoryBufferSize) {
  299. pDevExt->UnitDependentDirectory = ExAllocatePoolWithTag(PagedPool, pIrb->u.GetConfigurationInformation.UnitDependentDirectoryBufferSize, 'macd');
  300. if (!pDevExt->UnitDependentDirectory) {
  301. ERROR_LOG(("\'DCamHwInitialize: Couldn't allocate memory for the UnitDependentDirectory\n"));
  302. status = STATUS_INSUFFICIENT_RESOURCES;
  303. goto AbortLoading;
  304. }
  305. }
  306. if (pIrb->u.GetConfigurationInformation.VendorLeafBufferSize) {
  307. // From NonPaged pool since vendor name can be used in a func with DISPATCH level
  308. pDevExt->VendorLeaf = ExAllocatePoolWithTag(NonPagedPool, pIrb->u.GetConfigurationInformation.VendorLeafBufferSize, 'macd');
  309. if (!pDevExt->VendorLeaf) {
  310. ERROR_LOG(("\'DCamHwInitialize: Couldn't allocate memory for the VendorLeaf\n"));
  311. status = STATUS_INSUFFICIENT_RESOURCES;
  312. goto AbortLoading;
  313. }
  314. }
  315. if (pIrb->u.GetConfigurationInformation.ModelLeafBufferSize) {
  316. pDevExt->ModelLeaf = ExAllocatePoolWithTag(NonPagedPool, pIrb->u.GetConfigurationInformation.ModelLeafBufferSize, 'macd');
  317. if (!pDevExt->ModelLeaf) {
  318. ERROR_LOG(("\'DCamHwInitialize: Couldn't allocate memory for the ModelLeaf\n"));
  319. status = STATUS_INSUFFICIENT_RESOURCES;
  320. goto AbortLoading;
  321. }
  322. }
  323. //
  324. // Now resubmit the pIrb with the appropriate pointers inside
  325. //
  326. pIrb->FunctionNumber = REQUEST_GET_CONFIGURATION_INFO;
  327. pIrb->Flags = 0;
  328. pIrb->u.GetConfigurationInformation.ConfigRom = pDevExt->ConfigRom;
  329. pIrb->u.GetConfigurationInformation.UnitDirectory = pDevExt->UnitDirectory;
  330. pIrb->u.GetConfigurationInformation.UnitDependentDirectory = pDevExt->UnitDependentDirectory;
  331. pIrb->u.GetConfigurationInformation.VendorLeaf = pDevExt->VendorLeaf;
  332. pIrb->u.GetConfigurationInformation.ModelLeaf = pDevExt->ModelLeaf;
  333. status = DCamSubmitIrpSynch(pDevExt, pIrp, pIrb);
  334. if (status) {
  335. ERROR_LOG(("DCamHwInitialize: Error %x while trying to get configuration info (2)\n", status));
  336. status = STATUS_UNSUCCESSFUL;
  337. goto AbortLoading;
  338. }
  339. //
  340. // We might be able to return strings about a Device
  341. //
  342. if (pDevExt->VendorLeaf) {
  343. //
  344. // bswap to get the actual leaf length (in quadlets)
  345. //
  346. *((PULONG) pDevExt->VendorLeaf) = bswap(*((PULONG) pDevExt->VendorLeaf));
  347. DbgMsg1(("\'DCamHwInitialize: BufSize %d (byte); VendorLeaf %x; Len %d (Quad)\n",
  348. pIrb->u.GetConfigurationInformation.VendorLeafBufferSize,
  349. pDevExt->VendorLeaf,
  350. pDevExt->VendorLeaf->TL_Length));
  351. if(pDevExt->VendorLeaf->TL_Length >= 1) {
  352. pDevExt->pchVendorName = &pDevExt->VendorLeaf->TL_Data;
  353. } else {
  354. pDevExt->pchVendorName = szUnknownVendorName;
  355. }
  356. DbgMsg1(("\'DCamHwInitialize: VendorName %s, strLen %d\n", pDevExt->pchVendorName, strlen(pDevExt->pchVendorName)));
  357. }
  358. //
  359. // Now we chew thru the Unit Dependent Directory looking for our command
  360. // base register key.
  361. //
  362. DirectoryLength = pIrb->u.GetConfigurationInformation.UnitDependentDirectoryBufferSize >> 2;
  363. for (i=1; i < DirectoryLength; i++) {
  364. if ((*(((PULONG) pDevExt->UnitDependentDirectory)+i) & CONFIG_ROM_KEY_MASK) == COMMAND_BASE_KEY_SIGNATURE) {
  365. //
  366. // Found the command base offset. This is a quadlet offset from
  367. // the initial register space. (Should come out to 0xf0f00000)
  368. //
  369. pDevExt->BaseRegister = bswap(*(((PULONG) pDevExt->UnitDependentDirectory)+i) & CONFIG_ROM_OFFSET_MASK);
  370. pDevExt->BaseRegister <<= 2;
  371. pDevExt->BaseRegister |= INITIAL_REGISTER_SPACE_LO;
  372. break;
  373. }
  374. }
  375. ASSERT( pDevExt->BaseRegister );
  376. if(!DCamDeviceInUse(pIrb, pDevExt)) {
  377. //
  378. // Now let's actually do a write request to initialize the device
  379. //
  380. pDevExt->RegisterWorkArea.AsULONG = 0;
  381. pDevExt->RegisterWorkArea.Initialize.Initialize = TRUE;
  382. pDevExt->RegisterWorkArea.AsULONG = bswap(pDevExt->RegisterWorkArea.AsULONG);
  383. status = DCamWriteRegister ((PIRB) Srb->SRBExtension, pDevExt,
  384. FIELDOFFSET(CAMERA_REGISTER_MAP, Initialize), pDevExt->RegisterWorkArea.AsULONG);
  385. if(status) {
  386. ERROR_LOG(("DCamHwInitialize: Error %x while trying to write to Initialize register\n", status));
  387. status = STATUS_UNSUCCESSFUL;
  388. goto AbortLoading;
  389. }
  390. }
  391. //
  392. // Now we initialize the size of stream descriptor information.
  393. // We have one stream descriptor, and we attempt to dword align the
  394. // structure.
  395. //
  396. ConfigInfo->StreamDescriptorSize =
  397. 1 * (sizeof (HW_STREAM_INFORMATION)) + // 1 stream descriptor
  398. sizeof(HW_STREAM_HEADER); // and 1 stream header
  399. //
  400. // Construct the device property table from querying the device and registry
  401. //
  402. if(!NT_SUCCESS(status = DCamPrepareDevProperties(pDevExt))) {
  403. goto AbortLoading;
  404. }
  405. // Get the features of the properties as well as its persisted value.
  406. // It will also updated the table.
  407. // The return is ignored since the default values are set when there is a failure.
  408. DCamGetPropertyValuesFromRegistry(
  409. pDevExt
  410. );
  411. //
  412. // Query video mode supported, and then contruct the stream format table.
  413. //
  414. if(!DCamBuildFormatTable(pDevExt, pIrb)) {
  415. ERROR_LOG(("\'Failed to get Video Format and Mode information; return STATUS_NOT_SUPPORTED\n"));
  416. status = STATUS_NOT_SUPPORTED;
  417. goto AbortLoading;
  418. }
  419. //
  420. // register a bus reset callback notification (as the last action in this function)
  421. //
  422. // The controller driver will call (at DPC level)
  423. // if and only if the device is STILL attached.
  424. //
  425. // The device that has been removed, its
  426. // driver will get SRB_SURPRISE_REMOVAL instead.
  427. //
  428. pIrb->FunctionNumber = REQUEST_BUS_RESET_NOTIFICATION;
  429. pIrb->Flags = 0;
  430. pIrb->u.BusResetNotification.fulFlags = REGISTER_NOTIFICATION_ROUTINE;
  431. pIrb->u.BusResetNotification.ResetRoutine = (PBUS_BUS_RESET_NOTIFICATION) DCamBusResetNotification;
  432. pIrb->u.BusResetNotification.ResetContext = pDevExt;
  433. status = DCamSubmitIrpSynch(pDevExt, pIrp, pIrb);
  434. if (status) {
  435. ERROR_LOG(("DCamHwInitialize: Error (Status=%x) while trying to get local host info.\n", status));
  436. status = STATUS_UNSUCCESSFUL;
  437. goto AbortLoading;
  438. }
  439. // This Irp is used locally only.
  440. IoFreeIrp(pIrp); pIrp = NULL;
  441. DbgMsg1(("#### %s DCam loaded. ClassDO %x, PhyDO %x, BusDO %x, pDevExt %x, Gen# %d\n",
  442. pDevExt->pchVendorName, pDevExt->SharedDeviceObject, pDevExt->PhysicalDeviceObject, pDevExt->BusDeviceObject, pDevExt, pDevExt->CurrentGeneration));
  443. return (STATUS_SUCCESS);
  444. AbortLoading:
  445. if(pIrp) {
  446. IoFreeIrp(pIrp); pIrp = NULL;
  447. }
  448. if(pDevExt->ConfigRom) {
  449. ExFreePool(pDevExt->ConfigRom); pDevExt->ConfigRom = NULL;
  450. }
  451. if(pDevExt->UnitDirectory) {
  452. ExFreePool(pDevExt->UnitDirectory); pDevExt->UnitDirectory = NULL;
  453. }
  454. if(pDevExt->UnitDependentDirectory) {
  455. ExFreePool(pDevExt->UnitDependentDirectory); pDevExt->UnitDependentDirectory = NULL;
  456. }
  457. if(pDevExt->VendorLeaf) {
  458. ExFreePool(pDevExt->VendorLeaf); pDevExt->VendorLeaf = NULL;
  459. }
  460. if(pDevExt->ModelLeaf) {
  461. ExFreePool(pDevExt->ModelLeaf); pDevExt->ModelLeaf = NULL;
  462. }
  463. return status;
  464. }
  465. NTSTATUS
  466. DCamSubmitIrpSynch(
  467. PDCAM_EXTENSION pDevExt,
  468. PIRP pIrp,
  469. PIRB pIrb
  470. )
  471. /*++
  472. Routine Description:
  473. This routine submits an Irp synchronously to the bus driver. We'll
  474. wait here til the Irp comes back
  475. Arguments:
  476. pDevExt - Pointer to my local device extension
  477. pIrp - Pointer to Irp we're sending down to the port driver synchronously
  478. pIrb - Pointer to Irb we're submitting to the port driver
  479. Return Value:
  480. Status is returned from Irp
  481. --*/
  482. {
  483. LONG Retries=RETRY_COUNT_IRP_SYNC; // Take the worst case of 20 * 100 msec = 1sec
  484. KEVENT Event;
  485. NTSTATUS status;
  486. LARGE_INTEGER deltaTime;
  487. PIO_STACK_LOCATION NextIrpStack;
  488. BOOL bCanWait = KeGetCurrentIrql() < DISPATCH_LEVEL;
  489. BOOL bRetryStatus;
  490. PIRB pIrbRetry;
  491. NTSTATUS StatusRetry;
  492. ULONG ulGeneration;
  493. do {
  494. NextIrpStack = IoGetNextIrpStackLocation(pIrp);
  495. NextIrpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  496. NextIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_1394_CLASS;
  497. NextIrpStack->Parameters.Others.Argument1 = pIrb;
  498. KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
  499. IoSetCompletionRoutine(
  500. pIrp,
  501. DCamSynchCR,
  502. &Event,
  503. TRUE,
  504. TRUE,
  505. TRUE
  506. );
  507. status = IoCallDriver(
  508. pDevExt->BusDeviceObject,
  509. pIrp
  510. );
  511. DbgMsg3(("\'DCamSubmitIrpSynch: pIrp is pending(%s); will wait(%s)\n",
  512. status == STATUS_PENDING?"Y":"N", bCanWait?"Y":"N"));
  513. if (bCanWait &&
  514. status == STATUS_PENDING) {
  515. //
  516. // Still pending, wait for the IRP to complete
  517. //
  518. KeWaitForSingleObject( // Only in <= IRQL_DISPATCH_LEVEL; can only in DISPATCH if Timeout is 0
  519. &Event,
  520. Executive,
  521. KernelMode,
  522. FALSE,
  523. NULL
  524. );
  525. }
  526. // Will retry for any of these return status codes.
  527. bRetryStatus =
  528. pIrp->IoStatus.Status == STATUS_TIMEOUT ||
  529. pIrp->IoStatus.Status == STATUS_IO_TIMEOUT ||
  530. pIrp->IoStatus.Status == STATUS_DEVICE_BUSY ||
  531. pIrp->IoStatus.Status == STATUS_INVALID_GENERATION;
  532. if (bCanWait && bRetryStatus && Retries > 0) {
  533. // Camera isn't fast enough to respond so delay this thread and try again.
  534. switch(pIrp->IoStatus.Status) {
  535. case STATUS_TIMEOUT:
  536. case STATUS_IO_TIMEOUT:
  537. case STATUS_DEVICE_BUSY:
  538. deltaTime.LowPart = DCAM_DELAY_VALUE;
  539. deltaTime.HighPart = -1;
  540. KeDelayExecutionThread(KernelMode, TRUE, &deltaTime);
  541. break;
  542. case STATUS_INVALID_GENERATION:
  543. // Cache obsolete ulGeneration and use it to detect its udpate in busreset callback.
  544. if(pIrb->FunctionNumber == REQUEST_ASYNC_READ)
  545. ulGeneration = pIrb->u.AsyncRead.ulGeneration;
  546. else if(pIrb->FunctionNumber == REQUEST_ASYNC_WRITE)
  547. ulGeneration = pIrb->u.AsyncWrite.ulGeneration;
  548. else if(pIrb->FunctionNumber == REQUEST_ASYNC_LOCK)
  549. ulGeneration = pIrb->u.AsyncLock.ulGeneration;
  550. else if(pIrb->FunctionNumber == REQUEST_ISOCH_FREE_BANDWIDTH) {
  551. ERROR_LOG(("InvGen when free BW\n"));
  552. // Special case that we do not need to retry since BW should be free
  553. // and 1394 bus should just free the BW structure.
  554. Retries = 0; // no more retry and exit.
  555. break;
  556. }
  557. else {
  558. // Other REQUEST_* that depends on ulGeneration
  559. ERROR_LOG(("Unexpected IRB function with InvGen:%d\n", pIrb->FunctionNumber));
  560. ASSERT(FALSE && "New REQUEST that requires ulGeneration");
  561. Retries = 0; // do not know what to do so no more retry and exit.
  562. break;
  563. }
  564. pIrbRetry = ExAllocatePoolWithTag(NonPagedPool, sizeof(IRB), 'macd');
  565. if (pIrbRetry) {
  566. deltaTime.LowPart = DCAM_DELAY_VALUE_BUSRESET; // Longer than the regular delay
  567. deltaTime.HighPart = -1;
  568. do {
  569. KeDelayExecutionThread(KernelMode, TRUE, &deltaTime);
  570. pIrbRetry->FunctionNumber = REQUEST_GET_GENERATION_COUNT;
  571. pIrbRetry->u.GetGenerationCount.GenerationCount = 0;
  572. pIrbRetry->Flags = 0;
  573. StatusRetry = DCamSubmitIrpSynch(pDevExt, pIrp, pIrbRetry); // Recursive with differnt IRB but same IRP.
  574. if(NT_SUCCESS(StatusRetry) && pIrbRetry->u.GetGenerationCount.GenerationCount > ulGeneration) {
  575. InterlockedExchange(&pDevExt->CurrentGeneration, pIrbRetry->u.GetGenerationCount.GenerationCount);
  576. // Update the generation count for the original IRB request and try again.
  577. if(pIrb->FunctionNumber == REQUEST_ASYNC_READ)
  578. InterlockedExchange(&pIrb->u.AsyncRead.ulGeneration, pDevExt->CurrentGeneration);
  579. else if(pIrb->FunctionNumber == REQUEST_ASYNC_WRITE)
  580. InterlockedExchange(&pIrb->u.AsyncWrite.ulGeneration, pDevExt->CurrentGeneration);
  581. else if(pIrb->FunctionNumber == REQUEST_ASYNC_LOCK)
  582. InterlockedExchange(&pIrb->u.AsyncLock.ulGeneration, pDevExt->CurrentGeneration);
  583. else {
  584. // Other (new) REQUEST_* that depends on ulGeneration
  585. }
  586. }
  587. if(Retries)
  588. Retries--;
  589. } while (Retries && ulGeneration >= pDevExt->CurrentGeneration);
  590. ERROR_LOG(("(%d) IrpSync: StautsRetry %x; Generation %d -> %d\n",
  591. Retries, StatusRetry, ulGeneration, pDevExt->CurrentGeneration));
  592. ExFreePool(pIrbRetry); pIrbRetry = 0;
  593. } // if
  594. break;
  595. // All other status
  596. default:
  597. break;
  598. }
  599. }
  600. if(Retries)
  601. Retries--;
  602. } while (bCanWait && bRetryStatus && (Retries > 0));
  603. #if DBG
  604. if(!NT_SUCCESS(pIrp->IoStatus.Status)) {
  605. ERROR_LOG(("IrpSynch: IoCallDriver Status:%x; pIrp->IoStatus.Status (final):%x; Wait:%d; Retries:%d\n", status, pIrp->IoStatus.Status, bCanWait, Retries));
  606. }
  607. #endif
  608. return (pIrp->IoStatus.Status);
  609. }
  610. NTSTATUS
  611. DCamSynchCR(
  612. IN PDEVICE_OBJECT DeviceObject,
  613. IN PIRP pIrp,
  614. IN PKEVENT Event
  615. )
  616. /*++
  617. Routine Description:
  618. This routine is for use with synchronous IRP processing.
  619. All it does is signal an event, so the driver knows it
  620. can continue.
  621. Arguments:
  622. DriverObject - Pointer to driver object created by system.
  623. pIrp - Irp that just completed
  624. Event - Event we'll signal to say Irp is done
  625. Return Value:
  626. None.
  627. --*/
  628. {
  629. KeSetEvent((PKEVENT) Event, 0, FALSE);
  630. return (STATUS_MORE_PROCESSING_REQUIRED);
  631. }