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.

1297 lines
39 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1998 - 1999
  3. Module Name:
  4. pnp.c
  5. Abstract:
  6. This file handles the plug and play portions of redbook.sys
  7. This also handles the AddDevice, DriverEntry, and Unload routines,
  8. as they are part of initialization.
  9. Author:
  10. Henry Gabryjelski (henrygab)
  11. Environment:
  12. kernel mode only
  13. Notes:
  14. Revision History:
  15. --*/
  16. #include "redbook.h"
  17. #include "ntddredb.h"
  18. #include "proto.h"
  19. #ifdef _USE_ETW
  20. #include "pnp.tmh"
  21. #endif // _USE_ETW
  22. #ifdef ALLOC_PRAGMA
  23. #pragma alloc_text(PAGE, DriverEntry )
  24. #pragma alloc_text(PAGE, RedBookAddDevice )
  25. #pragma alloc_text(PAGE, RedBookPnp )
  26. #pragma alloc_text(PAGE, RedBookPnpRemoveDevice )
  27. #pragma alloc_text(PAGE, RedBookPnpStartDevice )
  28. #pragma alloc_text(PAGE, RedBookPnpStopDevice )
  29. #pragma alloc_text(PAGE, RedBookUnload )
  30. #endif // ALLOC_PRAGMA
  31. ////////////////////////////////////////////////////////////////////////////////
  32. NTSTATUS
  33. DriverEntry(
  34. IN PDRIVER_OBJECT DriverObject,
  35. IN PUNICODE_STRING RegistryPath
  36. )
  37. /*++
  38. Routine Description:
  39. Initialize RedBook driver.
  40. This is the system initialization entry point
  41. when the driver is linked into the kernel.
  42. Arguments:
  43. DriverObject
  44. Return Value:
  45. NTSTATUS
  46. --*/
  47. {
  48. ULONG i;
  49. NTSTATUS status;
  50. PREDBOOK_DRIVER_EXTENSION driverExtension;
  51. PAGED_CODE();
  52. #ifdef _USE_ETW
  53. WPP_INIT_TRACING(DriverObject, RegistryPath);
  54. #endif // _USE_ETW
  55. //
  56. // WMI requires registry path
  57. //
  58. status = IoAllocateDriverObjectExtension(DriverObject,
  59. REDBOOK_DRIVER_EXTENSION_ID,
  60. sizeof(REDBOOK_DRIVER_EXTENSION),
  61. &driverExtension);
  62. if (status == STATUS_OBJECT_NAME_COLLISION) {
  63. //
  64. // The extension already exists - get a pointer to it
  65. //
  66. driverExtension = IoGetDriverObjectExtension(DriverObject,
  67. REDBOOK_DRIVER_EXTENSION_ID);
  68. if (driverExtension != NULL)
  69. {
  70. status = STATUS_SUCCESS;
  71. }
  72. }
  73. if (!NT_SUCCESS(status)) {
  74. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugError, "[redbook] "
  75. "DriverEntry !! no drvObjExt %lx\n", status));
  76. return status;
  77. }
  78. //
  79. // Copy the RegistryPath to our newly acquired driverExtension
  80. //
  81. driverExtension->RegistryPath.Buffer =
  82. ExAllocatePoolWithTag(NonPagedPool,
  83. RegistryPath->Length + 2,
  84. TAG_REGPATH);
  85. if (driverExtension->RegistryPath.Buffer == NULL) {
  86. status = STATUS_NO_MEMORY;
  87. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugError, "[redbook] "
  88. "DriverEntry !! unable to alloc regPath %lx\n", status));
  89. return status;
  90. } else {
  91. driverExtension->RegistryPath.Length = RegistryPath->Length;
  92. driverExtension->RegistryPath.MaximumLength = RegistryPath->Length + 2;
  93. RtlCopyUnicodeString(&driverExtension->RegistryPath, RegistryPath);
  94. }
  95. //
  96. // Send everything down unless specifically handled.
  97. //
  98. for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) {
  99. DriverObject->MajorFunction[i] = RedBookSendToNextDriver;
  100. }
  101. //
  102. // These are the only IRP_MJ types that are handled
  103. //
  104. DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = RedBookWmiSystemControl;
  105. DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = RedBookDeviceControl;
  106. DriverObject->MajorFunction[IRP_MJ_READ] = RedBookReadWrite;
  107. DriverObject->MajorFunction[IRP_MJ_WRITE] = RedBookReadWrite;
  108. DriverObject->MajorFunction[IRP_MJ_PNP] = RedBookPnp;
  109. DriverObject->MajorFunction[IRP_MJ_POWER] = RedBookPower;
  110. DriverObject->DriverExtension->AddDevice = RedBookAddDevice;
  111. DriverObject->DriverUnload = RedBookUnload;
  112. return STATUS_SUCCESS;
  113. }
  114. NTSTATUS
  115. RedBookAddDevice(
  116. IN PDRIVER_OBJECT DriverObject,
  117. IN PDEVICE_OBJECT PhysicalDeviceObject
  118. )
  119. /*++
  120. Routine Description:
  121. This routine creates and initializes a new FDO for the
  122. corresponding PDO. It may perform property queries on
  123. the FDO but cannot do any media access operations.
  124. Arguments:
  125. DriverObject - CDROM class driver object or lower level filter
  126. Pdo - the physical device object we are being added to
  127. Return Value:
  128. status
  129. --*/
  130. {
  131. NTSTATUS status;
  132. PDEVICE_OBJECT deviceObject;
  133. PREDBOOK_DEVICE_EXTENSION extension = NULL;
  134. ULONG i;
  135. PAGED_CODE();
  136. TRY {
  137. //
  138. // Create the devObj so system doesn't unload us
  139. //
  140. status = IoCreateDevice(DriverObject,
  141. sizeof(REDBOOK_DEVICE_EXTENSION),
  142. NULL,
  143. FILE_DEVICE_CD_ROM,
  144. 0,
  145. FALSE,
  146. &deviceObject
  147. );
  148. if (!NT_SUCCESS(status)) {
  149. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugError, "[redbook] "
  150. "AddDevice !! Couldn't create device %lx\n",
  151. status));
  152. LEAVE;
  153. }
  154. extension = deviceObject->DeviceExtension;
  155. RtlZeroMemory(extension, sizeof(REDBOOK_DEVICE_EXTENSION));
  156. //
  157. // Attach to the stack
  158. //
  159. extension->TargetDeviceObject =
  160. IoAttachDeviceToDeviceStack(deviceObject, PhysicalDeviceObject);
  161. if (extension->TargetDeviceObject == NULL) {
  162. status = STATUS_UNSUCCESSFUL;
  163. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugError, "[redbook] "
  164. "AddDevice != Couldn't attach to stack %lx\n",
  165. status));
  166. LEAVE;
  167. }
  168. extension->DriverObject = DriverObject;
  169. extension->TargetPdo = PhysicalDeviceObject;
  170. extension->SelfDeviceObject = deviceObject;
  171. //
  172. // prepare the paging path additions
  173. //
  174. extension->PagingPathCount = 0;
  175. KeInitializeEvent(&extension->PagingPathEvent,
  176. SynchronizationEvent,
  177. TRUE);
  178. //
  179. // Create and acquire a remove lock for this device
  180. //
  181. IoInitializeRemoveLock(&extension->RemoveLock,
  182. TAG_REMLOCK,
  183. REMOVE_LOCK_MAX_MINUTES,
  184. REMOVE_LOCK_HIGH_MARK);
  185. //
  186. // Initialize the Pnp states
  187. //
  188. extension->Pnp.CurrentState = 0xff;
  189. extension->Pnp.PreviousState = 0xff;
  190. extension->Pnp.RemovePending = FALSE;
  191. //
  192. // Create thread -- PUT INTO SEPERATE ROUTINE
  193. //
  194. {
  195. HANDLE handle;
  196. PKTHREAD thread;
  197. //
  198. // have to setup a minimum amount of stuff for the thread
  199. // here....
  200. //
  201. extension->CDRom.StateNow = CD_STOPPED;
  202. //
  203. // Allocate memory for the numerous events all at once
  204. //
  205. extension->Thread.Events[0] =
  206. ExAllocatePoolWithTag(NonPagedPool,
  207. sizeof(KEVENT) * EVENT_MAXIMUM,
  208. TAG_EVENTS);
  209. if (extension->Thread.Events[0] == NULL) {
  210. status = STATUS_NO_MEMORY;
  211. LEAVE;
  212. }
  213. //
  214. // Set the pointers appropriately
  215. // ps - i love pointer math
  216. //
  217. for (i = 1; i < EVENT_MAXIMUM; i++) {
  218. extension->Thread.Events[i] = extension->Thread.Events[0] + i;
  219. }
  220. InitializeListHead( &extension->Thread.IoctlList);
  221. KeInitializeSpinLock(&extension->Thread.IoctlLock);
  222. InitializeListHead( &extension->Thread.WmiList);
  223. KeInitializeSpinLock(&extension->Thread.WmiLock);
  224. InitializeListHead( &extension->Thread.DigitalList);
  225. KeInitializeSpinLock(&extension->Thread.DigitalLock);
  226. extension->Thread.IoctlCurrent = NULL;
  227. for ( i = 0; i < EVENT_MAXIMUM; i++) {
  228. KeInitializeEvent(extension->Thread.Events[i],
  229. SynchronizationEvent,
  230. FALSE);
  231. }
  232. ASSERT(extension->Thread.SelfPointer == NULL);
  233. ASSERT(extension->Thread.SelfHandle == 0);
  234. //
  235. // create the thread that will do most of the work
  236. //
  237. status = PsCreateSystemThread(&handle,
  238. (ACCESS_MASK) 0L,
  239. NULL, NULL, NULL,
  240. RedBookSystemThread,
  241. extension);
  242. if (!NT_SUCCESS(status)) {
  243. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugError, "[redbook] "
  244. "StartDevice !! Unable to create thread %lx\n",
  245. status));
  246. RedBookLogError(extension,
  247. REDBOOK_ERR_CANNOT_CREATE_THREAD,
  248. status);
  249. LEAVE;
  250. }
  251. ASSERT(extension->Thread.SelfHandle == 0); // shouldn't be set yet
  252. extension->Thread.SelfHandle = handle;
  253. //
  254. // Reference the thread so we can properly wait on it in
  255. // the remove device routine.
  256. //
  257. status = ObReferenceObjectByHandle(handle,
  258. THREAD_ALL_ACCESS,
  259. NULL,
  260. KernelMode,
  261. &thread,
  262. NULL);
  263. if (!NT_SUCCESS(status)) {
  264. //
  265. // NOTE: we would leak a thread here, but don't
  266. // know a way to handle this error case?
  267. //
  268. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugError, "[redbook] "
  269. "StartDevice !! Unable to reference thread %lx\n",
  270. status));
  271. RedBookLogError(extension,
  272. REDBOOK_ERR_CANNOT_CREATE_THREAD,
  273. status);
  274. LEAVE;
  275. }
  276. extension->Thread.ThreadReference = thread;
  277. }
  278. } FINALLY {
  279. if (!NT_SUCCESS(status)) {
  280. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugError, "[redbook] "
  281. "AddDevice !! Failed with status %lx\n",
  282. status));
  283. if (!deviceObject) {
  284. //
  285. // same as no device extension
  286. //
  287. return status;
  288. }
  289. if (extension &&
  290. extension->Thread.Events[0]) {
  291. ExFreePool(extension->Thread.Events[0]);
  292. }
  293. if (extension &&
  294. extension->TargetDeviceObject) {
  295. IoDetachDevice(extension->TargetDeviceObject);
  296. }
  297. IoDeleteDevice( deviceObject );
  298. return status;
  299. }
  300. }
  301. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugPnp, "[redbook] "
  302. "AddDevice => DevExt at %p\n", extension));
  303. //
  304. // propogate only some flags from the lower devobj.
  305. //
  306. {
  307. ULONG flagsToPropogate;
  308. flagsToPropogate = DO_BUFFERED_IO | DO_DIRECT_IO;
  309. flagsToPropogate &= extension->TargetDeviceObject->Flags;
  310. SET_FLAG(deviceObject->Flags, flagsToPropogate);
  311. }
  312. SET_FLAG(deviceObject->Flags, DO_POWER_PAGABLE);
  313. //
  314. // No longer initializing
  315. //
  316. CLEAR_FLAG(deviceObject->Flags, DO_DEVICE_INITIALIZING);
  317. return STATUS_SUCCESS;
  318. }
  319. NTSTATUS
  320. RedBookPnp(
  321. IN PDEVICE_OBJECT DeviceObject,
  322. IN PIRP Irp
  323. )
  324. /*++
  325. Routine Description:
  326. Dispatch for PNP
  327. Arguments:
  328. DeviceObject - Supplies the device object.
  329. Irp - Supplies the I/O request packet.
  330. Return Value:
  331. NTSTATUS
  332. --*/
  333. {
  334. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  335. NTSTATUS status;
  336. PREDBOOK_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  337. PDEVICE_OBJECT targetDO = deviceExtension->TargetDeviceObject;
  338. ULONG cdromState;
  339. BOOLEAN completeRequest;
  340. BOOLEAN lockReleased;
  341. PAGED_CODE();
  342. status = IoAcquireRemoveLock(&deviceExtension->RemoveLock, Irp);
  343. if (!NT_SUCCESS(status)) {
  344. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugPnp, "[redbook] "
  345. "Pnp !! Remove lock failed PNP Irp type [%#02x]\n",
  346. irpSp->MinorFunction));
  347. Irp->IoStatus.Information = 0;
  348. Irp->IoStatus.Status = status;
  349. IoCompleteRequest(Irp, IO_CD_ROM_INCREMENT);
  350. return status;
  351. }
  352. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugPnp, "[redbook] "
  353. "Pnp (%p,%p,%x) => Entering previous %x current %x\n",
  354. DeviceObject, Irp, irpSp->MinorFunction,
  355. deviceExtension->Pnp.PreviousState,
  356. deviceExtension->Pnp.CurrentState));
  357. lockReleased = FALSE;
  358. completeRequest = TRUE;
  359. switch (irpSp->MinorFunction) {
  360. case IRP_MN_START_DEVICE:
  361. {
  362. //
  363. // first forward this down
  364. //
  365. status = RedBookForwardIrpSynchronous(deviceExtension, Irp);
  366. //
  367. // check status from new sent Start Irp
  368. //
  369. if (!NT_SUCCESS(status)) {
  370. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugPnp, "[redbook] "
  371. "Pnp (%p,%p,%x) => failed start status = %x\n",
  372. DeviceObject, Irp, irpSp->MinorFunction, status));
  373. break;
  374. }
  375. //
  376. // cannot pass this one down either, since it's already
  377. // done that in the startdevice routine.
  378. //
  379. status = RedBookPnpStartDevice(DeviceObject);
  380. if (NT_SUCCESS(status)) {
  381. deviceExtension->Pnp.PreviousState =
  382. deviceExtension->Pnp.CurrentState;
  383. deviceExtension->Pnp.CurrentState =
  384. irpSp->MinorFunction;
  385. }
  386. break;
  387. }
  388. case IRP_MN_QUERY_REMOVE_DEVICE:
  389. case IRP_MN_QUERY_STOP_DEVICE:
  390. {
  391. //
  392. // if this device is in use for some reason (paging, etc...)
  393. // then we need to fail the request.
  394. //
  395. if (deviceExtension->PagingPathCount != 0) {
  396. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugPnp, "[redbook] "
  397. "Device %p is in the paging path and cannot "
  398. "be removed\n",
  399. DeviceObject));
  400. status = STATUS_DEVICE_BUSY;
  401. break;
  402. }
  403. //
  404. // see if the query operation can succeed
  405. //
  406. if (irpSp->MinorFunction == IRP_MN_QUERY_STOP_DEVICE) {
  407. status = RedBookPnpStopDevice(DeviceObject, Irp);
  408. } else {
  409. status = RedBookPnpRemoveDevice(DeviceObject, Irp);
  410. }
  411. if (NT_SUCCESS(status)) {
  412. ASSERT(deviceExtension->Pnp.CurrentState != irpSp->MinorFunction);
  413. deviceExtension->Pnp.PreviousState =
  414. deviceExtension->Pnp.CurrentState;
  415. deviceExtension->Pnp.CurrentState =
  416. irpSp->MinorFunction;
  417. status = RedBookForwardIrpSynchronous(deviceExtension, Irp);
  418. }
  419. break;
  420. }
  421. case IRP_MN_CANCEL_REMOVE_DEVICE:
  422. case IRP_MN_CANCEL_STOP_DEVICE: {
  423. //
  424. // check if the cancel can succeed
  425. //
  426. if (irpSp->MinorFunction == IRP_MN_CANCEL_STOP_DEVICE) {
  427. status = RedBookPnpStopDevice(DeviceObject, Irp);
  428. ASSERTMSG("Pnp !! CANCEL_STOP_DEVICE should never be "
  429. " failed!\n", NT_SUCCESS(status));
  430. } else {
  431. status = RedBookPnpRemoveDevice(DeviceObject, Irp);
  432. ASSERTMSG("Pnp !! CANCEL_REMOVE_DEVICE should never be "
  433. "failed!\n", NT_SUCCESS(status));
  434. }
  435. Irp->IoStatus.Status = status;
  436. //
  437. // we got a CANCEL -- roll back to the previous state only if
  438. // the current state is the respective QUERY state.
  439. //
  440. if ((irpSp->MinorFunction == IRP_MN_CANCEL_STOP_DEVICE &&
  441. deviceExtension->Pnp.CurrentState == IRP_MN_QUERY_STOP_DEVICE)
  442. ||
  443. (irpSp->MinorFunction == IRP_MN_CANCEL_REMOVE_DEVICE &&
  444. deviceExtension->Pnp.CurrentState == IRP_MN_QUERY_REMOVE_DEVICE)
  445. ) {
  446. deviceExtension->Pnp.CurrentState =
  447. deviceExtension->Pnp.PreviousState;
  448. deviceExtension->Pnp.PreviousState = 0xff;
  449. }
  450. status = RedBookForwardIrpSynchronous(deviceExtension, Irp);
  451. break;
  452. }
  453. case IRP_MN_STOP_DEVICE: {
  454. ASSERT(deviceExtension->PagingPathCount == 0);
  455. //
  456. // call into the stop device routine.
  457. //
  458. status = RedBookPnpStopDevice(DeviceObject, Irp);
  459. ASSERTMSG("[redbook] Pnp !! STOP_DEVICE should never be failed\n",
  460. NT_SUCCESS(status));
  461. status = RedBookForwardIrpSynchronous(deviceExtension, Irp);
  462. if (NT_SUCCESS(status)) {
  463. deviceExtension->Pnp.CurrentState = irpSp->MinorFunction;
  464. deviceExtension->Pnp.PreviousState = 0xff;
  465. }
  466. break;
  467. }
  468. case IRP_MN_REMOVE_DEVICE:
  469. case IRP_MN_SURPRISE_REMOVAL: {
  470. //
  471. // forward the irp (to close pending io)
  472. //
  473. status = RedBookForwardIrpSynchronous(deviceExtension, Irp);
  474. ASSERT(NT_SUCCESS(status));
  475. //
  476. // move this here so i know that i am removing....
  477. //
  478. deviceExtension->Pnp.PreviousState =
  479. deviceExtension->Pnp.CurrentState;
  480. deviceExtension->Pnp.CurrentState =
  481. irpSp->MinorFunction;
  482. //
  483. // the remove lock is released by the remove device routine
  484. //
  485. lockReleased = TRUE;
  486. status = RedBookPnpRemoveDevice(DeviceObject, Irp);
  487. ASSERTMSG("Pnp !! REMOVE_DEVICE should never fail!\n",
  488. NT_SUCCESS(status));
  489. status = STATUS_SUCCESS;
  490. break;
  491. }
  492. case IRP_MN_DEVICE_USAGE_NOTIFICATION: {
  493. KEVENT event;
  494. BOOLEAN setPagable;
  495. if (irpSp->Parameters.UsageNotification.Type != DeviceUsageTypePaging) {
  496. status = RedBookForwardIrpSynchronous(deviceExtension, Irp);
  497. break; // out of case statement
  498. }
  499. KeWaitForSingleObject(&deviceExtension->PagingPathEvent,
  500. Executive, KernelMode,
  501. FALSE, NULL);
  502. //
  503. // if removing last paging device, need to set DO_POWER_PAGABLE
  504. // bit here, and possible re-set it below on failure.
  505. //
  506. setPagable = FALSE;
  507. if (!irpSp->Parameters.UsageNotification.InPath &&
  508. deviceExtension->PagingPathCount == 1) {
  509. //
  510. // removing last paging file. must have
  511. // DO_POWER_PAGABLE bits set prior to forwarding
  512. //
  513. if (TEST_FLAG(DeviceObject->Flags, DO_POWER_INRUSH)) {
  514. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugPnp, "[redbook] "
  515. "Pnp (%p,%p,%x) => Last paging file"
  516. " removed, but DO_POWER_INRUSH set, so "
  517. "not setting DO_POWER_PAGABLE\n",
  518. DeviceObject, Irp, irpSp->MinorFunction));
  519. } else {
  520. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugPnp, "[redbook] "
  521. "Pnp (%p,%p,%x) => Setting PAGABLE "
  522. "bit\n", DeviceObject, Irp,
  523. irpSp->MinorFunction));
  524. SET_FLAG(DeviceObject->Flags, DO_POWER_PAGABLE);
  525. setPagable = TRUE;
  526. }
  527. }
  528. //
  529. // send the irp synchronously
  530. //
  531. status = RedBookForwardIrpSynchronous(deviceExtension, Irp);
  532. //
  533. // now deal with the failure and success cases.
  534. // note that we are not allowed to fail the irp
  535. // once it is sent to the lower drivers.
  536. //
  537. if (NT_SUCCESS(status)) {
  538. IoAdjustPagingPathCount(
  539. &deviceExtension->PagingPathCount,
  540. irpSp->Parameters.UsageNotification.InPath);
  541. if (irpSp->Parameters.UsageNotification.InPath) {
  542. if (deviceExtension->PagingPathCount == 1) {
  543. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugPnp, "[redbook] "
  544. "Pnp (%p,%p,%x) => Clearing PAGABLE "
  545. "bit\n", DeviceObject, Irp,
  546. irpSp->MinorFunction));
  547. CLEAR_FLAG(DeviceObject->Flags, DO_POWER_PAGABLE);
  548. }
  549. }
  550. } else {
  551. //
  552. // cleanup the changes done above
  553. //
  554. if (setPagable == TRUE) {
  555. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugPnp, "[redbook] "
  556. "Pnp (%p,%p,%x) => Clearing PAGABLE bit "
  557. "due to irp failiing (%x)\n",
  558. DeviceObject, Irp, irpSp->MinorFunction,
  559. status));
  560. CLEAR_FLAG(DeviceObject->Flags, DO_POWER_PAGABLE);
  561. setPagable = FALSE;
  562. }
  563. }
  564. KeSetEvent(&deviceExtension->PagingPathEvent,
  565. IO_NO_INCREMENT, FALSE);
  566. break;
  567. }
  568. default: {
  569. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugPnp, "[redbook] "
  570. "Pnp (%p,%p,%x) => Leaving previous %x "
  571. "current %x (unhandled)\n",
  572. DeviceObject, Irp, irpSp->MinorFunction,
  573. deviceExtension->Pnp.PreviousState,
  574. deviceExtension->Pnp.CurrentState));
  575. status = RedBookSendToNextDriver(DeviceObject, Irp);
  576. IoReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  577. completeRequest = FALSE;
  578. lockReleased = TRUE;
  579. break;
  580. }
  581. }
  582. if (completeRequest) {
  583. if (!lockReleased) {
  584. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugPnp, "[redbook] "
  585. "Pnp (%p,%p,%x) => Leaving previous %x "
  586. "current %x status %x\n",
  587. DeviceObject, Irp, irpSp->MinorFunction,
  588. deviceExtension->Pnp.PreviousState,
  589. deviceExtension->Pnp.CurrentState,
  590. status));
  591. } else {
  592. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugPnp, "[redbook] "
  593. "Pnp (%p,%p,%x) => Leaving with released lock (unsafe "
  594. "to use device extension for states) status %x\n",
  595. DeviceObject, Irp, irpSp->MinorFunction, status));
  596. }
  597. Irp->IoStatus.Status = status;
  598. IoCompleteRequest(Irp, IO_CD_ROM_INCREMENT);
  599. if (!lockReleased) {
  600. IoReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  601. }
  602. }
  603. return status;
  604. }
  605. NTSTATUS
  606. RedBookPnpRemoveDevice(
  607. IN PDEVICE_OBJECT DeviceObject,
  608. IN PIRP Irp
  609. )
  610. /*++
  611. Routine Description:
  612. Dispatch for PNP
  613. Arguments:
  614. DeviceObject - Supplies the device object.
  615. Irp - Supplies the I/O request packet.
  616. Return Value:
  617. NTSTATUS
  618. --*/
  619. {
  620. PREDBOOK_DEVICE_EXTENSION deviceExtension;
  621. UCHAR type;
  622. NTSTATUS status;
  623. ULONG i;
  624. PAGED_CODE();
  625. type = IoGetCurrentIrpStackLocation(Irp)->MinorFunction;
  626. if (type == IRP_MN_QUERY_REMOVE_DEVICE ||
  627. type == IRP_MN_CANCEL_REMOVE_DEVICE) {
  628. return STATUS_SUCCESS;
  629. }
  630. //
  631. // Type is now either SURPRISE_REMOVAL or REMOVE_DEVICE
  632. //
  633. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugPnp, "[redbook] "
  634. "PnpRemove => starting %s\n",
  635. (type == IRP_MN_REMOVE_DEVICE ?
  636. "remove device" : "surprise removal")));
  637. deviceExtension = DeviceObject->DeviceExtension;
  638. deviceExtension->Pnp.RemovePending = TRUE;
  639. if (type == IRP_MN_REMOVE_DEVICE) {
  640. //
  641. // prevent any new io
  642. //
  643. IoReleaseRemoveLockAndWait(&deviceExtension->RemoveLock, Irp);
  644. //
  645. // cleanup the thread, if one exists
  646. // NOTE: a new one won't start due to the remove lock
  647. //
  648. if (deviceExtension->Thread.SelfHandle != NULL) {
  649. ASSERT(deviceExtension->Thread.ThreadReference);
  650. //
  651. // there is no API to wait on a handle, so we must wait on
  652. // the object.
  653. //
  654. KeSetEvent(deviceExtension->Thread.Events[EVENT_KILL_THREAD],
  655. IO_CD_ROM_INCREMENT, FALSE);
  656. KeWaitForSingleObject(deviceExtension->Thread.ThreadReference,
  657. Executive, KernelMode,
  658. FALSE, NULL);
  659. ObDereferenceObject(deviceExtension->Thread.ThreadReference);
  660. deviceExtension->Thread.ThreadReference = NULL;
  661. ZwClose(deviceExtension->Thread.SelfHandle);
  662. deviceExtension->Thread.SelfHandle = 0;
  663. deviceExtension->Thread.SelfPointer = NULL;
  664. }
  665. //
  666. // un-register pnp notification
  667. //
  668. if (deviceExtension->Stream.SysAudioReg != NULL) {
  669. IoUnregisterPlugPlayNotification(deviceExtension->Stream.SysAudioReg);
  670. deviceExtension->Stream.SysAudioReg = NULL;
  671. }
  672. //
  673. // free any cached toc
  674. //
  675. if (deviceExtension->CDRom.Toc != NULL) {
  676. ExFreePool(deviceExtension->CDRom.Toc);
  677. deviceExtension->CDRom.Toc = NULL;
  678. }
  679. //
  680. // de-register from wmi
  681. //
  682. if (deviceExtension->WmiLibInitialized) {
  683. status = RedBookWmiUninit(deviceExtension);
  684. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugPnp, "[redbook] "
  685. "PnpRemove => WMI Uninit returned %x\n", status));
  686. deviceExtension->WmiLibInitialized = FALSE;
  687. }
  688. //
  689. // Detach from the device stack
  690. //
  691. IoDetachDevice(deviceExtension->TargetDeviceObject);
  692. deviceExtension->TargetDeviceObject = NULL;
  693. //
  694. // free the events
  695. //
  696. if (deviceExtension->Thread.Events[0]) {
  697. ExFreePool(deviceExtension->Thread.Events[0]);
  698. }
  699. for (i=0;i<EVENT_MAXIMUM;i++) {
  700. deviceExtension->Thread.Events[i] = NULL;
  701. }
  702. //
  703. // make sure we aren't leaking anywhere...
  704. //
  705. ASSERT(deviceExtension->Buffer.Contexts == NULL);
  706. ASSERT(deviceExtension->Buffer.ReadOk_X == NULL);
  707. ASSERT(deviceExtension->Buffer.StreamOk_X == NULL);
  708. //
  709. // Now can safely (without leaks) delete our device object
  710. //
  711. IoDeleteDevice(deviceExtension->SelfDeviceObject);
  712. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugPnp, "[redbook] "
  713. "PnpRemove => REMOVE_DEVICE finished.\n"));
  714. } else {
  715. //
  716. // do nothing for a SURPRISE_REMOVAL, since a REMOVE_DEVICE
  717. // will soon follow.
  718. //
  719. IoReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  720. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugPnp, "[redbook] "
  721. "PnpRemove => SURPRISE_REMOVAL finished.\n"));
  722. }
  723. return STATUS_SUCCESS;
  724. }
  725. NTSTATUS
  726. RedBookPnpStopDevice(
  727. IN PDEVICE_OBJECT DeviceObject,
  728. IN PIRP Irp
  729. )
  730. {
  731. PAGED_CODE();
  732. return STATUS_SUCCESS;
  733. }
  734. NTSTATUS
  735. RedBookPnpStartDevice(
  736. IN PDEVICE_OBJECT DeviceObject
  737. )
  738. /*++
  739. Routine Description:
  740. Dispatch for START DEVICE.
  741. Arguments:
  742. DeviceObject - Supplies the device object.
  743. Irp - Supplies the I/O request packet.
  744. Return Value:
  745. NTSTATUS
  746. --*/
  747. {
  748. PREDBOOK_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  749. NTSTATUS status;
  750. ULONG i;
  751. PAGED_CODE();
  752. //
  753. // Never start my driver portion twice
  754. // system guarantees one Pnp Irp at a time,
  755. // so state will not change within this routine
  756. //
  757. switch ( deviceExtension->Pnp.CurrentState ) {
  758. case 0xff:
  759. case IRP_MN_STOP_DEVICE: {
  760. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugPnp, "[redbook] "
  761. "StartDevice => starting driver for devobj %p\n",
  762. DeviceObject));
  763. break;
  764. }
  765. case IRP_MN_START_DEVICE: {
  766. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugPnp, "[redbook] "
  767. "StartDevice => already started for devobj %p\n",
  768. DeviceObject));
  769. return STATUS_SUCCESS;
  770. }
  771. case IRP_MN_QUERY_REMOVE_DEVICE: {
  772. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugPnp, "[redbook] "
  773. "StartDevice !! remove pending for devobj %p\n",
  774. DeviceObject));
  775. return STATUS_UNSUCCESSFUL;
  776. }
  777. case IRP_MN_QUERY_STOP_DEVICE: {
  778. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugPnp, "[redbook] "
  779. "StartDevice !! stop pending for devobj %p\n",
  780. DeviceObject));
  781. return STATUS_UNSUCCESSFUL;
  782. }
  783. default: {
  784. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugError, "[redbook] "
  785. "StartDevice !! unknown DeviceState for devobj %p\n",
  786. DeviceObject));
  787. ASSERT(!"[RedBook] Pnp !! Unkown Device State");
  788. return STATUS_UNSUCCESSFUL;
  789. }
  790. }
  791. if (deviceExtension->Pnp.Initialized) {
  792. return STATUS_SUCCESS;
  793. }
  794. //
  795. // the following code will only successfully run once for each AddDevice()
  796. // must still ensure that we check if something is already allocated
  797. // if we allocate it here. also note that everything allocated here must
  798. // explicitly be checked for in the RemoveDevice() routine, even if we
  799. // never finished a start successfully.
  800. //
  801. deviceExtension->WmiData.MaximumSectorsPerRead = -1;
  802. deviceExtension->WmiData.PlayEnabled = 1;
  803. ASSERT(deviceExtension->CDRom.Toc == NULL);
  804. if (deviceExtension->CDRom.Toc != NULL) {
  805. ExFreePool(deviceExtension->CDRom.Toc);
  806. }
  807. ASSERT(deviceExtension->Buffer.ReadOk_X == NULL);
  808. ASSERT(deviceExtension->Buffer.StreamOk_X == NULL);
  809. ASSERT(deviceExtension->Buffer.Contexts == NULL);
  810. RtlZeroMemory(&deviceExtension->Stream, sizeof(REDBOOK_STREAM_DATA));
  811. deviceExtension->Stream.MixerPinId = -1;
  812. deviceExtension->Stream.VolumeNodeId = -1;
  813. deviceExtension->Stream.Connect.Interface.Set = KSINTERFACESETID_Standard;
  814. deviceExtension->Stream.Connect.Interface.Id = KSINTERFACE_STANDARD_STREAMING;
  815. deviceExtension->Stream.Connect.Interface.Flags = 0;
  816. deviceExtension->Stream.Connect.Medium.Set = KSMEDIUMSETID_Standard;
  817. deviceExtension->Stream.Connect.Medium.Id = KSMEDIUM_STANDARD_DEVIO;
  818. deviceExtension->Stream.Connect.Medium.Flags = 0;
  819. deviceExtension->Stream.Connect.Priority.PriorityClass = KSPRIORITY_NORMAL;
  820. deviceExtension->Stream.Connect.Priority.PrioritySubClass = 1;
  821. deviceExtension->Stream.Format.DataFormat.MajorFormat = KSDATAFORMAT_TYPE_AUDIO;
  822. deviceExtension->Stream.Format.DataFormat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
  823. deviceExtension->Stream.Format.DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;
  824. deviceExtension->Stream.Format.DataFormat.FormatSize = sizeof( KSDATAFORMAT_WAVEFORMATEX );
  825. deviceExtension->Stream.Format.DataFormat.Reserved = 0;
  826. deviceExtension->Stream.Format.DataFormat.Flags = 0;
  827. deviceExtension->Stream.Format.DataFormat.SampleSize = 0;
  828. deviceExtension->Stream.Format.WaveFormatEx.wFormatTag = WAVE_FORMAT_PCM;
  829. deviceExtension->Stream.Format.WaveFormatEx.nChannels = 2;
  830. deviceExtension->Stream.Format.WaveFormatEx.nSamplesPerSec = 44100;
  831. deviceExtension->Stream.Format.WaveFormatEx.wBitsPerSample = 16;
  832. deviceExtension->Stream.Format.WaveFormatEx.nAvgBytesPerSec = 44100*4;
  833. deviceExtension->Stream.Format.WaveFormatEx.nBlockAlign = 4;
  834. deviceExtension->Stream.Format.WaveFormatEx.cbSize = 0;
  835. //
  836. // set the volume, verify we're stopped
  837. //
  838. ASSERT(deviceExtension->CDRom.StateNow == CD_STOPPED);
  839. deviceExtension->CDRom.Volume.PortVolume[0] = 0xff;
  840. deviceExtension->CDRom.Volume.PortVolume[1] = 0xff;
  841. deviceExtension->CDRom.Volume.PortVolume[2] = 0xff;
  842. deviceExtension->CDRom.Volume.PortVolume[3] = 0xff;
  843. //
  844. // Register for Pnp Notifications for SysAudio
  845. //
  846. ASSERT(deviceExtension->Stream.SysAudioReg == NULL);
  847. //
  848. // read the defaults from the registry
  849. //
  850. RedBookRegistryRead(deviceExtension);
  851. //
  852. // get max transfer of adapter
  853. //
  854. status = RedBookSetTransferLength(deviceExtension);
  855. if (!NT_SUCCESS(status)){
  856. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugError, "[redbook] RedBookSetTransferLength failed with %x\n", status));
  857. return status;
  858. }
  859. //
  860. // and write the new values (just in case)
  861. //
  862. RedBookRegistryWrite(deviceExtension);
  863. //
  864. // also init the WmiPerf structure
  865. //
  866. KeInitializeSpinLock(&deviceExtension->WmiPerfLock);
  867. RtlZeroMemory(&deviceExtension->WmiPerf, sizeof(REDBOOK_WMI_PERF_DATA));
  868. //
  869. // Note dependency in OpenSysAudio() in sysaudio.c
  870. //
  871. if (deviceExtension->Stream.SysAudioReg == NULL) {
  872. status = IoRegisterPlugPlayNotification(
  873. EventCategoryDeviceInterfaceChange,
  874. PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
  875. (GUID*)&KSCATEGORY_PREFERRED_WAVEOUT_DEVICE,
  876. deviceExtension->DriverObject,
  877. SysAudioPnpNotification,
  878. deviceExtension,
  879. &deviceExtension->Stream.SysAudioReg
  880. );
  881. if (!NT_SUCCESS(status)) {
  882. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugError, "[redbook] "
  883. "StartDevice !! Unable to register for sysaudio pnp "
  884. "notifications %x\n", status));
  885. deviceExtension->Stream.SysAudioReg = NULL;
  886. return status;
  887. }
  888. }
  889. //
  890. // initialize WMI now that wmi settings are initialized
  891. //
  892. status = RedBookWmiInit(deviceExtension);
  893. if (!NT_SUCCESS(status)) {
  894. RedBookLogError(deviceExtension,
  895. REDBOOK_ERR_WMI_INIT_FAILED,
  896. status);
  897. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugError, "[redbook] "
  898. "AddDevice !! WMI Init failed %lx\n",
  899. status));
  900. return status;
  901. }
  902. //
  903. // log an error if drive doesn't support accurate reads
  904. //
  905. if (!deviceExtension->WmiData.CDDAAccurate) {
  906. RedBookLogError(deviceExtension,
  907. REDBOOK_ERR_UNSUPPORTED_DRIVE,
  908. STATUS_SUCCESS);
  909. }
  910. #if DBG
  911. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugPnp, "[redbook] "
  912. "StartDevice => DO %p SavedIoIndex @ %p Starts @ %p "
  913. "Each is %x bytes in size\n",
  914. DeviceObject,
  915. &deviceExtension->SavedIoCurrentIndex,
  916. &(deviceExtension->SavedIo[0]),
  917. sizeof(SAVED_IO)));
  918. #endif
  919. deviceExtension->Pnp.Initialized = TRUE;
  920. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugPnp, "[redbook] "
  921. "StartDevice => Finished Initialization\n"));
  922. return STATUS_SUCCESS;
  923. }
  924. VOID
  925. RedBookUnload(
  926. IN PDRIVER_OBJECT DriverObject
  927. )
  928. /*++
  929. Routine Description:
  930. This routine is called when the control panel "Unloads"
  931. the CDROM device.
  932. Arguments:
  933. DeviceObject
  934. Return Value:
  935. void
  936. --*/
  937. {
  938. PREDBOOK_DRIVER_EXTENSION driverExtension;
  939. PAGED_CODE();
  940. ASSERT( DriverObject->DeviceObject == NULL );
  941. driverExtension = IoGetDriverObjectExtension(DriverObject,
  942. REDBOOK_DRIVER_EXTENSION_ID);
  943. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugPnp, "[redbook] "
  944. "Unload => Unloading for DriverObject %p, ext %p\n",
  945. DriverObject, driverExtension));
  946. if (driverExtension != NULL &&
  947. driverExtension->RegistryPath.Buffer != NULL ) {
  948. ExFreePool( driverExtension->RegistryPath.Buffer );
  949. }
  950. #ifdef _USE_ETW
  951. WPP_CLEANUP(DriverObject);
  952. #endif // _USE_ETW
  953. return;
  954. }