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.

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