PageRenderTime 65ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 1ms

/drivers/storage/classpnp/class.c

https://bitbucket.org/arty/arty-newcc-reactos
C | 9183 lines | 6777 code | 933 blank | 1473 comment | 409 complexity | 57fb997264080c066297aa10d46bb03d MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, LGPL-3.0, CC-BY-SA-3.0, AGPL-3.0, GPL-3.0, CPL-1.0

Large files files are truncated, but you can click here to view the full file

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1991 - 1999
  3. Module Name:
  4. class.c
  5. Abstract:
  6. SCSI class driver routines
  7. Environment:
  8. kernel mode only
  9. Notes:
  10. Revision History:
  11. --*/
  12. #define CLASS_INIT_GUID 1
  13. #include "classp.h"
  14. #include "debug.h"
  15. #ifdef ALLOC_PRAGMA
  16. #pragma alloc_text(INIT, DriverEntry)
  17. #pragma alloc_text(PAGE, ClassAddDevice)
  18. #pragma alloc_text(PAGE, ClassClaimDevice)
  19. #pragma alloc_text(PAGE, ClassCreateDeviceObject)
  20. #pragma alloc_text(PAGE, ClassDispatchPnp)
  21. #pragma alloc_text(PAGE, ClassGetDescriptor)
  22. #pragma alloc_text(PAGE, ClassGetPdoId)
  23. #pragma alloc_text(PAGE, ClassInitialize)
  24. #pragma alloc_text(PAGE, ClassInitializeEx)
  25. #pragma alloc_text(PAGE, ClassInvalidateBusRelations)
  26. #pragma alloc_text(PAGE, ClassMarkChildMissing)
  27. #pragma alloc_text(PAGE, ClassMarkChildrenMissing)
  28. #pragma alloc_text(PAGE, ClassModeSense)
  29. #pragma alloc_text(PAGE, ClassPnpQueryFdoRelations)
  30. #pragma alloc_text(PAGE, ClassPnpStartDevice)
  31. #pragma alloc_text(PAGE, ClassQueryPnpCapabilities)
  32. #pragma alloc_text(PAGE, ClassQueryTimeOutRegistryValue)
  33. #pragma alloc_text(PAGE, ClassRemoveDevice)
  34. #pragma alloc_text(PAGE, ClassRetrieveDeviceRelations)
  35. #pragma alloc_text(PAGE, ClassUpdateInformationInRegistry)
  36. #pragma alloc_text(PAGE, ClassSendDeviceIoControlSynchronous)
  37. #pragma alloc_text(PAGE, ClassUnload)
  38. #pragma alloc_text(PAGE, ClasspAllocateReleaseRequest)
  39. #pragma alloc_text(PAGE, ClasspFreeReleaseRequest)
  40. #pragma alloc_text(PAGE, ClasspInitializeHotplugInfo)
  41. #pragma alloc_text(PAGE, ClasspRegisterMountedDeviceInterface)
  42. #pragma alloc_text(PAGE, ClasspScanForClassHacks)
  43. #pragma alloc_text(PAGE, ClasspScanForSpecialInRegistry)
  44. #endif
  45. ULONG ClassPnpAllowUnload = TRUE;
  46. #define FirstDriveLetter 'C'
  47. #define LastDriveLetter 'Z'
  48. /*++////////////////////////////////////////////////////////////////////////////
  49. DriverEntry()
  50. Routine Description:
  51. Temporary entry point needed to initialize the class system dll.
  52. It doesn't do anything.
  53. Arguments:
  54. DriverObject - Pointer to the driver object created by the system.
  55. Return Value:
  56. STATUS_SUCCESS
  57. --*/
  58. NTSTATUS
  59. NTAPI
  60. DriverEntry(
  61. IN PDRIVER_OBJECT DriverObject,
  62. IN PUNICODE_STRING RegistryPath
  63. )
  64. {
  65. return STATUS_SUCCESS;
  66. }
  67. /*++////////////////////////////////////////////////////////////////////////////
  68. ClassInitialize()
  69. Routine Description:
  70. This routine is called by a class driver during its
  71. DriverEntry routine to initialize the driver.
  72. Arguments:
  73. Argument1 - Driver Object.
  74. Argument2 - Registry Path.
  75. InitializationData - Device-specific driver's initialization data.
  76. Return Value:
  77. A valid return code for a DriverEntry routine.
  78. --*/
  79. ULONG
  80. ClassInitialize(
  81. IN PVOID Argument1,
  82. IN PVOID Argument2,
  83. IN PCLASS_INIT_DATA InitializationData
  84. )
  85. {
  86. PDRIVER_OBJECT DriverObject = Argument1;
  87. PUNICODE_STRING RegistryPath = Argument2;
  88. PCLASS_DRIVER_EXTENSION driverExtension;
  89. NTSTATUS status;
  90. PAGED_CODE();
  91. DebugPrint((3,"\n\nSCSI Class Driver\n"));
  92. ClasspInitializeDebugGlobals();
  93. //
  94. // Validate the length of this structure. This is effectively a
  95. // version check.
  96. //
  97. if (InitializationData->InitializationDataSize != sizeof(CLASS_INIT_DATA)) {
  98. //
  99. // This DebugPrint is to help third-party driver writers
  100. //
  101. DebugPrint((0,"ClassInitialize: Class driver wrong version\n"));
  102. return (ULONG) STATUS_REVISION_MISMATCH;
  103. }
  104. //
  105. // Check that each required entry is not NULL. Note that Shutdown, Flush and Error
  106. // are not required entry points.
  107. //
  108. if ((!InitializationData->FdoData.ClassDeviceControl) ||
  109. (!((InitializationData->FdoData.ClassReadWriteVerification) ||
  110. (InitializationData->ClassStartIo))) ||
  111. (!InitializationData->ClassAddDevice) ||
  112. (!InitializationData->FdoData.ClassStartDevice)) {
  113. //
  114. // This DebugPrint is to help third-party driver writers
  115. //
  116. DebugPrint((0,
  117. "ClassInitialize: Class device-specific driver missing required "
  118. "FDO entry\n"));
  119. return (ULONG) STATUS_REVISION_MISMATCH;
  120. }
  121. if ((InitializationData->ClassEnumerateDevice) &&
  122. ((!InitializationData->PdoData.ClassDeviceControl) ||
  123. (!InitializationData->PdoData.ClassStartDevice) ||
  124. (!((InitializationData->PdoData.ClassReadWriteVerification) ||
  125. (InitializationData->ClassStartIo))))) {
  126. //
  127. // This DebugPrint is to help third-party driver writers
  128. //
  129. DebugPrint((0, "ClassInitialize: Class device-specific missing "
  130. "required PDO entry\n"));
  131. return (ULONG) STATUS_REVISION_MISMATCH;
  132. }
  133. if((InitializationData->FdoData.ClassStopDevice == NULL) ||
  134. ((InitializationData->ClassEnumerateDevice != NULL) &&
  135. (InitializationData->PdoData.ClassStopDevice == NULL))) {
  136. //
  137. // This DebugPrint is to help third-party driver writers
  138. //
  139. DebugPrint((0, "ClassInitialize: Class device-specific missing "
  140. "required PDO entry\n"));
  141. ASSERT(FALSE);
  142. return (ULONG) STATUS_REVISION_MISMATCH;
  143. }
  144. //
  145. // Setup the default power handlers if the class driver didn't provide
  146. // any.
  147. //
  148. if(InitializationData->FdoData.ClassPowerDevice == NULL) {
  149. InitializationData->FdoData.ClassPowerDevice = ClassMinimalPowerHandler;
  150. }
  151. if((InitializationData->ClassEnumerateDevice != NULL) &&
  152. (InitializationData->PdoData.ClassPowerDevice == NULL)) {
  153. InitializationData->PdoData.ClassPowerDevice = ClassMinimalPowerHandler;
  154. }
  155. //
  156. // warn that unload is not supported
  157. //
  158. // ISSUE-2000/02/03-peterwie
  159. // We should think about making this a fatal error.
  160. //
  161. if(InitializationData->ClassUnload == NULL) {
  162. //
  163. // This DebugPrint is to help third-party driver writers
  164. //
  165. DebugPrint((0, "ClassInitialize: driver does not support unload %wZ\n",
  166. RegistryPath));
  167. }
  168. //
  169. // Create an extension for the driver object
  170. //
  171. status = IoAllocateDriverObjectExtension(DriverObject,
  172. CLASS_DRIVER_EXTENSION_KEY,
  173. sizeof(CLASS_DRIVER_EXTENSION),
  174. &driverExtension);
  175. if(NT_SUCCESS(status)) {
  176. //
  177. // Copy the registry path into the driver extension so we can use it later
  178. //
  179. driverExtension->RegistryPath.Length = RegistryPath->Length;
  180. driverExtension->RegistryPath.MaximumLength = RegistryPath->MaximumLength;
  181. driverExtension->RegistryPath.Buffer =
  182. ExAllocatePoolWithTag(PagedPool,
  183. RegistryPath->MaximumLength,
  184. '1CcS');
  185. if(driverExtension->RegistryPath.Buffer == NULL) {
  186. status = STATUS_INSUFFICIENT_RESOURCES;
  187. return status;
  188. }
  189. RtlCopyUnicodeString(
  190. &(driverExtension->RegistryPath),
  191. RegistryPath);
  192. //
  193. // Copy the initialization data into the driver extension so we can reuse
  194. // it during our add device routine
  195. //
  196. RtlCopyMemory(
  197. &(driverExtension->InitData),
  198. InitializationData,
  199. sizeof(CLASS_INIT_DATA));
  200. driverExtension->DeviceCount = 0;
  201. } else if (status == STATUS_OBJECT_NAME_COLLISION) {
  202. //
  203. // The extension already exists - get a pointer to it
  204. //
  205. driverExtension = IoGetDriverObjectExtension(DriverObject,
  206. CLASS_DRIVER_EXTENSION_KEY);
  207. ASSERT(driverExtension != NULL);
  208. } else {
  209. DebugPrint((1, "ClassInitialize: Class driver extension could not be "
  210. "allocated %lx\n", status));
  211. return status;
  212. }
  213. //
  214. // Update driver object with entry points.
  215. //
  216. DriverObject->MajorFunction[IRP_MJ_CREATE] = ClassCreateClose;
  217. DriverObject->MajorFunction[IRP_MJ_CLOSE] = ClassCreateClose;
  218. DriverObject->MajorFunction[IRP_MJ_READ] = ClassReadWrite;
  219. DriverObject->MajorFunction[IRP_MJ_WRITE] = ClassReadWrite;
  220. DriverObject->MajorFunction[IRP_MJ_SCSI] = ClassInternalIoControl;
  221. DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ClassDeviceControlDispatch;
  222. DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = ClassShutdownFlush;
  223. DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = ClassShutdownFlush;
  224. DriverObject->MajorFunction[IRP_MJ_PNP] = ClassDispatchPnp;
  225. DriverObject->MajorFunction[IRP_MJ_POWER] = ClassDispatchPower;
  226. DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = ClassSystemControl;
  227. if (InitializationData->ClassStartIo) {
  228. DriverObject->DriverStartIo = ClasspStartIo;
  229. }
  230. if ((InitializationData->ClassUnload) && (ClassPnpAllowUnload == TRUE)) {
  231. DriverObject->DriverUnload = ClassUnload;
  232. } else {
  233. DriverObject->DriverUnload = NULL;
  234. }
  235. DriverObject->DriverExtension->AddDevice = ClassAddDevice;
  236. DbgPrint("Driver is ready to go\n");
  237. status = STATUS_SUCCESS;
  238. return status;
  239. } // end ClassInitialize()
  240. /*++////////////////////////////////////////////////////////////////////////////
  241. ClassInitializeEx()
  242. Routine Description:
  243. This routine is allows the caller to do any extra initialization or
  244. setup that is not done in ClassInitialize. The operation is
  245. controlled by the GUID that is passed and the contents of the Data
  246. parameter is dependent upon the GUID.
  247. This is the list of supported operations:
  248. Guid - GUID_CLASSPNP_QUERY_REGINFOEX
  249. Data - A PCLASS_QUERY_WMI_REGINFO_EX callback function pointer
  250. Initialized classpnp to callback a PCLASS_QUERY_WMI_REGINFO_EX
  251. callback instead of a PCLASS_QUERY_WMI_REGINFO callback. The
  252. former callback allows the driver to specify the name of the
  253. mof resource.
  254. Arguments:
  255. DriverObject
  256. Guid
  257. Data
  258. Return Value:
  259. Status Code
  260. --*/
  261. ULONG
  262. ClassInitializeEx(
  263. IN PDRIVER_OBJECT DriverObject,
  264. IN LPGUID Guid,
  265. IN PVOID Data
  266. )
  267. {
  268. PCLASS_DRIVER_EXTENSION driverExtension;
  269. NTSTATUS status;
  270. PAGED_CODE();
  271. driverExtension = IoGetDriverObjectExtension( DriverObject,
  272. CLASS_DRIVER_EXTENSION_KEY
  273. );
  274. if (IsEqualGUID(Guid, &ClassGuidQueryRegInfoEx))
  275. {
  276. PCLASS_QUERY_WMI_REGINFO_EX_LIST List;
  277. //
  278. // Indicate the device supports PCLASS_QUERY_REGINFO_EX
  279. // callback instead of PCLASS_QUERY_REGINFO callback.
  280. //
  281. List = (PCLASS_QUERY_WMI_REGINFO_EX_LIST)Data;
  282. if (List->Size == sizeof(CLASS_QUERY_WMI_REGINFO_EX_LIST))
  283. {
  284. driverExtension->ClassFdoQueryWmiRegInfoEx = List->ClassFdoQueryWmiRegInfoEx;
  285. driverExtension->ClassPdoQueryWmiRegInfoEx = List->ClassPdoQueryWmiRegInfoEx;
  286. status = STATUS_SUCCESS;
  287. } else {
  288. status = STATUS_INVALID_PARAMETER;
  289. }
  290. } else {
  291. status = STATUS_NOT_SUPPORTED;
  292. }
  293. return(status);
  294. } // end ClassInitializeEx()
  295. /*++////////////////////////////////////////////////////////////////////////////
  296. ClassUnload()
  297. Routine Description:
  298. called when there are no more references to the driver. this allows
  299. drivers to be updated without rebooting.
  300. Arguments:
  301. DriverObject - a pointer to the driver object that is being unloaded
  302. Status:
  303. --*/
  304. VOID
  305. ClassUnload(
  306. IN PDRIVER_OBJECT DriverObject
  307. )
  308. {
  309. PCLASS_DRIVER_EXTENSION driverExtension;
  310. NTSTATUS status;
  311. PAGED_CODE();
  312. ASSERT( DriverObject->DeviceObject == NULL );
  313. driverExtension = IoGetDriverObjectExtension( DriverObject,
  314. CLASS_DRIVER_EXTENSION_KEY
  315. );
  316. ASSERT(driverExtension != NULL);
  317. ASSERT(driverExtension->RegistryPath.Buffer != NULL);
  318. ASSERT(driverExtension->InitData.ClassUnload != NULL);
  319. DebugPrint((1, "ClassUnload: driver unloading %wZ\n",
  320. &driverExtension->RegistryPath));
  321. //
  322. // attempt to process the driver's unload routine first.
  323. //
  324. driverExtension->InitData.ClassUnload(DriverObject);
  325. //
  326. // free own allocated resources and return
  327. //
  328. ExFreePool( driverExtension->RegistryPath.Buffer );
  329. driverExtension->RegistryPath.Buffer = NULL;
  330. driverExtension->RegistryPath.Length = 0;
  331. driverExtension->RegistryPath.MaximumLength = 0;
  332. return;
  333. } // end ClassUnload()
  334. /*++////////////////////////////////////////////////////////////////////////////
  335. ClassAddDevice()
  336. Routine Description:
  337. SCSI class driver add device routine. This is called by pnp when a new
  338. physical device come into being.
  339. This routine will call out to the class driver to verify that it should
  340. own this device then will create and attach a device object and then hand
  341. it to the driver to initialize and create symbolic links
  342. Arguments:
  343. DriverObject - a pointer to the driver object that this is being created for
  344. PhysicalDeviceObject - a pointer to the physical device object
  345. Status: STATUS_NO_SUCH_DEVICE if the class driver did not want this device
  346. STATUS_SUCCESS if the creation and attachment was successful
  347. status of device creation and initialization
  348. --*/
  349. NTSTATUS
  350. ClassAddDevice(
  351. IN PDRIVER_OBJECT DriverObject,
  352. IN PDEVICE_OBJECT PhysicalDeviceObject
  353. )
  354. {
  355. PCLASS_DRIVER_EXTENSION driverExtension =
  356. IoGetDriverObjectExtension(DriverObject,
  357. CLASS_DRIVER_EXTENSION_KEY);
  358. NTSTATUS status;
  359. PAGED_CODE();
  360. DbgPrint("got a device\n");
  361. status = driverExtension->InitData.ClassAddDevice(DriverObject,
  362. PhysicalDeviceObject);
  363. return status;
  364. } // end ClassAddDevice()
  365. /*++////////////////////////////////////////////////////////////////////////////
  366. ClassDispatchPnp()
  367. Routine Description:
  368. Storage class driver pnp routine. This is called by the io system when
  369. a PNP request is sent to the device.
  370. Arguments:
  371. DeviceObject - pointer to the device object
  372. Irp - pointer to the io request packet
  373. Return Value:
  374. status
  375. --*/
  376. NTSTATUS
  377. ClassDispatchPnp(
  378. IN PDEVICE_OBJECT DeviceObject,
  379. IN PIRP Irp
  380. )
  381. {
  382. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  383. BOOLEAN isFdo = commonExtension->IsFdo;
  384. PCLASS_DRIVER_EXTENSION driverExtension;
  385. PCLASS_INIT_DATA initData;
  386. PCLASS_DEV_INFO devInfo;
  387. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  388. PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
  389. NTSTATUS status = Irp->IoStatus.Status;
  390. BOOLEAN completeRequest = TRUE;
  391. BOOLEAN lockReleased = FALSE;
  392. ULONG isRemoved;
  393. PAGED_CODE();
  394. //
  395. // Extract all the useful information out of the driver object
  396. // extension
  397. //
  398. driverExtension = IoGetDriverObjectExtension(DeviceObject->DriverObject,
  399. CLASS_DRIVER_EXTENSION_KEY);
  400. if (driverExtension){
  401. initData = &(driverExtension->InitData);
  402. if(isFdo) {
  403. devInfo = &(initData->FdoData);
  404. } else {
  405. devInfo = &(initData->PdoData);
  406. }
  407. isRemoved = ClassAcquireRemoveLock(DeviceObject, Irp);
  408. DebugPrint((2, "ClassDispatchPnp (%p,%p): minor code %#x for %s %p\n",
  409. DeviceObject, Irp,
  410. irpStack->MinorFunction,
  411. isFdo ? "fdo" : "pdo",
  412. DeviceObject));
  413. DebugPrint((2, "ClassDispatchPnp (%p,%p): previous %#x, current %#x\n",
  414. DeviceObject, Irp,
  415. commonExtension->PreviousState,
  416. commonExtension->CurrentState));
  417. switch(irpStack->MinorFunction) {
  418. case IRP_MN_START_DEVICE: {
  419. //
  420. // if this is sent to the FDO we should forward it down the
  421. // attachment chain before we start the FDO.
  422. //
  423. if (isFdo) {
  424. status = ClassForwardIrpSynchronous(commonExtension, Irp);
  425. }
  426. else {
  427. status = STATUS_SUCCESS;
  428. }
  429. if (NT_SUCCESS(status)){
  430. status = Irp->IoStatus.Status = ClassPnpStartDevice(DeviceObject);
  431. }
  432. break;
  433. }
  434. case IRP_MN_QUERY_DEVICE_RELATIONS: {
  435. DEVICE_RELATION_TYPE type =
  436. irpStack->Parameters.QueryDeviceRelations.Type;
  437. PDEVICE_RELATIONS deviceRelations = NULL;
  438. if(!isFdo) {
  439. if(type == TargetDeviceRelation) {
  440. //
  441. // Device relations has one entry built in to it's size.
  442. //
  443. status = STATUS_INSUFFICIENT_RESOURCES;
  444. deviceRelations = ExAllocatePoolWithTag(PagedPool,
  445. sizeof(DEVICE_RELATIONS),
  446. '2CcS');
  447. if(deviceRelations != NULL) {
  448. RtlZeroMemory(deviceRelations,
  449. sizeof(DEVICE_RELATIONS));
  450. Irp->IoStatus.Information = (ULONG_PTR) deviceRelations;
  451. deviceRelations->Count = 1;
  452. deviceRelations->Objects[0] = DeviceObject;
  453. ObReferenceObject(deviceRelations->Objects[0]);
  454. status = STATUS_SUCCESS;
  455. }
  456. } else {
  457. //
  458. // PDO's just complete enumeration requests without altering
  459. // the status.
  460. //
  461. status = Irp->IoStatus.Status;
  462. }
  463. break;
  464. } else if (type == BusRelations) {
  465. ASSERT(commonExtension->IsInitialized);
  466. //
  467. // Make sure we support enumeration
  468. //
  469. if(initData->ClassEnumerateDevice == NULL) {
  470. //
  471. // Just send the request down to the lower driver. Perhaps
  472. // It can enumerate children.
  473. //
  474. } else {
  475. //
  476. // Re-enumerate the device
  477. //
  478. status = ClassPnpQueryFdoRelations(DeviceObject, Irp);
  479. if(!NT_SUCCESS(status)) {
  480. completeRequest = TRUE;
  481. break;
  482. }
  483. }
  484. }
  485. IoCopyCurrentIrpStackLocationToNext(Irp);
  486. ClassReleaseRemoveLock(DeviceObject, Irp);
  487. status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
  488. completeRequest = FALSE;
  489. break;
  490. }
  491. case IRP_MN_QUERY_ID: {
  492. BUS_QUERY_ID_TYPE idType = irpStack->Parameters.QueryId.IdType;
  493. UNICODE_STRING unicodeString;
  494. if(isFdo) {
  495. //
  496. // FDO's should just forward the query down to the lower
  497. // device objects
  498. //
  499. IoCopyCurrentIrpStackLocationToNext(Irp);
  500. ClassReleaseRemoveLock(DeviceObject, Irp);
  501. status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
  502. completeRequest = FALSE;
  503. break;
  504. }
  505. //
  506. // PDO's need to give an answer - this is easy for now
  507. //
  508. RtlInitUnicodeString(&unicodeString, NULL);
  509. status = ClassGetPdoId(DeviceObject,
  510. idType,
  511. &unicodeString);
  512. if(status == STATUS_NOT_IMPLEMENTED) {
  513. //
  514. // The driver doesn't implement this ID (whatever it is).
  515. // Use the status out of the IRP so that we don't mangle a
  516. // response from someone else.
  517. //
  518. status = Irp->IoStatus.Status;
  519. } else if(NT_SUCCESS(status)) {
  520. Irp->IoStatus.Information = (ULONG_PTR) unicodeString.Buffer;
  521. } else {
  522. Irp->IoStatus.Information = (ULONG_PTR) NULL;
  523. }
  524. break;
  525. }
  526. case IRP_MN_QUERY_STOP_DEVICE:
  527. case IRP_MN_QUERY_REMOVE_DEVICE: {
  528. DebugPrint((2, "ClassDispatchPnp (%p,%p): Processing QUERY_%s irp\n",
  529. DeviceObject, Irp,
  530. ((irpStack->MinorFunction == IRP_MN_QUERY_STOP_DEVICE) ?
  531. "STOP" : "REMOVE")));
  532. //
  533. // If this device is in use for some reason (paging, etc...)
  534. // then we need to fail the request.
  535. //
  536. if(commonExtension->PagingPathCount != 0) {
  537. DebugPrint((1, "ClassDispatchPnp (%p,%p): device is in paging "
  538. "path and cannot be removed\n",
  539. DeviceObject, Irp));
  540. status = STATUS_DEVICE_BUSY;
  541. break;
  542. }
  543. //
  544. // Check with the class driver to see if the query operation
  545. // can succeed.
  546. //
  547. if(irpStack->MinorFunction == IRP_MN_QUERY_STOP_DEVICE) {
  548. status = devInfo->ClassStopDevice(DeviceObject,
  549. irpStack->MinorFunction);
  550. } else {
  551. status = devInfo->ClassRemoveDevice(DeviceObject,
  552. irpStack->MinorFunction);
  553. }
  554. if(NT_SUCCESS(status)) {
  555. //
  556. // ASSERT that we never get two queries in a row, as
  557. // this will severly mess up the state machine
  558. //
  559. ASSERT(commonExtension->CurrentState != irpStack->MinorFunction);
  560. commonExtension->PreviousState = commonExtension->CurrentState;
  561. commonExtension->CurrentState = irpStack->MinorFunction;
  562. if(isFdo) {
  563. DebugPrint((2, "ClassDispatchPnp (%p,%p): Forwarding QUERY_"
  564. "%s irp\n", DeviceObject, Irp,
  565. ((irpStack->MinorFunction == IRP_MN_QUERY_STOP_DEVICE) ?
  566. "STOP" : "REMOVE")));
  567. status = ClassForwardIrpSynchronous(commonExtension, Irp);
  568. }
  569. }
  570. DebugPrint((2, "ClassDispatchPnp (%p,%p): Final status == %x\n",
  571. DeviceObject, Irp, status));
  572. break;
  573. }
  574. case IRP_MN_CANCEL_STOP_DEVICE:
  575. case IRP_MN_CANCEL_REMOVE_DEVICE: {
  576. //
  577. // Check with the class driver to see if the query or cancel
  578. // operation can succeed.
  579. //
  580. if(irpStack->MinorFunction == IRP_MN_CANCEL_STOP_DEVICE) {
  581. status = devInfo->ClassStopDevice(DeviceObject,
  582. irpStack->MinorFunction);
  583. ASSERTMSG("ClassDispatchPnp !! CANCEL_STOP_DEVICE should "
  584. "never be failed\n", NT_SUCCESS(status));
  585. } else {
  586. status = devInfo->ClassRemoveDevice(DeviceObject,
  587. irpStack->MinorFunction);
  588. ASSERTMSG("ClassDispatchPnp !! CANCEL_REMOVE_DEVICE should "
  589. "never be failed\n", NT_SUCCESS(status));
  590. }
  591. Irp->IoStatus.Status = status;
  592. //
  593. // We got a CANCEL - roll back to the previous state only
  594. // if the current state is the respective QUERY state.
  595. //
  596. if(((irpStack->MinorFunction == IRP_MN_CANCEL_STOP_DEVICE) &&
  597. (commonExtension->CurrentState == IRP_MN_QUERY_STOP_DEVICE)
  598. ) ||
  599. ((irpStack->MinorFunction == IRP_MN_CANCEL_REMOVE_DEVICE) &&
  600. (commonExtension->CurrentState == IRP_MN_QUERY_REMOVE_DEVICE)
  601. )
  602. ) {
  603. commonExtension->CurrentState =
  604. commonExtension->PreviousState;
  605. commonExtension->PreviousState = 0xff;
  606. }
  607. if(isFdo) {
  608. IoCopyCurrentIrpStackLocationToNext(Irp);
  609. ClassReleaseRemoveLock(DeviceObject, Irp);
  610. status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
  611. completeRequest = FALSE;
  612. } else {
  613. status = STATUS_SUCCESS;
  614. }
  615. break;
  616. }
  617. case IRP_MN_STOP_DEVICE: {
  618. //
  619. // These all mean nothing to the class driver currently. The
  620. // port driver will handle all queueing when necessary.
  621. //
  622. DebugPrint((2, "ClassDispatchPnp (%p,%p): got stop request for %s\n",
  623. DeviceObject, Irp,
  624. (isFdo ? "fdo" : "pdo")
  625. ));
  626. ASSERT(commonExtension->PagingPathCount == 0);
  627. //
  628. // ISSUE-2000/02/03-peterwie
  629. // if we stop the timer here then it means no class driver can
  630. // do i/o in its ClassStopDevice routine. This is because the
  631. // retry (among other things) is tied into the tick handler
  632. // and disabling retries could cause the class driver to deadlock.
  633. // Currently no class driver we're aware of issues i/o in its
  634. // Stop routine but this is a case we may want to defend ourself
  635. // against.
  636. //
  637. if (DeviceObject->Timer) {
  638. IoStopTimer(DeviceObject);
  639. }
  640. status = devInfo->ClassStopDevice(DeviceObject, IRP_MN_STOP_DEVICE);
  641. ASSERTMSG("ClassDispatchPnp !! STOP_DEVICE should "
  642. "never be failed\n", NT_SUCCESS(status));
  643. if(isFdo) {
  644. status = ClassForwardIrpSynchronous(commonExtension, Irp);
  645. }
  646. if(NT_SUCCESS(status)) {
  647. commonExtension->CurrentState = irpStack->MinorFunction;
  648. commonExtension->PreviousState = 0xff;
  649. }
  650. break;
  651. }
  652. case IRP_MN_REMOVE_DEVICE:
  653. case IRP_MN_SURPRISE_REMOVAL: {
  654. PDEVICE_OBJECT lowerDeviceObject = commonExtension->LowerDeviceObject;
  655. UCHAR removeType = irpStack->MinorFunction;
  656. if (commonExtension->PagingPathCount != 0) {
  657. DBGTRACE(ClassDebugWarning, ("ClassDispatchPnp (%p,%p): paging device is getting removed!", DeviceObject, Irp));
  658. }
  659. //
  660. // Release the lock for this IRP before calling in.
  661. //
  662. ClassReleaseRemoveLock(DeviceObject, Irp);
  663. lockReleased = TRUE;
  664. /*
  665. * If a timer was started on the device, stop it.
  666. */
  667. if (DeviceObject->Timer) {
  668. IoStopTimer(DeviceObject);
  669. }
  670. /*
  671. * "Fire-and-forget" the remove irp to the lower stack.
  672. * Don't touch the irp (or the irp stack!) after this.
  673. */
  674. if (isFdo) {
  675. IoCopyCurrentIrpStackLocationToNext(Irp);
  676. status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
  677. ASSERT(NT_SUCCESS(status));
  678. completeRequest = FALSE;
  679. }
  680. else {
  681. status = STATUS_SUCCESS;
  682. }
  683. /*
  684. * Do our own cleanup and call the class driver's remove
  685. * cleanup routine.
  686. * For IRP_MN_REMOVE_DEVICE, this also deletes our device object,
  687. * so don't touch the extension after this.
  688. */
  689. commonExtension->PreviousState = commonExtension->CurrentState;
  690. commonExtension->CurrentState = removeType;
  691. ClassRemoveDevice(DeviceObject, removeType);
  692. break;
  693. }
  694. case IRP_MN_DEVICE_USAGE_NOTIFICATION: {
  695. switch(irpStack->Parameters.UsageNotification.Type) {
  696. case DeviceUsageTypePaging: {
  697. BOOLEAN setPagable;
  698. if((irpStack->Parameters.UsageNotification.InPath) &&
  699. (commonExtension->CurrentState != IRP_MN_START_DEVICE)) {
  700. //
  701. // Device isn't started. Don't allow adding a
  702. // paging file, but allow a removal of one.
  703. //
  704. status = STATUS_DEVICE_NOT_READY;
  705. break;
  706. }
  707. ASSERT(commonExtension->IsInitialized);
  708. //
  709. // need to synchronize this now...
  710. //
  711. KeEnterCriticalRegion();
  712. status = KeWaitForSingleObject(&commonExtension->PathCountEvent,
  713. Executive, KernelMode,
  714. FALSE, NULL);
  715. ASSERT(NT_SUCCESS(status));
  716. status = STATUS_SUCCESS;
  717. //
  718. // If the volume is removable we should try to lock it in
  719. // place or unlock it once per paging path count
  720. //
  721. if (commonExtension->IsFdo){
  722. status = ClasspEjectionControl(
  723. DeviceObject,
  724. Irp,
  725. InternalMediaLock,
  726. (BOOLEAN)irpStack->Parameters.UsageNotification.InPath);
  727. }
  728. if (!NT_SUCCESS(status)){
  729. KeSetEvent(&commonExtension->PathCountEvent, IO_NO_INCREMENT, FALSE);
  730. KeLeaveCriticalRegion();
  731. break;
  732. }
  733. //
  734. // if removing last paging device, need to set DO_POWER_PAGABLE
  735. // bit here, and possible re-set it below on failure.
  736. //
  737. setPagable = FALSE;
  738. if (!irpStack->Parameters.UsageNotification.InPath &&
  739. commonExtension->PagingPathCount == 1
  740. ) {
  741. //
  742. // removing last paging file
  743. // must have DO_POWER_PAGABLE bits set, but only
  744. // if noone set the DO_POWER_INRUSH bit
  745. //
  746. if (TEST_FLAG(DeviceObject->Flags, DO_POWER_INRUSH)) {
  747. DebugPrint((2, "ClassDispatchPnp (%p,%p): Last "
  748. "paging file removed, but "
  749. "DO_POWER_INRUSH was set, so NOT "
  750. "setting DO_POWER_PAGABLE\n",
  751. DeviceObject, Irp));
  752. } else {
  753. DebugPrint((2, "ClassDispatchPnp (%p,%p): Last "
  754. "paging file removed, "
  755. "setting DO_POWER_PAGABLE\n",
  756. DeviceObject, Irp));
  757. SET_FLAG(DeviceObject->Flags, DO_POWER_PAGABLE);
  758. setPagable = TRUE;
  759. }
  760. }
  761. //
  762. // forward the irp before finishing handling the
  763. // special cases
  764. //
  765. status = ClassForwardIrpSynchronous(commonExtension, Irp);
  766. //
  767. // now deal with the failure and success cases.
  768. // note that we are not allowed to fail the irp
  769. // once it is sent to the lower drivers.
  770. //
  771. if (NT_SUCCESS(status)) {
  772. IoAdjustPagingPathCount(
  773. &commonExtension->PagingPathCount,
  774. irpStack->Parameters.UsageNotification.InPath);
  775. if (irpStack->Parameters.UsageNotification.InPath) {
  776. if (commonExtension->PagingPathCount == 1) {
  777. DebugPrint((2, "ClassDispatchPnp (%p,%p): "
  778. "Clearing PAGABLE bit\n",
  779. DeviceObject, Irp));
  780. CLEAR_FLAG(DeviceObject->Flags, DO_POWER_PAGABLE);
  781. }
  782. }
  783. } else {
  784. //
  785. // cleanup the changes done above
  786. //
  787. if (setPagable == TRUE) {
  788. DebugPrint((2, "ClassDispatchPnp (%p,%p): Unsetting "
  789. "PAGABLE bit due to irp failure\n",
  790. DeviceObject, Irp));
  791. CLEAR_FLAG(DeviceObject->Flags, DO_POWER_PAGABLE);
  792. setPagable = FALSE;
  793. }
  794. //
  795. // relock or unlock the media if needed.
  796. //
  797. if (commonExtension->IsFdo) {
  798. ClasspEjectionControl(
  799. DeviceObject,
  800. Irp,
  801. InternalMediaLock,
  802. (BOOLEAN)!irpStack->Parameters.UsageNotification.InPath);
  803. }
  804. }
  805. //
  806. // set the event so the next one can occur.
  807. //
  808. KeSetEvent(&commonExtension->PathCountEvent,
  809. IO_NO_INCREMENT, FALSE);
  810. KeLeaveCriticalRegion();
  811. break;
  812. }
  813. case DeviceUsageTypeHibernation: {
  814. IoAdjustPagingPathCount(
  815. &commonExtension->HibernationPathCount,
  816. irpStack->Parameters.UsageNotification.InPath
  817. );
  818. status = ClassForwardIrpSynchronous(commonExtension, Irp);
  819. if (!NT_SUCCESS(status)) {
  820. IoAdjustPagingPathCount(
  821. &commonExtension->HibernationPathCount,
  822. !irpStack->Parameters.UsageNotification.InPath
  823. );
  824. }
  825. break;
  826. }
  827. case DeviceUsageTypeDumpFile: {
  828. IoAdjustPagingPathCount(
  829. &commonExtension->DumpPathCount,
  830. irpStack->Parameters.UsageNotification.InPath
  831. );
  832. status = ClassForwardIrpSynchronous(commonExtension, Irp);
  833. if (!NT_SUCCESS(status)) {
  834. IoAdjustPagingPathCount(
  835. &commonExtension->DumpPathCount,
  836. !irpStack->Parameters.UsageNotification.InPath
  837. );
  838. }
  839. break;
  840. }
  841. default: {
  842. status = STATUS_INVALID_PARAMETER;
  843. break;
  844. }
  845. }
  846. break;
  847. }
  848. case IRP_MN_QUERY_CAPABILITIES: {
  849. DebugPrint((2, "ClassDispatchPnp (%p,%p): QueryCapabilities\n",
  850. DeviceObject, Irp));
  851. if(!isFdo) {
  852. status = ClassQueryPnpCapabilities(
  853. DeviceObject,
  854. irpStack->Parameters.DeviceCapabilities.Capabilities
  855. );
  856. break;
  857. } else {
  858. PDEVICE_CAPABILITIES deviceCapabilities;
  859. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
  860. PCLASS_PRIVATE_FDO_DATA fdoData;
  861. fdoExtension = DeviceObject->DeviceExtension;
  862. fdoData = fdoExtension->PrivateFdoData;
  863. deviceCapabilities =
  864. irpStack->Parameters.DeviceCapabilities.Capabilities;
  865. //
  866. // forward the irp before handling the special cases
  867. //
  868. status = ClassForwardIrpSynchronous(commonExtension, Irp);
  869. if (!NT_SUCCESS(status)) {
  870. break;
  871. }
  872. //
  873. // we generally want to remove the device from the hotplug
  874. // applet, which requires the SR-OK bit to be set.
  875. // only when the user specifies that they are capable of
  876. // safely removing things do we want to clear this bit
  877. // (saved in WriteCacheEnableOverride)
  878. //
  879. // setting of this bit is done either above, or by the
  880. // lower driver.
  881. //
  882. // note: may not be started, so check we have FDO data first.
  883. //
  884. if (fdoData &&
  885. fdoData->HotplugInfo.WriteCacheEnableOverride) {
  886. if (deviceCapabilities->SurpriseRemovalOK) {
  887. DebugPrint((1, "Classpnp: Clearing SR-OK bit in "
  888. "device capabilities due to hotplug "
  889. "device or media\n"));
  890. }
  891. deviceCapabilities->SurpriseRemovalOK = FALSE;
  892. }
  893. break;
  894. } // end QUERY_CAPABILITIES for FDOs
  895. ASSERT(FALSE);
  896. break;
  897. } // end QUERY_CAPABILITIES
  898. default: {
  899. if (isFdo){
  900. IoCopyCurrentIrpStackLocationToNext(Irp);
  901. ClassReleaseRemoveLock(DeviceObject, Irp);
  902. status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
  903. completeRequest = FALSE;
  904. }
  905. break;
  906. }
  907. }
  908. }
  909. else {
  910. ASSERT(driverExtension);
  911. status = STATUS_INTERNAL_ERROR;
  912. }
  913. if (completeRequest){
  914. Irp->IoStatus.Status = status;
  915. if (!lockReleased){
  916. ClassReleaseRemoveLock(DeviceObject, Irp);
  917. }
  918. ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
  919. DBGTRACE(ClassDebugTrace, ("ClassDispatchPnp (%p,%p): leaving with previous %#x, current %#x.", DeviceObject, Irp, commonExtension->PreviousState, commonExtension->CurrentState));
  920. }
  921. else {
  922. /*
  923. * The irp is already completed so don't touch it.
  924. * This may be a remove so don't touch the device extension.
  925. */
  926. DBGTRACE(ClassDebugTrace, ("ClassDispatchPnp (%p,%p): leaving.", DeviceObject, Irp));
  927. }
  928. return status;
  929. } // end ClassDispatchPnp()
  930. /*++////////////////////////////////////////////////////////////////////////////
  931. ClassPnpStartDevice()
  932. Routine Description:
  933. Storage class driver routine for IRP_MN_START_DEVICE requests.
  934. This routine kicks off any device specific initialization
  935. Arguments:
  936. DeviceObject - a pointer to the device object
  937. Irp - a pointer to the io request packet
  938. Return Value:
  939. none
  940. --*/
  941. NTSTATUS ClassPnpStartDevice(IN PDEVICE_OBJECT DeviceObject)
  942. {
  943. PCLASS_DRIVER_EXTENSION driverExtension;
  944. PCLASS_INIT_DATA initData;
  945. PCLASS_DEV_INFO devInfo;
  946. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  947. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  948. BOOLEAN isFdo = commonExtension->IsFdo;
  949. BOOLEAN isMountedDevice = TRUE;
  950. UNICODE_STRING interfaceName;
  951. BOOLEAN timerStarted;
  952. NTSTATUS status = STATUS_SUCCESS;
  953. PAGED_CODE();
  954. driverExtension = IoGetDriverObjectExtension(DeviceObject->DriverObject,
  955. CLASS_DRIVER_EXTENSION_KEY);
  956. initData = &(driverExtension->InitData);
  957. if(isFdo) {
  958. devInfo = &(initData->FdoData);
  959. } else {
  960. devInfo = &(initData->PdoData);
  961. }
  962. ASSERT(devInfo->ClassInitDevice != NULL);
  963. ASSERT(devInfo->ClassStartDevice != NULL);
  964. if (!commonExtension->IsInitialized){
  965. //
  966. // perform FDO/PDO specific initialization
  967. //
  968. if (isFdo){
  969. STORAGE_PROPERTY_ID propertyId;
  970. //
  971. // allocate a private extension for class data
  972. //
  973. if (fdoExtension->PrivateFdoData == NULL) {
  974. fdoExtension->PrivateFdoData =
  975. ExAllocatePoolWithTag(NonPagedPool,
  976. sizeof(CLASS_PRIVATE_FDO_DATA),
  977. CLASS_TAG_PRIVATE_DATA
  978. );
  979. }
  980. if (fdoExtension->PrivateFdoData == NULL) {
  981. DebugPrint((0, "ClassPnpStartDevice: Cannot allocate for "
  982. "private fdo data\n"));
  983. return STATUS_INSUFFICIENT_RESOURCES;
  984. }
  985. //
  986. // initialize the struct's various fields.
  987. //
  988. RtlZeroMemory(fdoExtension->PrivateFdoData,
  989. sizeof(CLASS_PRIVATE_FDO_DATA)
  990. );
  991. KeInitializeTimer(&fdoExtension->PrivateFdoData->Retry.Timer);
  992. KeInitializeDpc(&fdoExtension->PrivateFdoData->Retry.Dpc,
  993. ClasspRetryRequestDpc,
  994. DeviceObject);
  995. KeInitializeSpinLock(&fdoExtension->PrivateFdoData->Retry.Lock);
  996. fdoExtension->PrivateFdoData->Retry.Granularity =
  997. KeQueryTimeIncrement();
  998. commonExtension->Reserved4 = (ULONG_PTR)(' GPH'); // debug aid
  999. //
  1000. // NOTE: the old interface allowed the class driver to allocate
  1001. // this. this was unsafe for low-memory conditions. allocate one
  1002. // unconditionally now, and modify our internal functions to use
  1003. // our own exclusively as it is the only safe way to do this.
  1004. //
  1005. status = ClasspAllocateReleaseQueueIrp(fdoExtension);
  1006. if (!NT_SUCCESS(status)) {
  1007. DebugPrint((0, "ClassPnpStartDevice: Cannot allocate the "
  1008. "private release queue irp\n"));
  1009. return status;
  1010. }
  1011. //
  1012. // Call port driver to get adapter capabilities.
  1013. //
  1014. propertyId = StorageAdapterProperty;
  1015. status = ClassGetDescriptor(
  1016. commonExtension->LowerDeviceObject,
  1017. &propertyId,
  1018. &fdoExtension->AdapterDescriptor);
  1019. if(!NT_SUCCESS(status)) {
  1020. //
  1021. // This DebugPrint is to help third-party driver writers
  1022. //
  1023. DebugPrint((0, "ClassPnpStartDevice: ClassGetDescriptor "
  1024. "[ADAPTER] failed %lx\n", status));
  1025. return status;
  1026. }
  1027. //
  1028. // Call port driver to get device descriptor.
  1029. //
  1030. propertyId = StorageDeviceProperty;
  1031. status = ClassGetDescriptor(
  1032. commonExtension->LowerDeviceObject,
  1033. &propertyId,
  1034. &fdoExtension->DeviceDescriptor);
  1035. if(!NT_SUCCESS(status)) {
  1036. //
  1037. // This DebugPrint is to help third-party driver writers
  1038. //
  1039. DebugPrint((0, "ClassPnpStartDevice: ClassGetDescriptor "
  1040. "[DEVICE] failed %lx\n", status));
  1041. return status;
  1042. }
  1043. ClasspScanForSpecialInRegistry(fdoExtension);
  1044. ClassScanForSpecial(fdoExtension,
  1045. ClassBadItems,
  1046. ClasspScanForClassHacks);
  1047. //
  1048. // allow perf to be re-enabled after a given number of failed IOs
  1049. // require this number to be at least CLASS_PERF_RESTORE_MINIMUM
  1050. //
  1051. {
  1052. ULONG t = 0;
  1053. ClassGetDeviceParameter(fdoExtension,
  1054. CLASSP_REG_SUBKEY_NAME,
  1055. CLASSP_REG_PERF_RESTORE_VALUE_NAME,
  1056. &t);
  1057. if (t >= CLASS_PERF_RESTORE_MINIMUM) {
  1058. fdoExtension->PrivateFdoData->Perf.ReEnableThreshhold = t;
  1059. }
  1060. }
  1061. //
  1062. // compatibility comes first. writable cd media will not
  1063. // get a SYNCH_CACHE on power down.
  1064. //
  1065. if (fdoExtension->DeviceObject->DeviceType != FILE_DEVICE_DISK) {
  1066. SET_FLAG(fdoExtension->PrivateFdoData->HackFlags,
  1067. FDO_HACK_NO_SYNC_CACHE);
  1068. }
  1069. //
  1070. // initialize the hotplug information only after the ScanForSpecial
  1071. // routines, as it relies upon the hack flags.
  1072. //
  1073. status = ClasspInitializeHotplugInfo(fdoExtension);
  1074. if (!NT_SUCCESS(status)) {
  1075. DebugPrint((1, "ClassPnpStartDevice: Could not initialize "
  1076. "hotplug information %lx\n", status));
  1077. return status;
  1078. }
  1079. /*
  1080. * Allocate/initialize TRANSFER_PACKETs and related resources.
  1081. */
  1082. status = InitializeTransferPackets(DeviceObject);
  1083. }
  1084. //
  1085. // ISSUE - drivers need to disable write caching on the media
  1086. // if hotplug and !useroverride. perhaps we should
  1087. // allow registration of a callback to enable/disable
  1088. // write cache instead.
  1089. //
  1090. if (NT_SUCCESS(status)){
  1091. status = devInfo->ClassInitDevice(DeviceObject);
  1092. }
  1093. }
  1094. if (!NT_SUCCESS(status)){
  1095. //
  1096. // Just bail out - the remove that comes down will clean up the
  1097. // initialized scraps.
  1098. //
  1099. return status;
  1100. } else {
  1101. commonExtension->IsInitialized = TRUE;
  1102. if (commonExtension->IsFdo) {
  1103. fdoExtension->PrivateFdoData->Perf.OriginalSrbFlags = fdoExtension->SrbFlags;
  1104. }
  1105. }
  1106. //
  1107. // If device requests autorun functionality or a once a second callback
  1108. // then enable the once per second timer.
  1109. //
  1110. // NOTE: This assumes that ClassInitializeMediaChangeDetection is always
  1111. // called in the context of the ClassInitDevice callback. If called
  1112. // after then this check will have already been made and the
  1113. // once a second timer will not have been enabled.
  1114. //
  1115. if ((isFdo) &&
  1116. ((initData-

Large files files are truncated, but you can click here to view the full file