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.

1055 lines
33 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1998 - 1999
  3. Module Name:
  4. RedBook.c
  5. Abstract:
  6. This driver translates audio IOCTLs into raw reads from audio
  7. tracks on compliant cdrom drives. These reads are then passed
  8. to Kernel Streaming (KS) to reduce switching into/out of kernel
  9. mode.
  10. This driver also emulates most hardware functions, such as
  11. current head position, during play operation. This is done to
  12. prevent audio stuttering or because the drive would not understand
  13. the request while it is not playing audio (since it is only reading).
  14. At initialization, the driver reads the registry to determine
  15. if it should attach itself to the stack and the number of
  16. buffers to allocate.
  17. The WmiData (including enable/disable) may be changed while the
  18. drive is not playing audio.
  19. Read errors cause the buffer to be zero'd out and passed
  20. along, much like a CD player skipping. Too many consecutive
  21. errors will cause the play operation to abort.
  22. Author:
  23. Environment:
  24. kernel mode only
  25. Notes:
  26. Revision History:
  27. --*/
  28. #include "redbook.h"
  29. #include "ntddredb.h"
  30. #include "proto.h"
  31. #include <scsi.h> // for SetKnownGoodDrive()
  32. #include <stdio.h> // vsprintf()
  33. #ifdef _USE_ETW
  34. #include "redbook.tmh"
  35. #endif // _USE_ETW
  36. //////////////////////////////////////////////////////////
  37. //////////////////////////////////////////////////////////
  38. //////////////////////////////////////////////////////////
  39. //
  40. // Define the sections that allow for paging some of
  41. // the code.
  42. //
  43. #ifdef ALLOC_PRAGMA
  44. #pragma alloc_text(PAGE, RedBookForwardIrpSynchronous )
  45. #pragma alloc_text(PAGE, RedBookGetDescriptor )
  46. #pragma alloc_text(PAGE, RedBookRegistryRead )
  47. #pragma alloc_text(PAGE, RedBookRegistryWrite )
  48. #pragma alloc_text(PAGE, RedBookSetTransferLength )
  49. #endif // ALLOC_PRAGMA
  50. //
  51. // use this to get mode pages
  52. //
  53. typedef struct _PASS_THROUGH_REQUEST {
  54. SCSI_PASS_THROUGH Srb;
  55. SENSE_DATA SenseInfoBuffer;
  56. UCHAR DataBuffer[0];
  57. } PASS_THROUGH_REQUEST, *PPASS_THROUGH_REQUEST;
  58. //////////////////////////////////////////////////////////////////
  59. /// END PROTOTYPES ///
  60. //////////////////////////////////////////////////////////////////
  61. //////////////////////////////////////////////////////////////////
  62. NTSTATUS
  63. RedBookRegistryRead(
  64. PREDBOOK_DEVICE_EXTENSION DeviceExtension
  65. )
  66. /*++
  67. Routine Description:
  68. This routine queries the registry for values for the
  69. corresponding PDO. The values are then saved in the
  70. given DeviceExtension.
  71. Arguments:
  72. PhysicalDeviceObject - the physical device object we are being added to
  73. DeviceExtension - the redbook device extension used
  74. Return Value:
  75. status
  76. --*/
  77. {
  78. //
  79. // Use registry to hold key information
  80. //
  81. HANDLE deviceParameterHandle; // cdrom instance key
  82. HANDLE driverParameterHandle; // digital audio subkey
  83. OBJECT_ATTRIBUTES objectAttributes = {0};
  84. UNICODE_STRING subkeyName;
  85. NTSTATUS status;
  86. // seeded in the ENUM tree by ClassInstaller
  87. ULONG32 regCDDAAccurate;
  88. ULONG32 regCDDASupported;
  89. ULONG32 regSectorsPerReadMask;
  90. // seeded first time booting, set by wmi/control panel
  91. ULONG32 regSectorsPerRead;
  92. ULONG32 regNumberOfBuffers;
  93. ULONG32 regVersion;
  94. // table for above registry entries
  95. RTL_QUERY_REGISTRY_TABLE queryTable[7] = {0}; // null-terminated array
  96. PAGED_CODE();
  97. deviceParameterHandle = NULL;
  98. driverParameterHandle = NULL;
  99. // CDDAAccurate and Supported set from SetKnownGoodDrive()
  100. regCDDAAccurate = DeviceExtension->WmiData.CDDAAccurate;
  101. regCDDASupported = DeviceExtension->WmiData.CDDASupported;
  102. regSectorsPerReadMask = -1;
  103. regSectorsPerRead = REDBOOK_WMI_SECTORS_DEFAULT;
  104. regNumberOfBuffers = REDBOOK_WMI_BUFFERS_DEFAULT;
  105. regVersion = 0;
  106. TRY {
  107. status = IoOpenDeviceRegistryKey(DeviceExtension->TargetPdo,
  108. PLUGPLAY_REGKEY_DEVICE,
  109. KEY_WRITE,
  110. &deviceParameterHandle
  111. );
  112. if (!NT_SUCCESS(status)) {
  113. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugRegistry, "[redbook] "
  114. "RegistryRead !! CDROM PnP Instance DNE? %lx\n",
  115. status));
  116. LEAVE;
  117. }
  118. RtlInitUnicodeString(&subkeyName, REDBOOK_REG_SUBKEY_NAME);
  119. InitializeObjectAttributes(&objectAttributes,
  120. &subkeyName,
  121. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  122. deviceParameterHandle,
  123. NULL
  124. );
  125. status = ZwOpenKey( &driverParameterHandle,
  126. KEY_READ,
  127. &objectAttributes
  128. );
  129. if (!NT_SUCCESS(status)) {
  130. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugRegistry, "[redbook] "
  131. "RegistryRead !! Subkey not opened, using "
  132. "defaults %lx\n", status));
  133. LEAVE;
  134. }
  135. //
  136. // Setup the structure to read
  137. //
  138. queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
  139. queryTable[0].Name = REDBOOK_REG_CDDA_ACCURATE_KEY_NAME;
  140. queryTable[0].EntryContext = &regCDDAAccurate;
  141. queryTable[0].DefaultType = REG_DWORD;
  142. queryTable[0].DefaultData = &regCDDAAccurate;
  143. queryTable[0].DefaultLength = 0;
  144. queryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
  145. queryTable[1].Name = REDBOOK_REG_CDDA_SUPPORTED_KEY_NAME;
  146. queryTable[1].EntryContext = &regCDDASupported;
  147. queryTable[1].DefaultType = REG_DWORD;
  148. queryTable[1].DefaultData = &regCDDASupported;
  149. queryTable[1].DefaultLength = 0;
  150. queryTable[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
  151. queryTable[2].Name = REDBOOK_REG_SECTORS_MASK_KEY_NAME;
  152. queryTable[2].EntryContext = &regSectorsPerReadMask;
  153. queryTable[2].DefaultType = REG_DWORD;
  154. queryTable[2].DefaultData = &regSectorsPerReadMask;
  155. queryTable[2].DefaultLength = 0;
  156. queryTable[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
  157. queryTable[3].Name = REDBOOK_REG_SECTORS_KEY_NAME;
  158. queryTable[3].EntryContext = &regSectorsPerRead;
  159. queryTable[3].DefaultType = REG_DWORD;
  160. queryTable[3].DefaultData = &regSectorsPerRead;
  161. queryTable[3].DefaultLength = 0;
  162. queryTable[4].Flags = RTL_QUERY_REGISTRY_DIRECT;
  163. queryTable[4].Name = REDBOOK_REG_BUFFERS_KEY_NAME;
  164. queryTable[4].EntryContext = &regNumberOfBuffers;
  165. queryTable[4].DefaultType = REG_DWORD;
  166. queryTable[4].DefaultData = &regNumberOfBuffers;
  167. queryTable[4].DefaultLength = 0;
  168. queryTable[5].Flags = RTL_QUERY_REGISTRY_DIRECT;
  169. queryTable[5].Name = REDBOOK_REG_VERSION_KEY_NAME;
  170. queryTable[5].EntryContext = &regVersion;
  171. queryTable[5].DefaultType = REG_DWORD;
  172. queryTable[5].DefaultData = &regVersion;
  173. queryTable[5].DefaultLength = 0;
  174. //
  175. // queryTable[6] is null-filled to terminate reading
  176. //
  177. //
  178. // read values
  179. //
  180. status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
  181. (PWSTR)driverParameterHandle,
  182. &queryTable[0],
  183. NULL,
  184. NULL
  185. );
  186. //
  187. // Check for failure...
  188. //
  189. if (!NT_SUCCESS(status)) {
  190. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugRegistry, "[redbook] "
  191. "RegistryRead !! default values (read "
  192. "failed) %lx\n", status));
  193. LEAVE;
  194. }
  195. status = STATUS_SUCCESS;
  196. } FINALLY {
  197. if (deviceParameterHandle) {
  198. ZwClose(deviceParameterHandle);
  199. }
  200. if (driverParameterHandle) {
  201. ZwClose(driverParameterHandle);
  202. }
  203. if (!NT_SUCCESS(status)) {
  204. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugRegistry, "[redbook] "
  205. "RegistryRead !! Using Defaults\n"));
  206. }
  207. }
  208. if (regVersion > REDBOOK_REG_VERSION) {
  209. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugRegistry, "[redbook] "
  210. "RegistryRead !! Version %x in registry newer than %x\n",
  211. regVersion, REDBOOK_REG_VERSION));
  212. return STATUS_UNSUCCESSFUL;
  213. }
  214. //
  215. // successfully read from the registry, but make sure data is valid.
  216. //
  217. if (regSectorsPerReadMask == 0) {
  218. if (regCDDAAccurate) {
  219. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugRegistry, "[redbook] "
  220. "RegistryRead !! SectorMask==0 && CDDAAccurate?\n"));
  221. }
  222. if (regCDDASupported) {
  223. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugRegistry, "[redbook] "
  224. "RegistryRead !! SectorMask==0 && CDDASupported?\n"));
  225. }
  226. regCDDAAccurate = 0;
  227. regCDDASupported = 0;
  228. }
  229. if (regSectorsPerRead < REDBOOK_WMI_SECTORS_MIN) {
  230. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugRegistry, "[redbook] "
  231. "RegistryRead !! SectorsPerRead too small\n"));
  232. regSectorsPerRead = REDBOOK_WMI_SECTORS_MIN;
  233. }
  234. if (regSectorsPerRead > REDBOOK_WMI_SECTORS_MAX) {
  235. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugRegistry, "[redbook] "
  236. "RegistryRead !! SectorsPerRead too large\n"));
  237. regSectorsPerRead = REDBOOK_WMI_SECTORS_MAX;
  238. }
  239. if (regNumberOfBuffers < REDBOOK_WMI_BUFFERS_MIN) {
  240. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugRegistry, "[redbook] "
  241. "RegistryRead !! NumberOfBuffers too small\n"));
  242. regNumberOfBuffers = REDBOOK_WMI_BUFFERS_MIN;
  243. }
  244. if (regNumberOfBuffers > REDBOOK_WMI_BUFFERS_MAX) {
  245. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugRegistry, "[redbook] "
  246. "RegistryRead !! NumberOfBuffers too large\n"));
  247. regNumberOfBuffers = REDBOOK_WMI_BUFFERS_MAX;
  248. }
  249. if (regSectorsPerRead > DeviceExtension->WmiData.MaximumSectorsPerRead) {
  250. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugRegistry, "[redbook] "
  251. "RegistryRead !! SectorsPerRead too big for adapter\n"));
  252. regSectorsPerRead = DeviceExtension->WmiData.MaximumSectorsPerRead;
  253. }
  254. DeviceExtension->WmiData.CDDAAccurate = regCDDAAccurate ? 1 : 0;
  255. DeviceExtension->WmiData.CDDASupported = regCDDASupported ? 1: 0;
  256. DeviceExtension->WmiData.SectorsPerReadMask = regSectorsPerReadMask;
  257. /*
  258. * Don't update WmiData.SectorsPerRead and WmiData.NumberOfBuffers yet,
  259. * because doing so while we're playing can disrupt our play buffers
  260. * (and we could have been stopped and restarted in the middle of playing).
  261. * So just save these values until the beginning of the next play.
  262. */
  263. DeviceExtension->NextWmiSectorsPerRead = regSectorsPerRead;
  264. DeviceExtension->NextWmiNumberOfBuffers = regNumberOfBuffers;
  265. return STATUS_SUCCESS;
  266. }
  267. NTSTATUS
  268. RedBookRegistryWrite(
  269. PREDBOOK_DEVICE_EXTENSION DeviceExtension
  270. )
  271. /*++
  272. Routine Description:
  273. This routine queries the registry for values for the
  274. corresponding PDO. The values are then saved in the
  275. given DeviceExtension.
  276. Arguments:
  277. PhysicalDeviceObject - the physical device object we are being added to
  278. DeviceExtension - the redbook device extension used
  279. Return Value:
  280. status
  281. --*/
  282. {
  283. OBJECT_ATTRIBUTES objectAttributes = {0};
  284. UNICODE_STRING subkeyName;
  285. HANDLE deviceParameterHandle; // cdrom instance key
  286. HANDLE driverParameterHandle; // redbook subkey
  287. // seeded in the ENUM tree by ClassInstaller
  288. ULONG32 regCDDAAccurate;
  289. ULONG32 regCDDASupported;
  290. ULONG32 regSectorsPerReadMask;
  291. // seeded first time booting, set by wmi/control panel
  292. ULONG32 regSectorsPerRead;
  293. ULONG32 regNumberOfBuffers;
  294. ULONG32 regVersion;
  295. NTSTATUS status;
  296. PAGED_CODE();
  297. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugRegistry, "[redbook] "
  298. "RegistryWrite => Opening key\n"));
  299. status = IoOpenDeviceRegistryKey(DeviceExtension->TargetPdo,
  300. PLUGPLAY_REGKEY_DRIVER,
  301. KEY_ALL_ACCESS,
  302. &deviceParameterHandle);
  303. if (!NT_SUCCESS(status)) {
  304. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugRegistry, "[redbook] "
  305. "RegistryWrite !! CDROM PnP Instance DNE? %lx\n",
  306. status));
  307. return status;
  308. }
  309. RtlInitUnicodeString(&subkeyName, REDBOOK_REG_SUBKEY_NAME);
  310. InitializeObjectAttributes(&objectAttributes,
  311. &subkeyName,
  312. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  313. deviceParameterHandle,
  314. (PSECURITY_DESCRIPTOR) NULL);
  315. //
  316. // Create the key or open it if it already exists
  317. //
  318. status = ZwCreateKey(&driverParameterHandle,
  319. KEY_WRITE | KEY_READ,
  320. &objectAttributes,
  321. 0,
  322. (PUNICODE_STRING) NULL,
  323. REG_OPTION_NON_VOLATILE,
  324. NULL);
  325. if (!NT_SUCCESS(status)) {
  326. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugRegistry, "[redbook] "
  327. "RegistryWrite !! Subkey not created? %lx\n", status));
  328. ZwClose(deviceParameterHandle);
  329. return status;
  330. }
  331. regCDDAAccurate = DeviceExtension->WmiData.CDDAAccurate;
  332. regCDDASupported = DeviceExtension->WmiData.CDDASupported;
  333. regSectorsPerReadMask = DeviceExtension->WmiData.SectorsPerReadMask;
  334. regVersion = REDBOOK_REG_VERSION;
  335. /*
  336. * Don't write the actual WmiData.SectorsPerRead and WmiData.NumberOfBuffers.
  337. * Write the last values that were set, which is the ones that we will use on the next play.
  338. */
  339. regSectorsPerRead = DeviceExtension->NextWmiSectorsPerRead;
  340. regNumberOfBuffers = DeviceExtension->NextWmiNumberOfBuffers;
  341. status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE,
  342. (PWSTR)driverParameterHandle,
  343. REDBOOK_REG_VERSION_KEY_NAME,
  344. REG_DWORD,
  345. &regVersion,
  346. sizeof(regVersion));
  347. if (!NT_SUCCESS(status)) {
  348. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugRegistry, "[redbook] "
  349. "RegistryWrite !! Failed write version %lx\n", status));
  350. }
  351. status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE,
  352. (PWSTR)driverParameterHandle,
  353. REDBOOK_REG_BUFFERS_KEY_NAME,
  354. REG_DWORD,
  355. &regNumberOfBuffers,
  356. sizeof(regNumberOfBuffers));
  357. if (!NT_SUCCESS(status)) {
  358. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugRegistry, "[redbook] "
  359. "RegistryWrite !! Failed write buffers %lx\n", status));
  360. }
  361. status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE,
  362. (PWSTR)driverParameterHandle,
  363. REDBOOK_REG_SECTORS_KEY_NAME,
  364. REG_DWORD,
  365. &regSectorsPerRead,
  366. sizeof(regSectorsPerRead));
  367. if (!NT_SUCCESS(status)) {
  368. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugRegistry, "[redbook] "
  369. "RegistryWrite !! Failed write sectors %lx\n", status));
  370. }
  371. status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE,
  372. (PWSTR) driverParameterHandle,
  373. REDBOOK_REG_SECTORS_MASK_KEY_NAME,
  374. REG_DWORD,
  375. &regSectorsPerReadMask,
  376. sizeof(regSectorsPerReadMask));
  377. if (!NT_SUCCESS(status)) {
  378. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugRegistry, "[redbook] "
  379. "RegistryWrite !! Failed write SectorsMask %lx\n",
  380. status));
  381. }
  382. status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE,
  383. (PWSTR)driverParameterHandle,
  384. REDBOOK_REG_CDDA_SUPPORTED_KEY_NAME,
  385. REG_DWORD,
  386. &regCDDASupported,
  387. sizeof(regCDDASupported));
  388. if (!NT_SUCCESS(status)) {
  389. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugRegistry, "[redbook] "
  390. "RegistryWrite !! Failed write Supported %lx\n", status));
  391. }
  392. status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE,
  393. (PWSTR)driverParameterHandle,
  394. REDBOOK_REG_CDDA_ACCURATE_KEY_NAME,
  395. REG_DWORD,
  396. &regCDDAAccurate,
  397. sizeof(regCDDAAccurate));
  398. if (!NT_SUCCESS(status)) {
  399. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugRegistry, "[redbook] "
  400. "RegistryWrite !! Failed write Accurate %lx\n", status));
  401. }
  402. //
  403. // close the handles
  404. //
  405. ZwClose(driverParameterHandle);
  406. ZwClose(deviceParameterHandle);
  407. return STATUS_SUCCESS;
  408. }
  409. NTSTATUS
  410. RedBookReadWrite(
  411. PDEVICE_OBJECT DeviceObject,
  412. PIRP Irp
  413. )
  414. /*++
  415. Routine Description:
  416. This routine simply rejects read/write irps if currently
  417. playing audio.
  418. Arguments:
  419. DeviceObject
  420. Irp
  421. Return Value:
  422. NTSTATUS
  423. --*/
  424. {
  425. PREDBOOK_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  426. NTSTATUS status;
  427. ULONG state;
  428. status = IoAcquireRemoveLock(&deviceExtension->RemoveLock, Irp);
  429. if (!NT_SUCCESS(status)) {
  430. Irp->IoStatus.Information = 0;
  431. Irp->IoStatus.Status = status;
  432. IoCompleteRequest(Irp, IO_CD_ROM_INCREMENT);
  433. return status;
  434. }
  435. if (!deviceExtension->WmiData.PlayEnabled) {
  436. status = RedBookSendToNextDriver(DeviceObject, Irp);
  437. IoReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  438. return status;
  439. }
  440. state = GetCdromState(deviceExtension);
  441. //
  442. // it doesn't really matter if we allow a few reads down during
  443. // the start of a play, since io is not guaranteed to occur in
  444. // order.
  445. //
  446. if (!TEST_FLAG(state, CD_PLAYING)) {
  447. status = RedBookSendToNextDriver(DeviceObject, Irp);
  448. IoReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  449. return status;
  450. }
  451. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugTrace, "[redbook] "
  452. "ReadWrite => Rejecting a request\n"));
  453. Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
  454. Irp->IoStatus.Information = 0;
  455. IoCompleteRequest(Irp, IO_CD_ROM_INCREMENT);
  456. IoReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  457. return STATUS_DEVICE_BUSY;
  458. }
  459. NTSTATUS
  460. RedBookSignalCompletion(
  461. IN PDEVICE_OBJECT DeviceObject,
  462. IN PIRP Irp,
  463. IN PKEVENT Event
  464. )
  465. /*++
  466. Routine Description:
  467. This completion routine will signal the event given as context and then
  468. return STATUS_MORE_PROCESSING_REQUIRED to stop event completion. It is
  469. the responsibility of the routine waiting on the event to complete the
  470. request and free the event.
  471. Arguments:
  472. DeviceObject - a pointer to the device object
  473. Irp - a pointer to the irp
  474. Event - a pointer to the event to signal
  475. Return Value:
  476. STATUS_MORE_PROCESSING_REQUIRED
  477. --*/
  478. {
  479. UNREFERENCED_PARAMETER( DeviceObject );
  480. UNREFERENCED_PARAMETER( Irp );
  481. KeSetEvent(Event, IO_CD_ROM_INCREMENT, FALSE);
  482. return STATUS_MORE_PROCESSING_REQUIRED;
  483. }
  484. NTSTATUS
  485. RedBookSetTransferLength(
  486. IN PREDBOOK_DEVICE_EXTENSION DeviceExtension
  487. )
  488. /*++
  489. Routine Description:
  490. calls ClassGetDescriptor()
  491. set the maxSectorsPerRead based on storage properties
  492. checks for knownGood drives using the extension
  493. Arguments:
  494. DeviceExtension
  495. Return Value:
  496. NTSTATUS
  497. --*/
  498. {
  499. PSTORAGE_DESCRIPTOR_HEADER storageDescriptor;
  500. PSTORAGE_ADAPTER_DESCRIPTOR adapterDescriptor;
  501. STORAGE_PROPERTY_ID storageProperty;
  502. ULONGLONG maxPageLength;
  503. ULONGLONG maxPhysLength;
  504. ULONGLONG sectorLength;
  505. ULONG sectors;
  506. NTSTATUS status;
  507. PAGED_CODE();
  508. storageDescriptor = NULL;
  509. storageProperty = StorageAdapterProperty;
  510. status = RedBookGetDescriptor( DeviceExtension,
  511. &storageProperty,
  512. &storageDescriptor
  513. );
  514. if (!NT_SUCCESS(status)) {
  515. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugPnp, "[redbook] "
  516. "SetTranLen => failed to get descriptor\n"));
  517. ASSERT( storageDescriptor == NULL );
  518. NOTHING;
  519. } else {
  520. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugPnp, "[redbook] "
  521. "SetTranLen => got descriptor\n"));
  522. ASSERT( storageDescriptor != NULL );
  523. adapterDescriptor = (PVOID)storageDescriptor;
  524. maxPhysLength = (ULONGLONG) adapterDescriptor->MaximumTransferLength;
  525. maxPageLength = (ULONGLONG) adapterDescriptor->MaximumPhysicalPages;
  526. maxPageLength *= PAGE_SIZE;
  527. sectors = -1;
  528. sectorLength = sectors * (ULONGLONG)PAGE_SIZE;
  529. if (maxPhysLength == 0 || maxPageLength == 0) {
  530. //
  531. // what to do in this case? disable redbook?
  532. //
  533. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugError, "[redbook] "
  534. "SetTranLen !! The adapter cannot support transfers?!\n"));
  535. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugError, "[redbook] "
  536. "SetTranLen !! maxPhysLength = %I64x\n", maxPhysLength));
  537. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugError, "[redbook] "
  538. "SetTranLen !! maxPageLength = %I64x\n", maxPageLength));
  539. ASSERT(!"[redbook] SetTranLen !! Got bogus adapter properties");
  540. maxPhysLength = 1;
  541. maxPageLength = 1;
  542. }
  543. if (maxPhysLength > sectorLength &&
  544. maxPageLength > sectorLength) { // more than ulong can store?
  545. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugPnp, "[redbook] "
  546. "SetTranLen => both Max's more than a ulong?\n" ));
  547. } else if ( (ULONGLONG)maxPhysLength > (ULONGLONG)maxPageLength) {
  548. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugPnp, "[redbook] "
  549. "SetTranLen => restricted due to page length\n" ));
  550. sectorLength = maxPageLength;
  551. } else {
  552. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugPnp, "[redbook] "
  553. "SetTranLen => restricted due to phys length\n" ));
  554. sectorLength = maxPhysLength;
  555. }
  556. sectorLength -= PAGE_SIZE; // to handle non-page-aligned allocations
  557. if (sectorLength < RAW_SECTOR_SIZE) {
  558. sectorLength = RAW_SECTOR_SIZE;
  559. }
  560. //
  561. // took the smaller of physical transfer and page transfer,
  562. // therefore will never overflow sectors
  563. //
  564. sectors = (ULONG)(sectorLength / (ULONGLONG)RAW_SECTOR_SIZE);
  565. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugPnp, "[redbook] "
  566. "SetTranLen => MaxTransferLength = %lx\n",
  567. adapterDescriptor->MaximumTransferLength));
  568. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugPnp, "[redbook] "
  569. "SetTranLen => MaxPhysicalPages = %lx\n",
  570. adapterDescriptor->MaximumPhysicalPages));
  571. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugPnp, "[redbook] "
  572. "SetTranLen => Setting max sectors to = %lx\n",
  573. sectors));
  574. DeviceExtension->WmiData.MaximumSectorsPerRead = min(sectors, REDBOOK_WMI_SECTORS_MAX);
  575. if (DeviceExtension->NextWmiSectorsPerRead > sectors) {
  576. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugPnp, "[redbook] "
  577. "SetTranLen => Current sectors per read (%lx) too "
  578. "large. Setting to max sectors per read\n",
  579. DeviceExtension->NextWmiSectorsPerRead));
  580. DeviceExtension->NextWmiSectorsPerRead = sectors;
  581. } else if (DeviceExtension->NextWmiSectorsPerRead == 0) {
  582. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugPnp, "[redbook] "
  583. "SetTranLen => Current sectors per read (%lx) zero. "
  584. "Setting to max sectors per read\n",
  585. DeviceExtension->NextWmiSectorsPerRead));
  586. DeviceExtension->NextWmiSectorsPerRead = sectors;
  587. }
  588. }
  589. if (storageDescriptor !=NULL) {
  590. ExFreePool(storageDescriptor);
  591. }
  592. return STATUS_SUCCESS;
  593. }
  594. NTSTATUS
  595. RedBookPower(
  596. IN PDEVICE_OBJECT DeviceObject,
  597. IN PIRP Irp
  598. )
  599. {
  600. PREDBOOK_DEVICE_EXTENSION deviceExtension;
  601. NTSTATUS status;
  602. deviceExtension = (PREDBOOK_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
  603. status = IoAcquireRemoveLock(&deviceExtension->RemoveLock, Irp);
  604. if (!NT_SUCCESS(status)) {
  605. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugPnp, "[redbook] "
  606. "Power request after removal -- failing %x\n",
  607. status));
  608. return status;
  609. }
  610. PoStartNextPowerIrp(Irp);
  611. IoSkipCurrentIrpStackLocation(Irp);
  612. status = PoCallDriver(deviceExtension->TargetDeviceObject, Irp);
  613. IoReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  614. return status;
  615. }
  616. NTSTATUS
  617. RedBookForwardIrpSynchronous(
  618. IN PREDBOOK_DEVICE_EXTENSION DeviceExtension,
  619. IN PIRP Irp
  620. )
  621. {
  622. KEVENT event;
  623. NTSTATUS status;
  624. PAGED_CODE();
  625. KeInitializeEvent(&event, SynchronizationEvent, FALSE);
  626. IoCopyCurrentIrpStackLocationToNext(Irp);
  627. IoSetCompletionRoutine(Irp, RedBookSignalCompletion, &event,
  628. TRUE, TRUE, TRUE);
  629. status = IoCallDriver(DeviceExtension->TargetDeviceObject, Irp);
  630. if(status == STATUS_PENDING) {
  631. KeWaitForSingleObject(&event,
  632. Executive,
  633. KernelMode,
  634. FALSE,
  635. NULL);
  636. status = Irp->IoStatus.Status;
  637. }
  638. return status;
  639. }
  640. NTSTATUS
  641. RedBookGetDescriptor(
  642. IN PREDBOOK_DEVICE_EXTENSION DeviceExtension,
  643. IN PSTORAGE_PROPERTY_ID PropertyId,
  644. OUT PSTORAGE_DESCRIPTOR_HEADER *Descriptor
  645. )
  646. /*++
  647. Routine Description:
  648. This routine will perform a query for the specified property id and will
  649. allocate a non-paged buffer to store the data in. It is the responsibility
  650. of the caller to ensure that this buffer is freed.
  651. This routine must be run at IRQL_PASSIVE_LEVEL
  652. Arguments:
  653. DeviceObject - the device to query
  654. DeviceInfo - a location to store a pointer to the buffer we allocate
  655. Return Value:
  656. status
  657. if status is unsuccessful *DeviceInfo will be set to 0
  658. --*/
  659. {
  660. PDEVICE_OBJECT selfDeviceObject = DeviceExtension->SelfDeviceObject;
  661. PSTORAGE_DESCRIPTOR_HEADER descriptor;
  662. PSTORAGE_PROPERTY_QUERY query;
  663. PIO_STACK_LOCATION irpStack;
  664. PIRP irp;
  665. NTSTATUS status;
  666. ULONG length;
  667. UCHAR pass;
  668. PAGED_CODE();
  669. descriptor = NULL;
  670. irp = NULL;
  671. irpStack = NULL;
  672. query = NULL;
  673. pass = 0;
  674. //
  675. // Set the descriptor pointer to NULL
  676. //
  677. *Descriptor = NULL;
  678. TRY {
  679. // NOTE: should probably just use IoAllocateIrp() and
  680. // IoReuseIrp() when this gets updated.
  681. // Historical note: IoReuseIrp() was not available when
  682. // this was written, and verifier was just beginning and
  683. // complained loudly about reused irps.
  684. irp = ExAllocatePoolWithTag(NonPagedPool,
  685. IoSizeOfIrp(selfDeviceObject->StackSize+1),
  686. TAG_GET_DESC1);
  687. if (irp == NULL) {
  688. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugPnp, "[redbook] "
  689. "GetDescriptor: Unable to allocate irp\n"));
  690. status = STATUS_NO_MEMORY;
  691. LEAVE;
  692. }
  693. //
  694. // initialize the irp
  695. //
  696. IoInitializeIrp(irp,
  697. IoSizeOfIrp(selfDeviceObject->StackSize+1),
  698. (CCHAR)(selfDeviceObject->StackSize+1));
  699. irp->UserBuffer = NULL;
  700. IoSetNextIrpStackLocation(irp);
  701. //
  702. // Retrieve the property page
  703. //
  704. do {
  705. switch(pass) {
  706. case 0: {
  707. //
  708. // On the first pass we just want to get the first few
  709. // bytes of the descriptor so we can read it's size
  710. //
  711. length = sizeof(STORAGE_DESCRIPTOR_HEADER);
  712. descriptor = NULL;
  713. descriptor = ExAllocatePoolWithTag(NonPagedPool,
  714. MAX(sizeof(STORAGE_PROPERTY_QUERY),length),
  715. TAG_GET_DESC2);
  716. if (descriptor == NULL) {
  717. status = STATUS_NO_MEMORY;
  718. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugPnp, "[redbook] "
  719. "GetDescriptor: unable to alloc"
  720. "memory for descriptor (%d bytes)\n",
  721. length));
  722. LEAVE;
  723. }
  724. break;
  725. }
  726. case 1: {
  727. //
  728. // This time we know how much data there is so we can
  729. // allocate a buffer of the correct size
  730. //
  731. length = descriptor->Size;
  732. ExFreePool(descriptor);
  733. descriptor = NULL;
  734. //
  735. // Note: this allocation is returned to the caller
  736. //
  737. descriptor = ExAllocatePoolWithTag(NonPagedPool,
  738. MAX(sizeof(STORAGE_PROPERTY_QUERY),length),
  739. TAG_GET_DESC);
  740. if(descriptor == NULL) {
  741. status = STATUS_NO_MEMORY;
  742. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugPnp, "[redbook] "
  743. "GetDescriptor: unable to alloc"
  744. "memory for descriptor (%d bytes)\n",
  745. length));
  746. LEAVE;
  747. }
  748. break;
  749. }
  750. }
  751. irpStack = IoGetCurrentIrpStackLocation(irp);
  752. SET_FLAG(irpStack->Flags, SL_OVERRIDE_VERIFY_VOLUME);
  753. irpStack->MajorFunction = IRP_MJ_DEVICE_CONTROL;
  754. irpStack->Parameters.DeviceIoControl.IoControlCode =
  755. IOCTL_STORAGE_QUERY_PROPERTY;
  756. irpStack->Parameters.DeviceIoControl.InputBufferLength =
  757. sizeof(STORAGE_PROPERTY_QUERY);
  758. irpStack->Parameters.DeviceIoControl.OutputBufferLength = length;
  759. irp->UserBuffer = descriptor;
  760. irp->AssociatedIrp.SystemBuffer = descriptor;
  761. query = (PVOID)descriptor;
  762. query->PropertyId = *PropertyId;
  763. query->QueryType = PropertyStandardQuery;
  764. //
  765. // send the irp
  766. //
  767. status = RedBookForwardIrpSynchronous(DeviceExtension, irp);
  768. if(!NT_SUCCESS(status)) {
  769. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugPnp, "[redbook] "
  770. "GetDescriptor: error %lx trying to "
  771. "query properties\n", status));
  772. LEAVE;
  773. }
  774. } while(pass++ < 1);
  775. } FINALLY {
  776. if (irp != NULL) {
  777. ExFreePool(irp);
  778. }
  779. if(!NT_SUCCESS(status)) {
  780. if (descriptor != NULL) {
  781. ExFreePool(descriptor);
  782. descriptor = NULL;
  783. }
  784. }
  785. *Descriptor = descriptor;
  786. }
  787. return status;
  788. }