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.

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