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.

6981 lines
210 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1992 - 1999
  3. Module Name:
  4. audio.c
  5. Abstract:
  6. This driver filters scsi-2 cdrom audio commands for non-scsi-2
  7. compliant cdrom drives. At initialization, the driver scans the
  8. scsi bus for a recognized non-scsi-2 cdrom drive, and if one is
  9. found attached, installs itself to intercept IO_DEVICE_CONTROL
  10. requests for this drive.
  11. Environment:
  12. kernel mode only
  13. Notes:
  14. Revision History:
  15. --*/
  16. #include "ntddk.h"
  17. #include "ntddscsi.h"
  18. #include "ntddcdrm.h"
  19. #include "stdio.h"
  20. #include "scsi.h"
  21. #include "cdaudio.h"
  22. #ifdef POOL_TAGGING
  23. #ifdef ExAllocatePool
  24. #undef ExAllocatePool
  25. #endif
  26. #define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,' AdC')
  27. #endif
  28. //
  29. // Function declarations
  30. //
  31. NTSTATUS
  32. DriverEntry (
  33. IN PDRIVER_OBJECT DriverObject,
  34. IN PUNICODE_STRING RegistryPath
  35. );
  36. NTSTATUS
  37. CdAudioCreate(
  38. IN PDEVICE_OBJECT DeviceObject,
  39. IN PIRP Irp
  40. );
  41. NTSTATUS
  42. CdAudioReadWrite(
  43. IN PDEVICE_OBJECT DeviceObject,
  44. IN PIRP Irp
  45. );
  46. NTSTATUS
  47. CdAudioDeviceControl(
  48. IN PDEVICE_OBJECT DeviceObject,
  49. IN PIRP Irp
  50. );
  51. NTSTATUS
  52. CdAudioSendToNextDriver(
  53. IN PDEVICE_OBJECT DeviceObject,
  54. IN PIRP Irp
  55. );
  56. BOOLEAN
  57. CdAudioIsPlayActive(
  58. IN PDEVICE_OBJECT DeviceObject
  59. );
  60. BOOLEAN
  61. NecSupportNeeded(
  62. PUCHAR InquiryData
  63. );
  64. NTSTATUS
  65. CdAudioNECDeviceControl(
  66. IN PDEVICE_OBJECT DeviceObject,
  67. IN PIRP Irp
  68. );
  69. NTSTATUS
  70. CdAudioPioneerDeviceControl(
  71. IN PDEVICE_OBJECT DeviceObject,
  72. IN PIRP Irp
  73. );
  74. NTSTATUS
  75. CdAudioDenonDeviceControl(
  76. IN PDEVICE_OBJECT DeviceObject,
  77. IN PIRP Irp
  78. );
  79. NTSTATUS
  80. CdAudioHitachiSendPauseCommand(
  81. IN PDEVICE_OBJECT DeviceObject
  82. );
  83. NTSTATUS
  84. CdAudioHitachiDeviceControl(
  85. IN PDEVICE_OBJECT DeviceObject,
  86. IN PIRP Irp
  87. );
  88. NTSTATUS
  89. CdAudio535DeviceControl(
  90. IN PDEVICE_OBJECT DeviceObject,
  91. IN PIRP Irp
  92. );
  93. NTSTATUS
  94. CdAudio435DeviceControl(
  95. IN PDEVICE_OBJECT DeviceObject,
  96. IN PIRP Irp
  97. );
  98. NTSTATUS
  99. CdAudioPan533DeviceControl(
  100. IN PDEVICE_OBJECT DeviceObject,
  101. IN PIRP Irp
  102. );
  103. NTSTATUS
  104. CdAudioAtapiDeviceControl(
  105. IN PDEVICE_OBJECT DeviceObject,
  106. IN PIRP Irp
  107. );
  108. NTSTATUS
  109. CdAudioLionOpticsDeviceControl(
  110. IN PDEVICE_OBJECT DeviceObject,
  111. IN PIRP Irp
  112. );
  113. NTSTATUS
  114. CdAudioHPCdrDeviceControl(
  115. PDEVICE_OBJECT DeviceObject,
  116. PIRP Irp
  117. );
  118. VOID
  119. HpCdrProcessLastSession(
  120. IN PCDROM_TOC Toc
  121. );
  122. NTSTATUS
  123. HPCdrCompletion(
  124. IN PDEVICE_OBJECT DeviceObject,
  125. IN PIRP Irp,
  126. IN PVOID Context
  127. );
  128. NTSTATUS
  129. CdAudioPower(
  130. IN PDEVICE_OBJECT DeviceObject,
  131. IN PIRP Irp
  132. );
  133. NTSTATUS
  134. CdAudioForwardIrpSynchronous(
  135. IN PDEVICE_OBJECT DeviceObject,
  136. IN PIRP Irp
  137. );
  138. VOID CdAudioUnload(
  139. IN PDRIVER_OBJECT DriverObject
  140. );
  141. //
  142. // Define the sections that allow for discarding (i.e. paging) some of
  143. // the code. NEC is put into one section, all others go into another
  144. // section. This way unless there are both NEC and one of the other
  145. // device brands, some amount of code is freed.
  146. //
  147. #pragma alloc_text(INIT, DriverEntry)
  148. #pragma alloc_text(PAGECDNC, CdAudioNECDeviceControl)
  149. #pragma alloc_text(PAGECDOT, CdAudioHitachiSendPauseCommand)
  150. #pragma alloc_text(PAGECDOT, CdAudioHitachiDeviceControl)
  151. #pragma alloc_text(PAGECDOT, CdAudioDenonDeviceControl)
  152. #pragma alloc_text(PAGECDNC, CdAudio435DeviceControl)
  153. #pragma alloc_text(PAGECDNC, CdAudio535DeviceControl)
  154. #pragma alloc_text(PAGECDOT, CdAudioPioneerDeviceControl)
  155. #pragma alloc_text(PAGECDNC, CdAudioPan533DeviceControl)
  156. #pragma alloc_text(PAGECDOT, CdAudioAtapiDeviceControl)
  157. #pragma alloc_text(PAGECDOT, CdAudioLionOpticsDeviceControl)
  158. #pragma alloc_text(PAGECDOT, CdAudioHPCdrDeviceControl)
  159. #pragma alloc_text(PAGECDOT, HpCdrProcessLastSession)
  160. #pragma alloc_text(PAGECDOT, HPCdrCompletion)
  161. NTSTATUS
  162. SendSrbSynchronous(
  163. IN PCD_DEVICE_EXTENSION Extension,
  164. IN PSCSI_PASS_THROUGH Srb,
  165. IN PVOID Buffer,
  166. IN ULONG BufferLength
  167. )
  168. /*++
  169. Routine Description:
  170. This routine sends the given SRB synchronously to the CDROM class driver.
  171. Arguments:
  172. Extension - Supplies the device extension.
  173. Srb - Supplies the SRB.
  174. Buffer - Supplies the return buffer.
  175. BufferLength - Supplies the buffer length.
  176. Return Value:
  177. NTSTATUS
  178. --*/
  179. {
  180. ULONG ioctl;
  181. KEVENT event;
  182. PIRP irp = NULL;
  183. IO_STATUS_BLOCK ioStatus;
  184. NTSTATUS status;
  185. Srb->Length = sizeof(SCSI_PASS_THROUGH);
  186. Srb->SenseInfoLength = 0;
  187. Srb->SenseInfoOffset = 0;
  188. if (Buffer) {
  189. Srb->DataIn = SCSI_IOCTL_DATA_IN;
  190. Srb->DataTransferLength = BufferLength;
  191. Srb->DataBufferOffset = (ULONG_PTR) Buffer;
  192. ioctl = IOCTL_SCSI_PASS_THROUGH_DIRECT;
  193. } else {
  194. Srb->DataIn = SCSI_IOCTL_DATA_OUT;
  195. Srb->DataTransferLength = 0;
  196. Srb->DataBufferOffset = 0;
  197. ioctl = IOCTL_SCSI_PASS_THROUGH;
  198. }
  199. KeInitializeEvent(&event, NotificationEvent, FALSE);
  200. irp = IoBuildDeviceIoControlRequest(ioctl, Extension->TargetDeviceObject,
  201. Srb, sizeof(SCSI_PASS_THROUGH),
  202. Srb, sizeof(SCSI_PASS_THROUGH),
  203. FALSE, &event, &ioStatus);
  204. if (!irp) {
  205. return STATUS_INSUFFICIENT_RESOURCES;
  206. }
  207. status = IoCallDriver(Extension->TargetDeviceObject, irp);
  208. if (status == STATUS_PENDING) {
  209. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  210. status = ioStatus.Status;
  211. }
  212. return status;
  213. }
  214. NTSTATUS
  215. CdAudioAddDevice(
  216. IN PDRIVER_OBJECT DriverObject,
  217. IN PDEVICE_OBJECT PhysicalDeviceObject
  218. )
  219. /*++
  220. Routine Description:
  221. This routine creates and initializes a new FDO for the corresponding
  222. PDO. It may perform property queries on the FDO but cannot do any
  223. media access operations.
  224. Arguments:
  225. DriverObject - CDROM class driver object.
  226. Pdo - the physical device object we are being added to
  227. Return Value:
  228. status
  229. --*/
  230. {
  231. NTSTATUS status;
  232. PDEVICE_OBJECT deviceObject;
  233. PCD_DEVICE_EXTENSION extension;
  234. ULONG regActive = CDAUDIO_SEARCH_ACTIVE;
  235. //
  236. // Use registry to potentially not load onto stack
  237. //
  238. {
  239. HANDLE deviceParameterHandle;
  240. RTL_QUERY_REGISTRY_TABLE queryTable[2];
  241. //
  242. // See if key exists and is readable.
  243. //
  244. status = IoOpenDeviceRegistryKey(PhysicalDeviceObject,
  245. PLUGPLAY_REGKEY_DRIVER,
  246. KEY_READ,
  247. &deviceParameterHandle);
  248. if (!NT_SUCCESS(status)) {
  249. //
  250. // Pnp keys should always exist and be system-readable
  251. //
  252. CdDump((0, "AddDevice !! Registry key DNE?! %lx\n", status));
  253. ASSERT(FALSE);
  254. regActive = CDAUDIO_SEARCH_ACTIVE;
  255. goto AddDeviceEndRegistry;
  256. }
  257. //
  258. // Zero out the memory
  259. //
  260. RtlZeroMemory(&queryTable, sizeof(queryTable));
  261. //
  262. // Setup the structure for the read call
  263. //
  264. queryTable->Flags =
  265. RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
  266. queryTable->Name = CDAUDIO_ACTIVE_KEY_NAME;
  267. queryTable->EntryContext = &regActive;
  268. queryTable->DefaultType = REG_DWORD;
  269. queryTable->DefaultData = NULL;
  270. queryTable->DefaultLength = 0;
  271. //
  272. // Get the value in regActive (using queryTable)
  273. //
  274. status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
  275. (PWSTR)deviceParameterHandle,
  276. queryTable,
  277. NULL,
  278. NULL);
  279. //
  280. // Check for failure...
  281. //
  282. if (!NT_SUCCESS(status)) {
  283. //
  284. // This is normal, as the key does not exist the first
  285. // time the system loads the driver for the device.
  286. //
  287. CdDump(( 2,
  288. "AddDevice !! Read value, status %lx\n",
  289. status));
  290. regActive = CDAUDIO_SEARCH_ACTIVE;
  291. } else if (regActive > CDAUDIO_MAX_ACTIVE) {
  292. //
  293. // The registry value has either been corrupted, or manually
  294. // set to CDAUDIO_SEARCH_ACTIVE. Either way, the driver will
  295. // search for drive type later.
  296. //
  297. CdDump(( 2,
  298. "AddDevice !! Need to search, value %x\n",
  299. regActive));
  300. regActive = CDAUDIO_SEARCH_ACTIVE;
  301. } else {
  302. //
  303. // We read a valid value, which will override the mapping type.
  304. //
  305. CdDump(( 2,
  306. "AddDevice => Read value %x\n",
  307. regActive));
  308. }
  309. //
  310. // close the handle
  311. //
  312. ZwClose(deviceParameterHandle);
  313. } // Finished registry handling
  314. AddDeviceEndRegistry:
  315. //
  316. // We forcibly set to within these bounds above
  317. //
  318. if (( regActive > CDAUDIO_MAX_ACTIVE ) &&
  319. ( regActive != CDAUDIO_SEARCH_ACTIVE )) {
  320. CdDump((0,
  321. "AddDevice => Invalid registry value for "
  322. "maptype %x, resetting\n",
  323. regActive
  324. ));
  325. regActive = CDAUDIO_SEARCH_ACTIVE;
  326. }
  327. CdDump((1,
  328. "AddDevice => Active == %x\n",
  329. regActive));
  330. //
  331. // The system will remove us from memory if we don't call IoCreateDevice
  332. //
  333. if (regActive == CDAUDIO_NOT_ACTIVE) {
  334. CdDump((2,
  335. "AddDevice => Not attaching for pdo %p\n",
  336. PhysicalDeviceObject
  337. ));
  338. return STATUS_SUCCESS;
  339. }
  340. //
  341. // Map support section into non-paged pool
  342. //
  343. switch (regActive) {
  344. case CDAUDIO_NEC:
  345. MmLockPagableCodeSection((PVOID)CdAudioNECDeviceControl);
  346. break;
  347. case CDAUDIO_PIONEER:
  348. case CDAUDIO_PIONEER624:
  349. MmLockPagableCodeSection((PVOID)CdAudioPioneerDeviceControl);
  350. break;
  351. case CDAUDIO_DENON:
  352. MmLockPagableCodeSection((PVOID)CdAudioDenonDeviceControl);
  353. break;
  354. case CDAUDIO_HITACHI:
  355. case CDAUDIO_FUJITSU:
  356. MmLockPagableCodeSection((PVOID)CdAudioHitachiDeviceControl);
  357. break;
  358. case CDAUDIO_CDS535:
  359. MmLockPagableCodeSection((PVOID)CdAudio535DeviceControl);
  360. break;
  361. case CDAUDIO_CDS435:
  362. MmLockPagableCodeSection((PVOID)CdAudio435DeviceControl);
  363. break;
  364. case CDAUDIO_ATAPI:
  365. MmLockPagableCodeSection((PVOID)CdAudioAtapiDeviceControl);
  366. break;
  367. case CDAUDIO_HPCDR:
  368. MmLockPagableCodeSection((PVOID)CdAudioHPCdrDeviceControl);
  369. break;
  370. case CDAUDIO_SEARCH_ACTIVE:
  371. default:
  372. break;
  373. }
  374. //
  375. // Create the devObj so we are used
  376. //
  377. status = IoCreateDevice(DriverObject,
  378. sizeof(CD_DEVICE_EXTENSION),
  379. NULL,
  380. PhysicalDeviceObject->DeviceType,
  381. FILE_DEVICE_SECURE_OPEN,
  382. FALSE,
  383. &deviceObject);
  384. if (!NT_SUCCESS(status)) {
  385. CdDump(( 0,
  386. "AddDevice !! Unable to create device %lx\n",
  387. status
  388. ));
  389. // LOGLOG
  390. return status;
  391. }
  392. //
  393. // Set device object flags, device extension
  394. //
  395. deviceObject->Flags |= DO_DIRECT_IO;
  396. if (deviceObject->Flags & DO_POWER_INRUSH) {
  397. CdDump((0,
  398. "AddDevice ?? DO_POWER_INRUSH set for DO %p\n",
  399. deviceObject
  400. ));
  401. } else {
  402. deviceObject->Flags |= DO_POWER_PAGABLE;
  403. }
  404. extension = deviceObject->DeviceExtension;
  405. RtlZeroMemory(extension, sizeof(CD_DEVICE_EXTENSION));
  406. //
  407. // Useful to have next lower driver
  408. //
  409. extension->TargetDeviceObject =
  410. IoAttachDeviceToDeviceStack(deviceObject, PhysicalDeviceObject);
  411. if (!extension->TargetDeviceObject) {
  412. CdDump(( 0,
  413. "AddDevice !! Unable to attach to device stack %lx\n",
  414. STATUS_NO_SUCH_DEVICE
  415. ));
  416. // LOGLOG
  417. IoDeleteDevice(deviceObject);
  418. return STATUS_NO_SUCH_DEVICE;
  419. }
  420. KeInitializeEvent(&extension->PagingPathCountEvent, SynchronizationEvent, TRUE);
  421. //
  422. // Must set Active flag, Pdo
  423. //
  424. extension->Active = (UCHAR)regActive;
  425. extension->DeviceObject = deviceObject;
  426. extension->TargetPdo = PhysicalDeviceObject;
  427. //
  428. // No longer initializing
  429. //
  430. deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  431. return STATUS_SUCCESS;
  432. }
  433. NTSTATUS
  434. CdAudioSignalCompletion(
  435. IN PDEVICE_OBJECT DeviceObject,
  436. IN PIRP Irp,
  437. IN PKEVENT Event
  438. )
  439. /*++
  440. Routine Description:
  441. This completion routine will signal the event given as context and then
  442. return STATUS_MORE_PROCESSING_REQUIRED to stop event completion. It is
  443. the responsibility of the routine waiting on the event to complete the
  444. request and free the event.
  445. Arguments:
  446. DeviceObject - a pointer to the device object
  447. Irp - a pointer to the irp
  448. Event - a pointer to the event to signal
  449. Return Value:
  450. STATUS_MORE_PROCESSING_REQUIRED
  451. --*/
  452. {
  453. KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
  454. return STATUS_MORE_PROCESSING_REQUIRED;
  455. }
  456. NTSTATUS
  457. CdAudioStartDevice(
  458. IN PDEVICE_OBJECT DeviceObject,
  459. IN PIRP Irp
  460. )
  461. /*++
  462. Routine Description:
  463. Dispatch for START DEVICE.
  464. Arguments:
  465. DeviceObject - Supplies the device object.
  466. Irp - Supplies the I/O request packet.
  467. Return Value:
  468. NTSTATUS
  469. --*/
  470. {
  471. PCD_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  472. NTSTATUS status;
  473. KEVENT event;
  474. #if DBG
  475. UCHAR string[17];
  476. #endif
  477. CdDump((2, "StartDevice => Entering.\n"));
  478. status = CdAudioForwardIrpSynchronous(DeviceObject, Irp);
  479. if (!NT_SUCCESS(status)) {
  480. // LOGLOG - Should put some message into the system log
  481. return status;
  482. }
  483. ///
  484. /// From this point forward, not matter what occurs, we should
  485. /// return STATUS_SUCCESS. The rest of the code is non-critical,
  486. /// and the worst occurance is that audio will not play on a CDROM.
  487. ///
  488. CdDump((2, "StartDevice => Starting\n"));
  489. //
  490. // Initialize device extension data
  491. //
  492. deviceExtension->Paused = CDAUDIO_NOT_PAUSED;
  493. deviceExtension->PausedM = 0;
  494. deviceExtension->PausedS = 0;
  495. deviceExtension->PausedF = 0;
  496. deviceExtension->LastEndM = 0;
  497. deviceExtension->LastEndS = 0;
  498. deviceExtension->LastEndF = 0;
  499. //
  500. // deviceExtension->Active possibly set from registry in AddDevice
  501. //
  502. ASSERT(deviceExtension->Active > 0);
  503. ASSERT((deviceExtension->Active <= CDAUDIO_MAX_ACTIVE) ||
  504. (deviceExtension->Active == CDAUDIO_SEARCH_ACTIVE));
  505. //
  506. // Search for the type of translation via the inquiry data
  507. // if registry value DNE or says to. Otherwise, use the
  508. // registry value (gotten in CdAudioAddDevice) as the Active Value
  509. //
  510. if (deviceExtension->Active == (UCHAR)CDAUDIO_SEARCH_ACTIVE) {
  511. SCSI_PASS_THROUGH srb;
  512. PCDB cdb = (PCDB) srb.Cdb;
  513. PUCHAR inquiryDataPtr = NULL;
  514. UCHAR attempt = 0;
  515. CdDump(( 1,
  516. "StartDevice => Searching for map type via InquiryData\n"
  517. ));
  518. //
  519. // Allocate buffer for returned inquiry data
  520. //
  521. inquiryDataPtr = (PUCHAR)ExAllocatePool( NonPagedPoolCacheAligned,
  522. INQUIRYDATABUFFERSIZE
  523. );
  524. if (!inquiryDataPtr) {
  525. CdDump(( 0,
  526. "StartDevice !! Insufficient resources for inquiry data\n"
  527. ));
  528. deviceExtension->Active = CDAUDIO_NOT_ACTIVE;
  529. // LOGLOG
  530. return STATUS_SUCCESS;
  531. }
  532. //
  533. // Force it into the loop
  534. //
  535. status = STATUS_UNSUCCESSFUL;
  536. CdDump(( 4,
  537. "StartDevice => Inquiry Data at %p\n",
  538. inquiryDataPtr
  539. ));
  540. //
  541. // Try to get inquiry data a few times
  542. //
  543. while (
  544. !(NT_SUCCESS(status)) &&
  545. (attempt++ < MAXIMUM_RETRIES)
  546. ) {
  547. CdDump(( 1,
  548. "StartDevice => Inquiry attempt %d\n",
  549. attempt
  550. ));
  551. //
  552. // Zero SRB (including cdb)
  553. //
  554. RtlZeroMemory( &srb, sizeof(SCSI_PASS_THROUGH) );
  555. //
  556. // Just for safety, zero the inquiryDataPtr
  557. //
  558. RtlZeroMemory( inquiryDataPtr, INQUIRYDATABUFFERSIZE );
  559. //
  560. // Fill in CDB for INQUIRY to CDROM
  561. //
  562. cdb->CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY;
  563. cdb->CDB6INQUIRY.AllocationLength = INQUIRYDATABUFFERSIZE;
  564. //
  565. // Inquiry length is 6, with timeout
  566. //
  567. srb.CdbLength = 6;
  568. srb.TimeOutValue = AUDIO_TIMEOUT;
  569. status = SendSrbSynchronous( deviceExtension,
  570. &srb,
  571. inquiryDataPtr,
  572. INQUIRYDATABUFFERSIZE
  573. );
  574. CdDump(( 2,
  575. "StartDevice => Inquiry status for attempt %d is %lx\n",
  576. attempt,
  577. status
  578. ));
  579. }
  580. //
  581. // So if it failed a bunch of times....
  582. //
  583. if (!NT_SUCCESS(status)) {
  584. CdDump(( 1, "StartDevice !! Inquiry failed! %lx\n", status ));
  585. ExFreePool( inquiryDataPtr );
  586. // LOGLOG
  587. //
  588. // Do not translate any commands if we cannot determine
  589. // the drive type. Better to lose audio than to lose
  590. // data functionality.
  591. //
  592. deviceExtension->Active = CDAUDIO_NOT_ACTIVE;
  593. return STATUS_SUCCESS;
  594. }
  595. #if DBG
  596. RtlZeroMemory( string, 17 );
  597. RtlCopyMemory( string, &(inquiryDataPtr[8]), 8 );
  598. CdDump((2, "StartDevice => Vendor '%s'\n", string));
  599. RtlZeroMemory( string, 17 );
  600. RtlCopyMemory( string, &(inquiryDataPtr[16]), 16 );
  601. CdDump((2, "StartDevice => Drive '%s'\n", string));
  602. #endif
  603. //
  604. // Conduct a search by the inquiry data
  605. //
  606. {
  607. //
  608. // Set the default value to NONE (not SEARCH_ACTIVE)
  609. //
  610. deviceExtension->Active = CDAUDIO_NOT_ACTIVE;
  611. //
  612. // Check for NEC drive
  613. //
  614. if ( RtlEqualMemory( &(inquiryDataPtr[8]), "NEC ", 8 )) {
  615. if (NecSupportNeeded(inquiryDataPtr)) {
  616. MmLockPagableCodeSection((PVOID)CdAudioNECDeviceControl);
  617. deviceExtension->Active = CDAUDIO_NEC;
  618. }
  619. }
  620. //
  621. // Check for PIONEER DRM-600 and DRM-600x drives
  622. //
  623. if ( (RtlEqualMemory( &(inquiryDataPtr[8]), "PIONEER ", 8 )) &&
  624. (RtlEqualMemory( &(inquiryDataPtr[16]), "CD-ROM DRM-600", 15 ))
  625. ) {
  626. MmLockPagableCodeSection((PVOID)CdAudioPioneerDeviceControl);
  627. deviceExtension->Active = CDAUDIO_PIONEER;
  628. }
  629. //
  630. // Check for DENON drive
  631. //
  632. if ((inquiryDataPtr[8] =='D') &&
  633. (inquiryDataPtr[9] =='E') &&
  634. (inquiryDataPtr[10]=='N') &&
  635. (inquiryDataPtr[16]=='D') &&
  636. (inquiryDataPtr[17]=='R') &&
  637. (inquiryDataPtr[18]=='D') &&
  638. (inquiryDataPtr[20]=='2') &&
  639. (inquiryDataPtr[21]=='5') &&
  640. (inquiryDataPtr[22]=='X')) {
  641. MmLockPagableCodeSection((PVOID)CdAudioDenonDeviceControl);
  642. deviceExtension->Active = CDAUDIO_DENON;
  643. }
  644. if ( RtlEqualMemory( &(inquiryDataPtr[8]), "CHINON", 6 )) {
  645. //
  646. // Check for Chinon CDS-535
  647. //
  648. if ((inquiryDataPtr[27]=='5') &&
  649. (inquiryDataPtr[28]=='3') &&
  650. (inquiryDataPtr[29]=='5') &&
  651. (inquiryDataPtr[32]=='Q')
  652. ) {
  653. MmLockPagableCodeSection((PVOID)CdAudio535DeviceControl);
  654. deviceExtension->Active = CDAUDIO_CDS535;
  655. }
  656. //
  657. // Check for Chinon CDS-435 or CDS-431
  658. // (willing to handle versions M/N, S/U, and H)
  659. //
  660. if ((inquiryDataPtr[27]=='4') &&
  661. (inquiryDataPtr[28]=='3') &&
  662. ((inquiryDataPtr[29]=='5') ||
  663. (inquiryDataPtr[29]=='1')
  664. ) &&
  665. ((inquiryDataPtr[32]=='M') ||
  666. (inquiryDataPtr[32]=='N') ||
  667. (inquiryDataPtr[32]=='S') ||
  668. (inquiryDataPtr[32]=='U') ||
  669. (inquiryDataPtr[32]=='H')
  670. )
  671. ) {
  672. MmLockPagableCodeSection((PVOID)CdAudio435DeviceControl);
  673. deviceExtension->Active = CDAUDIO_CDS435;
  674. }
  675. //
  676. // End of the Chinon drives
  677. //
  678. }
  679. //
  680. // Check for HITACHI drives
  681. //
  682. if ( (RtlEqualMemory( &(inquiryDataPtr[8]), "HITACHI ", 8 )) &&
  683. ( (RtlEqualMemory( &(inquiryDataPtr[16]), "CDR-3650/1650S ", 16 )) ||
  684. (RtlEqualMemory( &(inquiryDataPtr[16]), "CDR-1750S ", 16 ))
  685. )
  686. ) {
  687. MmLockPagableCodeSection((PVOID)CdAudioHitachiDeviceControl);
  688. deviceExtension->Active = CDAUDIO_HITACHI;
  689. }
  690. //
  691. // Check for Atapi drives that require support.
  692. //
  693. if ( ((RtlEqualMemory( &(inquiryDataPtr[8]), "WEARNES ", 8 )) &&
  694. (RtlEqualMemory( &(inquiryDataPtr[16]), "RUB", 3 ))
  695. ) ||
  696. ((RtlEqualMemory( &(inquiryDataPtr[8]), "OTI ", 8)) &&
  697. (RtlEqualMemory( &(inquiryDataPtr[16]), "DOLPHIN ", 8))
  698. )
  699. ) {
  700. MmLockPagableCodeSection((PVOID)CdAudioAtapiDeviceControl);
  701. deviceExtension->Active = CDAUDIO_ATAPI;
  702. inquiryDataPtr[25] = (UCHAR)0;
  703. }
  704. //
  705. // Check for FUJITSU drives
  706. //
  707. if (RtlEqualMemory( &(inquiryDataPtr[8]), "FUJITSU ", 8 )) {
  708. //
  709. // It's a Fujitsu drive...is it one we want to
  710. // handle...?
  711. if ((inquiryDataPtr[16]=='C') &&
  712. (inquiryDataPtr[17]=='D') &&
  713. (inquiryDataPtr[18]=='R') &&
  714. (inquiryDataPtr[20]=='3') &&
  715. (inquiryDataPtr[21]=='6') &&
  716. (inquiryDataPtr[22]=='5') &&
  717. (inquiryDataPtr[23]=='0')) {
  718. //
  719. // Yes, we want to handle this as HITACHI compatible drive
  720. //
  721. MmLockPagableCodeSection((PVOID)CdAudioHitachiDeviceControl);
  722. deviceExtension->Active = CDAUDIO_HITACHI;
  723. inquiryDataPtr[25] = (UCHAR)0;
  724. } else if ((inquiryDataPtr[16]=='F') &&
  725. (inquiryDataPtr[17]=='M') &&
  726. (inquiryDataPtr[18]=='C') &&
  727. (inquiryDataPtr[21]=='1') &&
  728. (inquiryDataPtr[22]=='0') &&
  729. ((inquiryDataPtr[23]=='1') ||
  730. (inquiryDataPtr[23]=='2')) ) {
  731. //
  732. // Yes, we want to handle this as FUJITSU drive
  733. //
  734. MmLockPagableCodeSection((PVOID)CdAudioHitachiDeviceControl);
  735. deviceExtension->Active = CDAUDIO_FUJITSU;
  736. inquiryDataPtr[25] = (UCHAR)0;
  737. }
  738. }
  739. //
  740. // Check for HP CDR
  741. //
  742. if ((RtlEqualMemory( &(inquiryDataPtr[8]), "HP ", 8 )) &&
  743. (RtlEqualMemory( &(inquiryDataPtr[16]), "C4324/C4325", 11 ))
  744. ) {
  745. MmLockPagableCodeSection((PVOID)CdAudioHPCdrDeviceControl);
  746. deviceExtension->Active = CDAUDIO_HPCDR;
  747. }
  748. }
  749. ExFreePool( inquiryDataPtr );
  750. }
  751. CdDump((2,
  752. "StartDevice => Active is set to %x\n",
  753. deviceExtension->Active));
  754. //
  755. // Store the value in the registry so the inquiry data does
  756. // not have to be read and searched.
  757. //
  758. {
  759. HANDLE deviceParameterHandle;
  760. ULONG keyValue = (ULONG)deviceExtension->Active;
  761. //
  762. // Open a handle to the key
  763. //
  764. status = IoOpenDeviceRegistryKey(deviceExtension->TargetPdo,
  765. PLUGPLAY_REGKEY_DRIVER,
  766. KEY_WRITE,
  767. &deviceParameterHandle);
  768. if (!NT_SUCCESS(status)) {
  769. CdDump(( 0,
  770. "StartDevice !! Failed to open registry %lx\n",
  771. status
  772. ));
  773. // LOGLOG
  774. //
  775. // Handle not open, so just
  776. //
  777. return STATUS_SUCCESS;
  778. }
  779. //
  780. // Write the value
  781. //
  782. status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE,
  783. (PWSTR) deviceParameterHandle,
  784. CDAUDIO_ACTIVE_KEY_NAME,
  785. REG_DWORD,
  786. &keyValue,
  787. sizeof(keyValue));
  788. if (!NT_SUCCESS(status)) {
  789. //
  790. // This is a non-fatal error, so just write to debugger?
  791. //
  792. CdDump(( 0,
  793. "StartDevice !! Failed to write registry %lx\n",
  794. status
  795. ));
  796. // LOGLOG
  797. //
  798. // But fall through to close the handle to the registry
  799. //
  800. }
  801. //
  802. // Don't forget to close what we open...
  803. //
  804. ZwClose(deviceParameterHandle);
  805. CdDump(( 2,
  806. "StartDevice => Wrote value %x successfully\n",
  807. deviceExtension->Active
  808. ));
  809. }
  810. return STATUS_SUCCESS;
  811. }
  812. NTSTATUS
  813. CdAudioPnp(
  814. IN PDEVICE_OBJECT DeviceObject,
  815. IN PIRP Irp
  816. )
  817. /*++
  818. Routine Description:
  819. Dispatch for PNP
  820. Arguments:
  821. DeviceObject - Supplies the device object.
  822. Irp - Supplies the I/O request packet.
  823. Return Value:
  824. NTSTATUS
  825. --*/
  826. {
  827. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  828. NTSTATUS status = STATUS_NOT_SUPPORTED;
  829. switch (irpSp->MinorFunction) {
  830. case IRP_MN_START_DEVICE: {
  831. status = CdAudioStartDevice(DeviceObject, Irp);
  832. Irp->IoStatus.Status = status;
  833. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  834. return status;
  835. }
  836. case IRP_MN_DEVICE_USAGE_NOTIFICATION: {
  837. ULONG count;
  838. BOOLEAN setPagable;
  839. PCD_DEVICE_EXTENSION deviceExtension;
  840. if (irpSp->Parameters.UsageNotification.Type != DeviceUsageTypePaging) {
  841. return CdAudioSendToNextDriver(DeviceObject, Irp);
  842. }
  843. deviceExtension = DeviceObject->DeviceExtension;
  844. //
  845. // wait on the paging path event
  846. //
  847. status = KeWaitForSingleObject(&deviceExtension->PagingPathCountEvent,
  848. Executive, KernelMode,
  849. FALSE, NULL);
  850. //
  851. // if removing last paging device, need to clear DO_POWER_PAGABLE
  852. // bit here, and possible re-set it below on failure.
  853. //
  854. setPagable = FALSE;
  855. if (!irpSp->Parameters.UsageNotification.InPath &&
  856. deviceExtension->PagingPathCount == 1 ) {
  857. //
  858. // removing the last paging file
  859. // must have DO_POWER_PAGABLE bits set
  860. //
  861. if (DeviceObject->Flags & DO_POWER_INRUSH) {
  862. CdDump((2, "Pnp: Last paging file removed "
  863. "but DO_POWER_INRUSH set, so not setting PAGABLE bit "
  864. "for DO %p\n", DeviceObject));
  865. } else {
  866. CdDump((2, "Pnp: Setting PAGABLE bit "
  867. "for DO %p\n", DeviceObject));
  868. DeviceObject->Flags |= DO_POWER_PAGABLE;
  869. setPagable = TRUE;
  870. }
  871. }
  872. //
  873. // send the irp synchronously
  874. //
  875. status = CdAudioForwardIrpSynchronous(DeviceObject, Irp);
  876. //
  877. // now deal with the failure and success cases.
  878. // note that we are not allowed to fail the irp
  879. // once it is sent to the lower drivers.
  880. //
  881. if (NT_SUCCESS(status)) {
  882. IoAdjustPagingPathCount(
  883. &deviceExtension->PagingPathCount,
  884. irpSp->Parameters.UsageNotification.InPath);
  885. if (irpSp->Parameters.UsageNotification.InPath) {
  886. if (deviceExtension->PagingPathCount == 1) {
  887. CdDump((2, "Pnp: Clearing PAGABLE bit "
  888. "for DO %p\n", DeviceObject));
  889. DeviceObject->Flags &= ~DO_POWER_PAGABLE;
  890. }
  891. } // end InPath if/else
  892. } else {
  893. //
  894. // cleanup the changes done above
  895. //
  896. if (setPagable == TRUE) {
  897. CdDump((2, "Pnp: Un-setting pagable bit for DO %p\n", DeviceObject));
  898. DeviceObject->Flags &= ~DO_POWER_PAGABLE;
  899. setPagable = FALSE;
  900. }
  901. }
  902. //
  903. // set the event so the next one can occur.
  904. //
  905. KeSetEvent(&deviceExtension->PagingPathCountEvent,
  906. IO_NO_INCREMENT, FALSE);
  907. //
  908. // and complete the irp
  909. //
  910. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  911. return status;
  912. break;
  913. }
  914. default:
  915. return CdAudioSendToNextDriver(DeviceObject, Irp);
  916. }
  917. }
  918. NTSTATUS
  919. DriverEntry(
  920. IN PDRIVER_OBJECT DriverObject,
  921. IN PUNICODE_STRING RegistryPath
  922. )
  923. /*++
  924. Routine Description:
  925. Initialize CdAudio driver.
  926. This is the system initialization entry point
  927. when the driver is linked into the kernel.
  928. Arguments:
  929. DriverObject
  930. Return Value:
  931. NTSTATUS
  932. --*/
  933. {
  934. ULONG i;
  935. //
  936. // Send everything down unless specifically handled.
  937. //
  938. for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) {
  939. DriverObject->MajorFunction[i] = CdAudioSendToNextDriver;
  940. }
  941. DriverObject->MajorFunction[IRP_MJ_READ] = CdAudioReadWrite;
  942. DriverObject->MajorFunction[IRP_MJ_WRITE] = CdAudioReadWrite;
  943. DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = CdAudioDeviceControl;
  944. DriverObject->MajorFunction[IRP_MJ_PNP] = CdAudioPnp;
  945. DriverObject->MajorFunction[IRP_MJ_POWER] = CdAudioPower;
  946. DriverObject->DriverExtension->AddDevice = CdAudioAddDevice;
  947. DriverObject->DriverUnload = CdAudioUnload;
  948. return STATUS_SUCCESS;
  949. }
  950. #define NEC_CDAUDIO_SUPPORT_DRIVES 12
  951. BOOLEAN
  952. NecSupportNeeded(
  953. PUCHAR InquiryData
  954. )
  955. /*++
  956. Routine Description:
  957. This routine determines whether the NEC drive in question
  958. needs assistance from this driver.
  959. Arguments:
  960. InquiryData - Pointer to the inquiry data buffer.
  961. Return Value:
  962. TRUE - if support is needed.
  963. --*/
  964. {
  965. PINQUIRYDATA inquiryData = (PINQUIRYDATA)InquiryData;
  966. ULONG i;
  967. PUCHAR badDriveList[NEC_CDAUDIO_SUPPORT_DRIVES] = {
  968. "CD-ROM DRIVE:80 ", // must be 16 byte long
  969. "CD-ROM DRIVE:82 ",
  970. "CD-ROM DRIVE:83 ",
  971. "CD-ROM DRIVE:84 ",
  972. "CD-ROM DRIVE:841",
  973. "CD-ROM DRIVE:38 ",
  974. "CD-ROM DRIVE 4 M",
  975. "CD-ROM DRIVE:500",
  976. "CD-ROM DRIVE:400",
  977. "CD-ROM DRIVE:401",
  978. "CD-ROM DRIVE:501",
  979. "CD-ROM DRIVE:900"};
  980. for (i = 0; i < NEC_CDAUDIO_SUPPORT_DRIVES; i++) {
  981. if (RtlCompareMemory(inquiryData->ProductId, badDriveList[i], 16)==16) {
  982. return TRUE;
  983. }
  984. }
  985. return FALSE;
  986. }
  987. NTSTATUS
  988. CdAudioReadWrite(
  989. IN PDEVICE_OBJECT DeviceObject,
  990. IN PIRP Irp
  991. )
  992. /*++
  993. Routine Description:
  994. This is the driver entry point for read and write requests
  995. to the cdrom. Since we only want to trap device control requests,
  996. we will just pass these requests on to the original driver.
  997. Arguments:
  998. DeviceObject - pointer to device object for disk partition
  999. Irp - NT IO Request Packet
  1000. Return Value:
  1001. NTSTATUS - status of request
  1002. --*/
  1003. {
  1004. PCD_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  1005. //
  1006. // If the cd is playing music then reject this request.
  1007. //
  1008. if (deviceExtension->PlayActive) {
  1009. Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
  1010. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1011. return STATUS_DEVICE_BUSY;
  1012. }
  1013. //
  1014. // simply return status of driver below us...
  1015. //
  1016. return CdAudioSendToNextDriver(DeviceObject, Irp);
  1017. }
  1018. NTSTATUS
  1019. CdAudioDeviceControl(
  1020. PDEVICE_OBJECT DeviceObject,
  1021. PIRP Irp
  1022. )
  1023. /*++
  1024. Routine Description:
  1025. This routine is called by the I/O subsystem for device controls.
  1026. Arguments:
  1027. DeviceObject
  1028. Irp
  1029. Return Value:
  1030. NTSTATUS
  1031. --*/
  1032. {
  1033. PCD_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  1034. NTSTATUS status;
  1035. switch ( deviceExtension->Active ) {
  1036. case CDAUDIO_SEARCH_ACTIVE:
  1037. //
  1038. // This occurs while we have not finished StartDevice()
  1039. //
  1040. status = CdAudioSendToNextDriver( DeviceObject, Irp );
  1041. break;
  1042. case CDAUDIO_NOT_ACTIVE:
  1043. CdDump(( 3,
  1044. "DeviceControl => NOT ACTIVE for this drive.\n"
  1045. ));
  1046. status = CdAudioSendToNextDriver( DeviceObject, Irp );
  1047. break;
  1048. case CDAUDIO_NEC:
  1049. status = CdAudioNECDeviceControl( DeviceObject, Irp );
  1050. break;
  1051. case CDAUDIO_PIONEER:
  1052. case CDAUDIO_PIONEER624:
  1053. status = CdAudioPioneerDeviceControl( DeviceObject, Irp );
  1054. break;
  1055. case CDAUDIO_DENON:
  1056. status = CdAudioDenonDeviceControl( DeviceObject, Irp );
  1057. break;
  1058. case CDAUDIO_FUJITSU:
  1059. case CDAUDIO_HITACHI:
  1060. status = CdAudioHitachiDeviceControl( DeviceObject, Irp );
  1061. break;
  1062. case CDAUDIO_CDS535:
  1063. status = CdAudio535DeviceControl( DeviceObject, Irp );
  1064. break;
  1065. case CDAUDIO_CDS435:
  1066. status = CdAudio435DeviceControl( DeviceObject, Irp );
  1067. break;
  1068. case CDAUDIO_ATAPI:
  1069. status = CdAudioAtapiDeviceControl( DeviceObject, Irp );
  1070. break;
  1071. case CDAUDIO_HPCDR:
  1072. status = CdAudioHPCdrDeviceControl( DeviceObject, Irp );
  1073. break;
  1074. default:
  1075. // LOGLOG
  1076. CdDump(( 0,
  1077. "DeviceControl !! Active==UNKNOWN %x\n",
  1078. deviceExtension->Active
  1079. ));
  1080. ASSERT(FALSE);
  1081. deviceExtension->Active = CDAUDIO_NOT_ACTIVE;
  1082. status = CdAudioSendToNextDriver( DeviceObject, Irp );
  1083. }
  1084. return status;
  1085. }
  1086. NTSTATUS
  1087. CdAudioSendToNextDriver(
  1088. PDEVICE_OBJECT DeviceObject,
  1089. PIRP Irp
  1090. )
  1091. /*++
  1092. Routine Description:
  1093. This routine is sends the Irp to the next driver in line
  1094. when the Irp is not processed by this driver.
  1095. Arguments:
  1096. DeviceObject
  1097. Irp
  1098. Return Value:
  1099. NTSTATUS
  1100. --*/
  1101. {
  1102. PCD_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  1103. IoSkipCurrentIrpStackLocation(Irp);
  1104. return IoCallDriver(deviceExtension->TargetDeviceObject, Irp);
  1105. }
  1106. BOOLEAN
  1107. CdAudioIsPlayActive(
  1108. IN PDEVICE_OBJECT DeviceObject
  1109. )
  1110. /*++
  1111. Routine Description:
  1112. This routine determines if the cd is currently playing music.
  1113. Arguments:
  1114. DeviceObject - Device object to test.
  1115. Return Value:
  1116. TRUE if the device is playing music.
  1117. --*/
  1118. {
  1119. PCD_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  1120. PIRP irp;
  1121. IO_STATUS_BLOCK ioStatus;
  1122. KEVENT event;
  1123. NTSTATUS status;
  1124. PSUB_Q_CURRENT_POSITION currentBuffer;
  1125. BOOLEAN returnValue;
  1126. if (!deviceExtension->PlayActive) {
  1127. return(FALSE);
  1128. }
  1129. currentBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
  1130. sizeof(SUB_Q_CURRENT_POSITION));
  1131. if (currentBuffer == NULL) {
  1132. return(FALSE);
  1133. }
  1134. ((PCDROM_SUB_Q_DATA_FORMAT) currentBuffer)->Format =
  1135. IOCTL_CDROM_CURRENT_POSITION;
  1136. ((PCDROM_SUB_Q_DATA_FORMAT) currentBuffer)->Track = 0;
  1137. //
  1138. // Create notification event object to be used to signal the
  1139. // request completion.
  1140. //
  1141. KeInitializeEvent(&event, NotificationEvent, FALSE);
  1142. //
  1143. // Build the synchronous request to be sent to the port driver
  1144. // to perform the request.
  1145. //
  1146. irp = IoBuildDeviceIoControlRequest(IOCTL_CDROM_READ_Q_CHANNEL,
  1147. deviceExtension->DeviceObject,
  1148. currentBuffer,
  1149. sizeof(CDROM_SUB_Q_DATA_FORMAT),
  1150. currentBuffer,
  1151. sizeof(SUB_Q_CURRENT_POSITION),
  1152. FALSE,
  1153. &event,
  1154. &ioStatus);
  1155. if (irp == NULL) {
  1156. ExFreePool(currentBuffer);
  1157. return FALSE;
  1158. }
  1159. //
  1160. // Pass request to port driver and wait for request to complete.
  1161. //
  1162. status = IoCallDriver(deviceExtension->DeviceObject, irp);
  1163. if (status == STATUS_PENDING) {
  1164. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  1165. status = ioStatus.Status;
  1166. }
  1167. if (!NT_SUCCESS(status)) {
  1168. ExFreePool(currentBuffer);
  1169. return FALSE;
  1170. }
  1171. if (currentBuffer->Header.AudioStatus == AUDIO_STATUS_IN_PROGRESS) {
  1172. returnValue = TRUE;
  1173. } else {
  1174. returnValue = FALSE;
  1175. deviceExtension->PlayActive = FALSE;
  1176. }
  1177. ExFreePool(currentBuffer);
  1178. return(returnValue);
  1179. }
  1180. NTSTATUS
  1181. CdAudioNECDeviceControl(
  1182. PDEVICE_OBJECT DeviceObject,
  1183. PIRP Irp
  1184. )
  1185. /*++
  1186. Routine Description:
  1187. This routine is called by CdAudioDeviceControl to handle
  1188. audio IOCTLs sent to NEC cdrom drives.
  1189. Arguments:
  1190. DeviceObject
  1191. Irp
  1192. Return Value:
  1193. NTSTATUS
  1194. --*/
  1195. {
  1196. PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
  1197. PCD_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  1198. PCDROM_TOC cdaudioDataOut = Irp->AssociatedIrp.SystemBuffer;
  1199. SCSI_PASS_THROUGH srb;
  1200. PNEC_CDB cdb = (PNEC_CDB)srb.Cdb;
  1201. NTSTATUS status;
  1202. ULONG i,bytesTransfered;
  1203. PUCHAR Toc;
  1204. ULONG retryCount = 0;
  1205. ULONG address;
  1206. LARGE_INTEGER delay;
  1207. NECRestart:
  1208. //
  1209. // Clear out cdb
  1210. //
  1211. RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
  1212. //
  1213. // What IOCTL do we need to execute?
  1214. //
  1215. switch (currentIrpStack->Parameters.DeviceIoControl.IoControlCode) {
  1216. case IOCTL_CDROM_GET_LAST_SESSION:
  1217. CdDump(( 2,
  1218. "NECDeviceControl => IOCTL_CDROM_GET_LAST_SESSION recv'd.\n"
  1219. ));
  1220. //
  1221. // Ensure we have a large enough buffer?
  1222. //
  1223. if (currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength <
  1224. (ULONG)FIELD_OFFSET(CDROM_TOC, TrackData[1])) {
  1225. status = STATUS_BUFFER_TOO_SMALL;
  1226. // we have transferred zero bytes
  1227. Irp->IoStatus.Information = 0;
  1228. break;
  1229. }
  1230. //
  1231. // If the cd is playing music then reject this request.
  1232. //
  1233. if (CdAudioIsPlayActive(DeviceObject)) {
  1234. Irp->IoStatus.Information = 0;
  1235. status = STATUS_DEVICE_BUSY;
  1236. break;
  1237. }
  1238. //
  1239. // Allocate storage to hold TOC from disc
  1240. //
  1241. Toc = (PUCHAR)ExAllocatePool( NonPagedPoolCacheAligned,
  1242. NEC_CDROM_TOC_SIZE
  1243. );
  1244. if ( Toc == NULL ) {
  1245. status = STATUS_INSUFFICIENT_RESOURCES;
  1246. Irp->IoStatus.Information = 0;
  1247. goto SetStatusAndReturn;
  1248. }
  1249. //
  1250. // Set up defaults
  1251. //
  1252. RtlZeroMemory( Toc, NEC_CDROM_TOC_SIZE );
  1253. srb.CdbLength = 10;
  1254. //
  1255. // Fill in CDB
  1256. //
  1257. cdb->NEC_READ_TOC.OperationCode = NEC_READ_TOC_CODE;
  1258. cdb->NEC_READ_TOC.Type = NEC_TRANSFER_WHOLE_TOC;
  1259. cdb->NEC_READ_TOC.TrackNumber = NEC_TOC_TYPE_SESSION;
  1260. srb.TimeOutValue = AUDIO_TIMEOUT;
  1261. status = SendSrbSynchronous(
  1262. deviceExtension,
  1263. &srb,
  1264. Toc,
  1265. NEC_CDROM_TOC_SIZE
  1266. );
  1267. if (!NT_SUCCESS(status) && (status!=STATUS_DATA_OVERRUN)) {
  1268. CdDump(( 1,
  1269. "NECDeviceControl => READ_TOC error, status %lx\n",
  1270. status ));
  1271. ExFreePool( Toc );
  1272. Irp->IoStatus.Information = 0;
  1273. goto SetStatusAndReturn;
  1274. } else {
  1275. status = STATUS_SUCCESS;
  1276. }
  1277. //
  1278. // Translate data into our format.
  1279. //
  1280. bytesTransfered = FIELD_OFFSET(CDROM_TOC, TrackData[1]);
  1281. Irp->IoStatus.Information = bytesTransfered;
  1282. RtlZeroMemory(cdaudioDataOut, bytesTransfered);
  1283. cdaudioDataOut->Length[0] = (UCHAR)((bytesTransfered - 2) >> 8);
  1284. cdaudioDataOut->Length[1] = (UCHAR)((bytesTransfered - 2) & 0xFF);
  1285. //
  1286. // Determine if this is a multisession cd.
  1287. //
  1288. if (*((ULONG UNALIGNED *) &Toc[14]) == 0) {
  1289. //
  1290. // This is a single session disk. Just return.
  1291. //
  1292. ExFreePool(Toc);
  1293. break;
  1294. }
  1295. //
  1296. // Fake the session information.
  1297. //
  1298. cdaudioDataOut->FirstTrack = 1;
  1299. cdaudioDataOut->LastTrack = 2;
  1300. CdDump(( 4,
  1301. "NECDeviceControl => Tracks %d - %d, (%x bytes)\n",
  1302. cdaudioDataOut->FirstTrack,
  1303. cdaudioDataOut->LastTrack,
  1304. bytesTransfered
  1305. ));
  1306. //
  1307. // Grab Information for the last session.
  1308. //
  1309. cdaudioDataOut->TrackData[0].Reserved = 0;
  1310. cdaudioDataOut->TrackData[0].Control =
  1311. ((Toc[2] & 0x0F) << 4) | (Toc[2] >> 4);
  1312. cdaudioDataOut->TrackData[0].TrackNumber = 1;
  1313. cdaudioDataOut->TrackData[0].Reserved1 = 0;
  1314. //
  1315. // Convert the minutes, seconds and frames to an absolute block
  1316. // address. The formula comes from NEC.
  1317. //
  1318. address = (BCD_TO_DEC(Toc[15]) * 60 + BCD_TO_DEC(Toc[16])) * 75
  1319. + BCD_TO_DEC(Toc[17]);
  1320. //
  1321. // Put the address in big-endian in the the user's TOC.
  1322. //
  1323. cdaudioDataOut->TrackData[0].Address[0] = (UCHAR) (address >> 24);
  1324. cdaudioDataOut->TrackData[0].Address[1] = (UCHAR) (address >> 16);
  1325. cdaudioDataOut->TrackData[0].Address[2] = (UCHAR) (address >> 8);
  1326. cdaudioDataOut->TrackData[0].Address[3] = (UCHAR) address;
  1327. //
  1328. // Free storage now that we've stored it elsewhere
  1329. //
  1330. ExFreePool( Toc );
  1331. break;
  1332. case IOCTL_CDROM_READ_TOC:
  1333. CdDump(( 2,
  1334. "NECDeviceControl => IOCTL_CDROM_READ_TOC recv'd.\n"
  1335. ));
  1336. //
  1337. // If the cd is playing music then reject this request.
  1338. //
  1339. if (CdAudioIsPlayActive(DeviceObject)) {
  1340. status = STATUS_DEVICE_BUSY;
  1341. Irp->IoStatus.Information = 0;
  1342. break;
  1343. }
  1344. //
  1345. // Must have allocated at least enough buffer space
  1346. // to store how many tracks are on the disc
  1347. //
  1348. if (currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength <
  1349. ((ULONG)FIELD_OFFSET(CDROM_TOC, TrackData[0]))
  1350. ) {
  1351. status = STATUS_BUFFER_TOO_SMALL;
  1352. // we have transferred zero bytes
  1353. Irp->IoStatus.Information = 0;
  1354. break;
  1355. }
  1356. //
  1357. // Allocate storage to hold TOC from disc
  1358. //
  1359. Toc = (PUCHAR)ExAllocatePool( NonPagedPoolCacheAligned,
  1360. NEC_CDROM_TOC_SIZE
  1361. );
  1362. if ( Toc == NULL ) {
  1363. status = STATUS_INSUFFICIENT_RESOURCES;
  1364. Irp->IoStatus.Information = 0;
  1365. goto SetStatusAndReturn;
  1366. }
  1367. CdDump(( 4,
  1368. "NECDeviceControl => Toc = %p cdaudioDataOut = %p\n",
  1369. Toc, cdaudioDataOut
  1370. ));
  1371. //
  1372. // Set up defaults
  1373. //
  1374. RtlZeroMemory( Toc, NEC_CDROM_TOC_SIZE );
  1375. srb.CdbLength = 10;
  1376. //
  1377. // Fill in CDB
  1378. //
  1379. cdb->NEC_READ_TOC.OperationCode = NEC_READ_TOC_CODE;
  1380. cdb->NEC_READ_TOC.Type = NEC_TRANSFER_WHOLE_TOC;
  1381. srb.TimeOutValue = AUDIO_TIMEOUT;
  1382. status = SendSrbSynchronous(
  1383. deviceExtension,
  1384. &srb,
  1385. Toc,
  1386. NEC_CDROM_TOC_SIZE
  1387. );
  1388. if (!NT_SUCCESS(status) && (status!=STATUS_DATA_OVERRUN)) {
  1389. CdDump(( 1,
  1390. "NECDeviceControl => READ_TOC error (%lx)\n",
  1391. status ));
  1392. if (status != STATUS_DATA_OVERRUN) {
  1393. CdDump(( 1, "NECDeviceControl => SRB ERROR (%lx)\n",
  1394. status ));
  1395. Irp->IoStatus.Information = 0;
  1396. ExFreePool( Toc );
  1397. goto SetStatusAndReturn;
  1398. }
  1399. } else {
  1400. status = STATUS_SUCCESS;
  1401. }
  1402. //
  1403. // Translate data into our format.
  1404. //
  1405. bytesTransfered =
  1406. currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength >
  1407. sizeof(CDROM_TOC) ?
  1408. sizeof(CDROM_TOC) :
  1409. currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
  1410. cdaudioDataOut->FirstTrack = BCD_TO_DEC(Toc[9]);
  1411. cdaudioDataOut->LastTrack = BCD_TO_DEC(Toc[19]);
  1412. CdDump(( 4,
  1413. "NECDeviceControl => Tracks %d - %d, (%x bytes)\n",
  1414. cdaudioDataOut->FirstTrack,
  1415. cdaudioDataOut->LastTrack,
  1416. bytesTransfered
  1417. ));
  1418. //
  1419. // Return only N number of tracks, where N is the number of
  1420. // full tracks of info we can stuff into the user buffer
  1421. // if tracks from 1 to 2, that means there are two tracks,
  1422. // so let i go from 0 to 1 (two tracks of info)
  1423. //
  1424. {
  1425. //
  1426. // tracksToReturn == Number of real track info to return
  1427. // tracksInBuffer == How many fit into the user-supplied buffer
  1428. // tracksOnCd == Number of tracks on the CD (not including lead-out)
  1429. //
  1430. ULONG tracksToReturn;
  1431. ULONG tracksOnCd;
  1432. ULONG tracksInBuffer;
  1433. ULONG dataLength;
  1434. tracksOnCd = (cdaudioDataOut->LastTrack - cdaudioDataOut->FirstTrack) + 1;
  1435. dataLength = ((ULONG)FIELD_OFFSET(CDROM_TOC, TrackData[tracksOnCd])) - 2;
  1436. cdaudioDataOut->Length[0] = (UCHAR)(dataLength >> 8);
  1437. cdaudioDataOut->Length[1] = (UCHAR)(dataLength & 0xFF);
  1438. tracksInBuffer = currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength -
  1439. ((ULONG)FIELD_OFFSET(CDROM_TOC, TrackData[0]));
  1440. tracksInBuffer /= sizeof(TRACK_DATA);
  1441. // take the lesser of the two
  1442. tracksToReturn = (tracksInBuffer < tracksOnCd) ?
  1443. tracksInBuffer :
  1444. tracksOnCd;
  1445. for( i=0; i < tracksToReturn; i++ ) {
  1446. //
  1447. // Grab Information for each track
  1448. //
  1449. cdaudioDataOut->TrackData[i].Reserved = 0;
  1450. cdaudioDataOut->TrackData[i].Control =
  1451. ((Toc[(i*10)+32] & 0x0F) << 4) | (Toc[(i*10)+32] >> 4);
  1452. cdaudioDataOut->TrackData[i].TrackNumber =
  1453. (UCHAR)(i + cdaudioDataOut->FirstTrack);
  1454. cdaudioDataOut->TrackData[i].Reserved1 = 0;
  1455. cdaudioDataOut->TrackData[i].Address[0] = 0;
  1456. cdaudioDataOut->TrackData[i].Address[1] =
  1457. BCD_TO_DEC((Toc[(i*10)+39]));
  1458. cdaudioDataOut->TrackData[i].Address[2] =
  1459. BCD_TO_DEC((Toc[(i*10)+40]));
  1460. cdaudioDataOut->TrackData[i].Address[3] =
  1461. BCD_TO_DEC((Toc[(i*10)+41]));
  1462. CdDump(( 4,
  1463. "CdAudioNecDeviceControl: Track %d %d:%d:%d\n",
  1464. cdaudioDataOut->TrackData[i].TrackNumber,
  1465. cdaudioDataOut->TrackData[i].Address[1],
  1466. cdaudioDataOut->TrackData[i].Address[2],
  1467. cdaudioDataOut->TrackData[i].Address[3]
  1468. ));
  1469. }
  1470. //
  1471. // Fake "lead out track" info
  1472. // Only if all tracks have been copied...
  1473. //
  1474. if ( tracksInBuffer > tracksOnCd ) {
  1475. cdaudioDataOut->TrackData[i].Reserved = 0;
  1476. cdaudioDataOut->TrackData[i].Control = 0x10;
  1477. cdaudioDataOut->TrackData[i].TrackNumber = 0xaa;
  1478. cdaudioDataOut->TrackData[i].Reserved1 = 0;
  1479. cdaudioDataOut->TrackData[i].Address[0] = 0;
  1480. cdaudioDataOut->TrackData[i].Address[1] = BCD_TO_DEC(Toc[29]);
  1481. cdaudioDataOut->TrackData[i].Address[2] = BCD_TO_DEC(Toc[30]);
  1482. cdaudioDataOut->TrackData[i].Address[3] = BCD_TO_DEC(Toc[31]);
  1483. CdDump(( 4,
  1484. "NECDeviceControl => Track %d %d:%d:%d\n",
  1485. cdaudioDataOut->TrackData[i].TrackNumber,
  1486. cdaudioDataOut->TrackData[i].Address[1],
  1487. cdaudioDataOut->TrackData[i].Address[2],
  1488. cdaudioDataOut->TrackData[i].Address[3]
  1489. ));
  1490. i++;
  1491. }
  1492. Irp->IoStatus.Information = ((ULONG)FIELD_OFFSET(CDROM_TOC, TrackData[i]));
  1493. }
  1494. //
  1495. // Free storage now that we've stored it elsewhere
  1496. //
  1497. ExFreePool( Toc );
  1498. break;
  1499. case IOCTL_CDROM_STOP_AUDIO:
  1500. deviceExtension->PlayActive = FALSE;
  1501. //
  1502. // Same as scsi-2 spec, so just send to default driver
  1503. //
  1504. return CdAudioSendToNextDriver( DeviceObject, Irp );
  1505. break;
  1506. case IOCTL_CDROM_PLAY_AUDIO_MSF:
  1507. {
  1508. PCDROM_PLAY_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
  1509. CdDump(( 3,
  1510. "NECDeviceControl => IOCTL_CDROM_PLAY_AUDIO_MSF recv'd.\n"
  1511. ));
  1512. if (currentIrpStack->Parameters.DeviceIoControl.InputBufferLength <
  1513. sizeof(CDROM_PLAY_AUDIO_MSF)
  1514. ) {
  1515. status = STATUS_INFO_LENGTH_MISMATCH;
  1516. Irp->IoStatus.Information = 0;
  1517. break;
  1518. }
  1519. //
  1520. // First, seek to Starting MSF and enter play mode.
  1521. //
  1522. srb.CdbLength = 10;
  1523. srb.TimeOutValue = AUDIO_TIMEOUT;
  1524. cdb->NEC_PLAY_AUDIO.OperationCode = NEC_AUDIO_TRACK_SEARCH_CODE;
  1525. cdb->NEC_PLAY_AUDIO.PlayMode = NEC_ENTER_PLAY_MODE;
  1526. cdb->NEC_PLAY_AUDIO.Minute = DEC_TO_BCD(inputBuffer->StartingM);
  1527. cdb->NEC_PLAY_AUDIO.Second = DEC_TO_BCD(inputBuffer->StartingS);
  1528. cdb->NEC_PLAY_AUDIO.Frame = DEC_TO_BCD(inputBuffer->StartingF);
  1529. cdb->NEC_PLAY_AUDIO.Control = NEC_TYPE_ATIME;
  1530. CdDump(( 3,
  1531. "NECDeviceControl => play start MSF is BCD(%x:%x:%x)\n",
  1532. cdb->NEC_PLAY_AUDIO.Minute,
  1533. cdb->NEC_PLAY_AUDIO.Second,
  1534. cdb->NEC_PLAY_AUDIO.Frame
  1535. ));
  1536. status = SendSrbSynchronous(deviceExtension,
  1537. &srb,
  1538. NULL,
  1539. 0
  1540. );
  1541. if (NT_SUCCESS(status)) {
  1542. //
  1543. // Indicate the play actition is active.
  1544. //
  1545. deviceExtension->PlayActive = TRUE;
  1546. //
  1547. // Now, set the termination point for the play operation
  1548. //
  1549. RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
  1550. cdb->NEC_PLAY_AUDIO.OperationCode = NEC_PLAY_AUDIO_CODE;
  1551. cdb->NEC_PLAY_AUDIO.PlayMode = NEC_PLAY_STEREO;
  1552. cdb->NEC_PLAY_AUDIO.Minute = DEC_TO_BCD(inputBuffer->EndingM);
  1553. cdb->NEC_PLAY_AUDIO.Second = DEC_TO_BCD(inputBuffer->EndingS);
  1554. cdb->NEC_PLAY_AUDIO.Frame = DEC_TO_BCD(inputBuffer->EndingF);
  1555. cdb->NEC_PLAY_AUDIO.Control = NEC_TYPE_ATIME;
  1556. CdDump(( 3,
  1557. "NECDeviceControl => play end MSF is BCD(%x:%x:%x)\n",
  1558. cdb->NEC_PLAY_AUDIO.Minute,
  1559. cdb->NEC_PLAY_AUDIO.Second,
  1560. cdb->NEC_PLAY_AUDIO.Frame
  1561. ));
  1562. status = SendSrbSynchronous(
  1563. deviceExtension,
  1564. &srb,
  1565. NULL,
  1566. 0
  1567. );
  1568. }
  1569. }
  1570. break;
  1571. case IOCTL_CDROM_SEEK_AUDIO_MSF:
  1572. {
  1573. PCDROM_SEEK_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
  1574. CdDump(( 3,
  1575. "NECDeviceControl => IOCTL_CDROM_SEEK_AUDIO_MSF recv'd.\n"
  1576. ));
  1577. //
  1578. // Must have allocated at least enough buffer space
  1579. // to store how many tracks are on the disc
  1580. //
  1581. if (currentIrpStack->Parameters.DeviceIoControl.InputBufferLength <
  1582. sizeof(CDROM_SEEK_AUDIO_MSF)
  1583. ) {
  1584. status = STATUS_INFO_LENGTH_MISMATCH;
  1585. Irp->IoStatus.Information = 0;
  1586. break;
  1587. }
  1588. //
  1589. // seek to MSF and enter pause (still) mode.
  1590. //
  1591. srb.CdbLength = 10;
  1592. srb.TimeOutValue = AUDIO_TIMEOUT;
  1593. cdb->NEC_SEEK_AUDIO.OperationCode = NEC_AUDIO_TRACK_SEARCH_CODE;
  1594. cdb->NEC_SEEK_AUDIO.Minute = DEC_TO_BCD(inputBuffer->M);
  1595. cdb->NEC_SEEK_AUDIO.Second = DEC_TO_BCD(inputBuffer->S);
  1596. cdb->NEC_SEEK_AUDIO.Frame = DEC_TO_BCD(inputBuffer->F);
  1597. cdb->NEC_SEEK_AUDIO.Control = NEC_TYPE_ATIME;
  1598. CdDump(( 4,
  1599. "NECDeviceControl => seek MSF is %d:%d:%d\n",
  1600. cdb->NEC_SEEK_AUDIO.Minute,
  1601. cdb->NEC_SEEK_AUDIO.Second,
  1602. cdb->NEC_SEEK_AUDIO.Frame
  1603. ));
  1604. status = SendSrbSynchronous(
  1605. deviceExtension,
  1606. &srb,
  1607. NULL,
  1608. 0
  1609. );
  1610. }
  1611. break;
  1612. case IOCTL_CDROM_PAUSE_AUDIO:
  1613. CdDump(( 3,
  1614. "NECDeviceControl => IOCTL_CDROM_PAUSE_AUDIO recv'd.\n"
  1615. ));
  1616. deviceExtension->PlayActive = FALSE;
  1617. //
  1618. // Enter pause (still ) mode
  1619. //
  1620. srb.CdbLength = 10;
  1621. srb.TimeOutValue = AUDIO_TIMEOUT;
  1622. cdb->NEC_PAUSE_AUDIO.OperationCode = NEC_STILL_CODE;
  1623. status = SendSrbSynchronous(
  1624. deviceExtension,
  1625. &srb,
  1626. NULL,
  1627. 0
  1628. );
  1629. break;
  1630. case IOCTL_CDROM_RESUME_AUDIO:
  1631. CdDump(( 3,
  1632. "NECDeviceControl => IOCTL_CDROM_RESUME_AUDIO recv'd.\n"
  1633. ));
  1634. //
  1635. // Resume play
  1636. //
  1637. srb.CdbLength = 10;
  1638. srb.TimeOutValue = AUDIO_TIMEOUT;
  1639. cdb->NEC_PLAY_AUDIO.OperationCode = NEC_PLAY_AUDIO_CODE;
  1640. cdb->NEC_PLAY_AUDIO.PlayMode = NEC_PLAY_STEREO;
  1641. cdb->NEC_PLAY_AUDIO.Control = NEC_TYPE_NO_CHANGE;
  1642. status = SendSrbSynchronous(
  1643. deviceExtension,
  1644. &srb,
  1645. NULL,
  1646. 0
  1647. );
  1648. break;
  1649. case IOCTL_CDROM_READ_Q_CHANNEL:
  1650. {
  1651. PSUB_Q_CURRENT_POSITION userPtr =
  1652. Irp->AssociatedIrp.SystemBuffer;
  1653. PUCHAR SubQPtr =
  1654. ExAllocatePool( NonPagedPoolCacheAligned,
  1655. NEC_Q_CHANNEL_TRANSFER_SIZE
  1656. );
  1657. if (currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength <
  1658. sizeof(SUB_Q_CURRENT_POSITION)
  1659. ) {
  1660. status = STATUS_BUFFER_TOO_SMALL;
  1661. // we have transferred zero bytes
  1662. Irp->IoStatus.Information = 0;
  1663. if (SubQPtr) ExFreePool(SubQPtr);
  1664. break;
  1665. }
  1666. CdDump(( 5,
  1667. "NECDeviceControl => IOCTL_CDROM_READ_Q_CHANNEL recv'd.\n"
  1668. ));
  1669. if (SubQPtr==NULL) {
  1670. CdDump(( 1,
  1671. "NECDeviceControl !! READ_Q_CHANNEL, SubQPtr==NULL!\n"
  1672. ));
  1673. status = STATUS_INSUFFICIENT_RESOURCES;
  1674. Irp->IoStatus.Information = 0;
  1675. goto SetStatusAndReturn;
  1676. }
  1677. RtlZeroMemory( SubQPtr, NEC_Q_CHANNEL_TRANSFER_SIZE );
  1678. if ( ((PCDROM_SUB_Q_DATA_FORMAT)userPtr)->Format!=
  1679. IOCTL_CDROM_CURRENT_POSITION) {
  1680. CdDump((1,
  1681. "NECDeviceControl !! READ_Q_CHANNEL, illegal Format (%d)\n",
  1682. ((PCDROM_SUB_Q_DATA_FORMAT)userPtr)->Format
  1683. ));
  1684. ExFreePool( SubQPtr );
  1685. status = STATUS_UNSUCCESSFUL;
  1686. Irp->IoStatus.Information = 0;
  1687. goto SetStatusAndReturn;
  1688. }
  1689. NECSeek:
  1690. //
  1691. // Set up to read Q Channel
  1692. //
  1693. srb.CdbLength = 10;
  1694. srb.TimeOutValue = AUDIO_TIMEOUT;
  1695. cdb->NEC_READ_Q_CHANNEL.OperationCode = NEC_READ_SUB_Q_CHANNEL_CODE;
  1696. // Transfer Length
  1697. cdb->NEC_READ_Q_CHANNEL.TransferSize = NEC_Q_CHANNEL_TRANSFER_SIZE;
  1698. CdDump(( 4, "NECDeviceControl => cdb = %p srb = %p SubQPtr = %p\n",
  1699. cdb,
  1700. &srb,
  1701. SubQPtr
  1702. ));
  1703. status = SendSrbSynchronous(
  1704. deviceExtension,
  1705. &srb,
  1706. SubQPtr,
  1707. NEC_Q_CHANNEL_TRANSFER_SIZE
  1708. );
  1709. CdDump(( 4, "NECDeviceControl => READ_Q_CHANNEL, status is %lx\n",
  1710. status
  1711. ));
  1712. if ((NT_SUCCESS(status)) || (status==STATUS_DATA_OVERRUN)) {
  1713. userPtr->Header.Reserved = 0;
  1714. if (SubQPtr[0]==0x00)
  1715. userPtr->Header.AudioStatus = AUDIO_STATUS_IN_PROGRESS;
  1716. else if (SubQPtr[0]==0x01) {
  1717. userPtr->Header.AudioStatus = AUDIO_STATUS_PAUSED;
  1718. deviceExtension->PlayActive = FALSE;
  1719. } else if (SubQPtr[0]==0x02) {
  1720. userPtr->Header.AudioStatus = AUDIO_STATUS_PAUSED;
  1721. deviceExtension->PlayActive = FALSE;
  1722. } else if (SubQPtr[0]==0x03) {
  1723. userPtr->Header.AudioStatus = AUDIO_STATUS_PLAY_COMPLETE;
  1724. deviceExtension->PlayActive = FALSE;
  1725. } else {
  1726. deviceExtension->PlayActive = FALSE;
  1727. }
  1728. userPtr->Header.DataLength[0] = 0;
  1729. userPtr->Header.DataLength[0] = 12;
  1730. userPtr->FormatCode = 0x01;
  1731. userPtr->Control = SubQPtr[1] & 0x0F;
  1732. userPtr->ADR = 0;
  1733. userPtr->TrackNumber = BCD_TO_DEC(SubQPtr[2]);
  1734. userPtr->IndexNumber = BCD_TO_DEC(SubQPtr[3]);
  1735. userPtr->AbsoluteAddress[0] = 0;
  1736. userPtr->AbsoluteAddress[1] = BCD_TO_DEC((SubQPtr[7]));
  1737. userPtr->AbsoluteAddress[2] = BCD_TO_DEC((SubQPtr[8]));
  1738. userPtr->AbsoluteAddress[3] = BCD_TO_DEC((SubQPtr[9]));
  1739. userPtr->TrackRelativeAddress[0] = 0;
  1740. userPtr->TrackRelativeAddress[1] = BCD_TO_DEC((SubQPtr[4]));
  1741. userPtr->TrackRelativeAddress[2] = BCD_TO_DEC((SubQPtr[5]));
  1742. userPtr->TrackRelativeAddress[3] = BCD_TO_DEC((SubQPtr[6]));
  1743. Irp->IoStatus.Information = sizeof(SUB_Q_CURRENT_POSITION);
  1744. CdDump(( 5,
  1745. "NECDeviceControl => <SubQPtr> Status = 0x%lx, [%x %x:%x] (%x:%x:%x)\n",
  1746. SubQPtr[0],
  1747. SubQPtr[2],
  1748. SubQPtr[4],
  1749. SubQPtr[5],
  1750. SubQPtr[7],
  1751. SubQPtr[8],
  1752. SubQPtr[9]
  1753. ));
  1754. CdDump(( 5,
  1755. "NECDeviceControl => <userPtr> Status = 0x%lx, [%d %d:%d] (%d:%d:%d)\n",
  1756. userPtr->Header.AudioStatus,
  1757. userPtr->TrackNumber,
  1758. userPtr->TrackRelativeAddress[1],
  1759. userPtr->TrackRelativeAddress[2],
  1760. userPtr->AbsoluteAddress[1],
  1761. userPtr->AbsoluteAddress[2],
  1762. userPtr->AbsoluteAddress[3]
  1763. ));
  1764. //
  1765. // Sometimes the NEC will return a bogus value for track number.
  1766. // if this occurs just retry.
  1767. //
  1768. if (userPtr->TrackNumber > MAXIMUM_NUMBER_TRACKS) {
  1769. //
  1770. // Delay for .5 seconds.
  1771. //
  1772. delay.QuadPart = - 10 * (LONGLONG)1000 * 100 * 5;
  1773. //
  1774. // Stall for a while to let the controller spinup.
  1775. //
  1776. KeDelayExecutionThread(KernelMode,
  1777. FALSE,
  1778. &delay);
  1779. if (retryCount++ < MAXIMUM_RETRIES) {
  1780. goto NECSeek;
  1781. } else {
  1782. Irp->IoStatus.Information = 0;
  1783. status = STATUS_DEVICE_PROTOCOL_ERROR;
  1784. }
  1785. } else {
  1786. status = STATUS_SUCCESS;
  1787. }
  1788. } else {
  1789. RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
  1790. Irp->IoStatus.Information = 0;
  1791. CdDump((1,
  1792. "NECDeviceControl => READ_Q_CHANNEL failed %lx)\n",
  1793. status
  1794. ));
  1795. }
  1796. ExFreePool( SubQPtr );
  1797. }
  1798. break;
  1799. case IOCTL_CDROM_EJECT_MEDIA:
  1800. CdDump(( 3,
  1801. "NECDeviceControl => IOCTL_CDROM_EJECT_MEDIA recv'd.\n"
  1802. ));
  1803. deviceExtension->PlayActive = FALSE;
  1804. //
  1805. // Set up to read Q Channel
  1806. //
  1807. srb.CdbLength = 10;
  1808. srb.TimeOutValue = AUDIO_TIMEOUT;
  1809. cdb->NEC_EJECT.OperationCode = NEC_EJECT_CODE;
  1810. status = SendSrbSynchronous(
  1811. deviceExtension,
  1812. &srb,
  1813. NULL,
  1814. 0
  1815. );
  1816. Irp->IoStatus.Information = 0;
  1817. CdDump(( 3,
  1818. "NECDeviceControl => invalidating cached TOC!\n"
  1819. ));
  1820. break;
  1821. case IOCTL_CDROM_GET_CONTROL:
  1822. case IOCTL_CDROM_GET_VOLUME:
  1823. case IOCTL_CDROM_SET_VOLUME:
  1824. CdDump(( 3, "NECDeviceControl => Not Supported yet.\n" ));
  1825. Irp->IoStatus.Information = 0;
  1826. status = STATUS_INVALID_DEVICE_REQUEST;
  1827. break;
  1828. case IOCTL_CDROM_CHECK_VERIFY:
  1829. //
  1830. // Update the play active flag.
  1831. //
  1832. CdAudioIsPlayActive(DeviceObject);
  1833. //
  1834. // Fall through and pass the request to the next driver.
  1835. //
  1836. default:
  1837. CdDump(( 10,
  1838. "NECDeviceControl => Unsupported device IOCTL (%x)\n",
  1839. currentIrpStack->Parameters.DeviceIoControl.IoControlCode
  1840. ));
  1841. return CdAudioSendToNextDriver( DeviceObject, Irp );
  1842. break;
  1843. } // end switch( IOCTL )
  1844. SetStatusAndReturn:
  1845. //
  1846. // set status code and return
  1847. //
  1848. if (status == STATUS_VERIFY_REQUIRED) {
  1849. //
  1850. // If the status is verified required and the this request
  1851. // should bypass verify required then retry the request.
  1852. //
  1853. if (currentIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME) {
  1854. status = STATUS_IO_DEVICE_ERROR;
  1855. goto NECRestart;
  1856. }
  1857. IoSetHardErrorOrVerifyDevice( Irp,
  1858. deviceExtension->TargetDeviceObject
  1859. );
  1860. Irp->IoStatus.Information = 0;
  1861. }
  1862. Irp->IoStatus.Status = status;
  1863. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1864. return status;
  1865. }
  1866. NTSTATUS
  1867. CdAudioPioneerDeviceControl(
  1868. PDEVICE_OBJECT DeviceObject,
  1869. PIRP Irp
  1870. )
  1871. /*++
  1872. Routine Description:
  1873. This routine is called by CdAudioDeviceControl to handle
  1874. audio IOCTLs sent to PIONEER DRM-6xx cdrom drives.
  1875. Arguments:
  1876. DeviceObject
  1877. Irp
  1878. Return Value:
  1879. NTSTATUS
  1880. --*/
  1881. {
  1882. PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
  1883. PCD_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  1884. PCDROM_TOC cdaudioDataOut = Irp->AssociatedIrp.SystemBuffer;
  1885. SCSI_PASS_THROUGH srb;
  1886. PPNR_CDB cdb = (PPNR_CDB)srb.Cdb;
  1887. PCDB scsiCdb = (PCDB) srb.Cdb;
  1888. NTSTATUS status;
  1889. ULONG i,retry;
  1890. PUCHAR Toc;
  1891. PioneerRestart:
  1892. //
  1893. // Clear out cdb
  1894. //
  1895. RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
  1896. //
  1897. // What IOCTL do we need to execute?
  1898. //
  1899. switch (currentIrpStack->Parameters.DeviceIoControl.IoControlCode) {
  1900. case IOCTL_CDROM_READ_TOC: {
  1901. CdDump(( 3,
  1902. "PioneerDeviceControl => IOCTL_CDROM_READ_TOC recv'd.\n"
  1903. ));
  1904. //
  1905. // Must have allocated at least enough buffer space
  1906. // to store how many tracks are on the disc
  1907. //
  1908. if (currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength <
  1909. ((ULONG)FIELD_OFFSET(CDROM_TOC, TrackData[0]))
  1910. ) {
  1911. status = STATUS_BUFFER_TOO_SMALL;
  1912. // we have transferred zero bytes
  1913. Irp->IoStatus.Information = 0;
  1914. break;
  1915. }
  1916. //
  1917. // If the cd is playing music then reject this request.
  1918. //
  1919. if (CdAudioIsPlayActive(DeviceObject)) {
  1920. status = STATUS_DEVICE_BUSY;
  1921. Irp->IoStatus.Information = 0;
  1922. break;
  1923. }
  1924. //
  1925. // Allocate storage to hold TOC from disc
  1926. //
  1927. Toc = (PUCHAR)ExAllocatePool( NonPagedPoolCacheAligned,
  1928. CDROM_TOC_SIZE
  1929. );
  1930. if (Toc==NULL) {
  1931. status = STATUS_INSUFFICIENT_RESOURCES;
  1932. Irp->IoStatus.Information = 0;
  1933. goto SetStatusAndReturn;
  1934. }
  1935. RtlZeroMemory( Toc, CDROM_TOC_SIZE );
  1936. //
  1937. // mount this disc (via START/STOP unit), which is
  1938. // necessary since we don't know which is the
  1939. // currently loaded disc.
  1940. //
  1941. if (deviceExtension->Active == CDAUDIO_PIONEER) {
  1942. cdb->PNR_START_STOP.Immediate = 1;
  1943. } else {
  1944. cdb->PNR_START_STOP.Immediate = 0;
  1945. }
  1946. cdb->PNR_START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
  1947. cdb->PNR_START_STOP.Start = 1;
  1948. srb.CdbLength = 6;
  1949. srb.TimeOutValue = AUDIO_TIMEOUT;
  1950. status = SendSrbSynchronous( deviceExtension,
  1951. &srb,
  1952. NULL,
  1953. 0
  1954. );
  1955. if (!NT_SUCCESS(status)) {
  1956. CdDump(( 1,
  1957. "PioneerDeviceControl => Start Unit failed (%lx)\n",
  1958. status));
  1959. ExFreePool( Toc );
  1960. Irp->IoStatus.Information = 0;
  1961. goto SetStatusAndReturn;
  1962. }
  1963. //
  1964. // Get first and last tracks
  1965. //
  1966. RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
  1967. srb.CdbLength = 10;
  1968. cdb->PNR_READ_TOC.OperationCode = PIONEER_READ_TOC_CODE;
  1969. cdb->PNR_READ_TOC.AssignedLength[1] = PIONEER_TRANSFER_SIZE;
  1970. cdb->PNR_READ_TOC.Type = PIONEER_READ_FIRST_AND_LAST;
  1971. srb.TimeOutValue = AUDIO_TIMEOUT;
  1972. status = SendSrbSynchronous( deviceExtension,
  1973. &srb,
  1974. Toc,
  1975. PIONEER_TRANSFER_SIZE
  1976. );
  1977. if (!NT_SUCCESS(status)) {
  1978. CdDump(( 1,
  1979. "PioneerDeviceControl => ReadTOC, First/Last Tracks failed (%lx)\n",
  1980. status ));
  1981. ExFreePool( Toc );
  1982. Irp->IoStatus.Information = 0;
  1983. goto SetStatusAndReturn;
  1984. }
  1985. cdaudioDataOut->FirstTrack = BCD_TO_DEC(Toc[0]);
  1986. cdaudioDataOut->LastTrack = BCD_TO_DEC(Toc[1]);
  1987. //
  1988. // Return only N number of tracks, where N is the number of
  1989. // full tracks of info we can stuff into the user buffer
  1990. // if tracks from 1 to 2, that means there are two tracks,
  1991. // so let i go from 0 to 1 (two tracks of info)
  1992. //
  1993. {
  1994. //
  1995. // tracksToReturn == Number of real track info to return
  1996. // tracksInBuffer == How many fit into the user-supplied buffer
  1997. // tracksOnCd == Number of tracks on the CD (not including lead-out)
  1998. //
  1999. ULONG tracksToReturn;
  2000. ULONG tracksOnCd;
  2001. ULONG tracksInBuffer;
  2002. ULONG dataLength;
  2003. tracksOnCd = (cdaudioDataOut->LastTrack - cdaudioDataOut->FirstTrack) + 1;
  2004. //
  2005. // set the number of tracks correctly
  2006. //
  2007. dataLength = ((ULONG)FIELD_OFFSET(CDROM_TOC, TrackData[tracksOnCd])) - 2;
  2008. cdaudioDataOut->Length[0] = (UCHAR)(dataLength >> 8);
  2009. cdaudioDataOut->Length[1] = (UCHAR)(dataLength & 0xFF);
  2010. tracksInBuffer = currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength -
  2011. ((ULONG)FIELD_OFFSET(CDROM_TOC, TrackData[0]));
  2012. tracksInBuffer /= sizeof(TRACK_DATA);
  2013. // take the lesser of the two
  2014. tracksToReturn = (tracksInBuffer < tracksOnCd) ?
  2015. tracksInBuffer :
  2016. tracksOnCd;
  2017. for( i=0; i < tracksToReturn; i++ ) {
  2018. //
  2019. // Grab Information for each track
  2020. //
  2021. RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
  2022. cdb->PNR_READ_TOC.OperationCode = PIONEER_READ_TOC_CODE;
  2023. // track
  2024. cdb->PNR_READ_TOC.TrackNumber =
  2025. (UCHAR)(DEC_TO_BCD((i+cdaudioDataOut->FirstTrack)));
  2026. cdb->PNR_READ_TOC.AssignedLength[1] = PIONEER_TRANSFER_SIZE;
  2027. cdb->PNR_READ_TOC.Type = PIONEER_READ_TRACK_INFO;
  2028. srb.TimeOutValue = AUDIO_TIMEOUT;
  2029. status = SendSrbSynchronous( deviceExtension,
  2030. &srb,
  2031. Toc,
  2032. PIONEER_TRANSFER_SIZE
  2033. );
  2034. if (!NT_SUCCESS(status)) {
  2035. CdDump(( 1,
  2036. "PioneerDeviceControl => ReadTOC, Track #%d, failed (%lx)\n",
  2037. i+cdaudioDataOut->FirstTrack,
  2038. status ));
  2039. ExFreePool( Toc );
  2040. Irp->IoStatus.Information = 0;
  2041. goto SetStatusAndReturn;
  2042. }
  2043. cdaudioDataOut->TrackData[i].Reserved = 0;
  2044. cdaudioDataOut->TrackData[i].Control = Toc[0];
  2045. cdaudioDataOut->TrackData[i].TrackNumber =
  2046. (UCHAR)((i + cdaudioDataOut->FirstTrack));
  2047. cdaudioDataOut->TrackData[i].Reserved1 = 0;
  2048. cdaudioDataOut->TrackData[i].Address[0]=0;
  2049. cdaudioDataOut->TrackData[i].Address[1]=BCD_TO_DEC(Toc[1]);
  2050. cdaudioDataOut->TrackData[i].Address[2]=BCD_TO_DEC(Toc[2]);
  2051. cdaudioDataOut->TrackData[i].Address[3]=BCD_TO_DEC(Toc[3]);
  2052. CdDump(( 4,
  2053. "CdAudioPioneerDeviceControl: Track %d %d:%d:%d\n",
  2054. cdaudioDataOut->TrackData[i].TrackNumber,
  2055. cdaudioDataOut->TrackData[i].Address[1],
  2056. cdaudioDataOut->TrackData[i].Address[2],
  2057. cdaudioDataOut->TrackData[i].Address[3]
  2058. ));
  2059. }
  2060. //
  2061. // Fake "lead out track" info
  2062. // Only if all tracks have been copied...
  2063. //
  2064. if ( tracksInBuffer > tracksOnCd ) {
  2065. RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
  2066. cdb->PNR_READ_TOC.OperationCode = PIONEER_READ_TOC_CODE;
  2067. cdb->PNR_READ_TOC.AssignedLength[1] = PIONEER_TRANSFER_SIZE;
  2068. cdb->PNR_READ_TOC.Type = PIONEER_READ_LEAD_OUT_INFO;
  2069. srb.TimeOutValue = AUDIO_TIMEOUT;
  2070. status = SendSrbSynchronous( deviceExtension,
  2071. &srb,
  2072. Toc,
  2073. PIONEER_TRANSFER_SIZE
  2074. );
  2075. if (!NT_SUCCESS(status)) {
  2076. CdDump(( 1,
  2077. "PioneerDeviceControl => ReadTOC, read LeadOutTrack failed (%lx)\n",
  2078. status ));
  2079. ExFreePool( Toc );
  2080. Irp->IoStatus.Information = 0;
  2081. goto SetStatusAndReturn;
  2082. }
  2083. cdaudioDataOut->TrackData[i].Reserved = 0;
  2084. cdaudioDataOut->TrackData[i].Control = 0x10;
  2085. cdaudioDataOut->TrackData[i].TrackNumber = 0xaa;
  2086. cdaudioDataOut->TrackData[i].Reserved1 = 0;
  2087. cdaudioDataOut->TrackData[i].Address[0] = 0;
  2088. cdaudioDataOut->TrackData[i].Address[1] = BCD_TO_DEC(Toc[0]);
  2089. cdaudioDataOut->TrackData[i].Address[2] = BCD_TO_DEC(Toc[1]);
  2090. cdaudioDataOut->TrackData[i].Address[3] = BCD_TO_DEC(Toc[2]);
  2091. CdDump(( 4,
  2092. "CdAudioPioneerDeviceControl: Track %d %d:%d:%d\n",
  2093. cdaudioDataOut->TrackData[i].TrackNumber,
  2094. cdaudioDataOut->TrackData[i].Address[1],
  2095. cdaudioDataOut->TrackData[i].Address[2],
  2096. cdaudioDataOut->TrackData[i].Address[3]
  2097. ));
  2098. i++;
  2099. }
  2100. //
  2101. // Set size of information transfered to
  2102. // max size possible for CDROM Table of Contents
  2103. //
  2104. Irp->IoStatus.Information = ((ULONG)FIELD_OFFSET(CDROM_TOC, TrackData[i]));
  2105. }
  2106. ExFreePool( Toc );
  2107. }
  2108. break;
  2109. case IOCTL_CDROM_STOP_AUDIO: {
  2110. CdDump((3,
  2111. "PioneerDeviceControl => IOCTL_CDROM_STOP_AUDIO recv'd.\n"
  2112. ));
  2113. deviceExtension->PlayActive = FALSE;
  2114. //
  2115. // Same as scsi-2 spec, so just send to default driver
  2116. //
  2117. return CdAudioSendToNextDriver( DeviceObject, Irp );
  2118. }
  2119. break;
  2120. case IOCTL_CDROM_PLAY_AUDIO_MSF: {
  2121. PCDROM_PLAY_AUDIO_MSF inputBuffer =
  2122. Irp->AssociatedIrp.SystemBuffer;
  2123. CdDump(( 3,
  2124. "PioneerDeviceControl => IOCTL_CDROM_PLAY_AUDIO_MSF recv'd.\n"
  2125. ));
  2126. Irp->IoStatus.Information = 0;
  2127. if (currentIrpStack->Parameters.DeviceIoControl.InputBufferLength <
  2128. sizeof(CDROM_PLAY_AUDIO_MSF)
  2129. ) {
  2130. status = STATUS_INFO_LENGTH_MISMATCH;
  2131. break;
  2132. }
  2133. //
  2134. // First, set play END point for the play operation
  2135. //
  2136. retry = 5;
  2137. do {
  2138. srb.CdbLength = 10;
  2139. srb.TimeOutValue = AUDIO_TIMEOUT;
  2140. cdb->PNR_SEEK_AUDIO.OperationCode =
  2141. PIONEER_AUDIO_TRACK_SEARCH_CODE;
  2142. cdb->PNR_SEEK_AUDIO.Minute =
  2143. DEC_TO_BCD(inputBuffer->StartingM);
  2144. cdb->PNR_SEEK_AUDIO.Second =
  2145. DEC_TO_BCD(inputBuffer->StartingS);
  2146. cdb->PNR_SEEK_AUDIO.Frame =
  2147. DEC_TO_BCD(inputBuffer->StartingF);
  2148. cdb->PNR_SEEK_AUDIO.Type = PIONEER_TYPE_ATIME;
  2149. status = SendSrbSynchronous( deviceExtension,
  2150. &srb,
  2151. NULL,
  2152. 0
  2153. );
  2154. } while ( !NT_SUCCESS(status) && ((retry--)>0) );
  2155. if (NT_SUCCESS(status)) {
  2156. //
  2157. // Now, set play start position and start playing.
  2158. //
  2159. RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
  2160. retry = 5;
  2161. do {
  2162. srb.CdbLength = 10;
  2163. srb.TimeOutValue = AUDIO_TIMEOUT;
  2164. cdb->PNR_PLAY_AUDIO.OperationCode = PIONEER_PLAY_AUDIO_CODE;
  2165. cdb->PNR_PLAY_AUDIO.StopAddr = 1;
  2166. cdb->PNR_PLAY_AUDIO.Minute =
  2167. DEC_TO_BCD(inputBuffer->EndingM);
  2168. cdb->PNR_PLAY_AUDIO.Second =
  2169. DEC_TO_BCD(inputBuffer->EndingS);
  2170. cdb->PNR_PLAY_AUDIO.Frame =
  2171. DEC_TO_BCD(inputBuffer->EndingF);
  2172. cdb->PNR_PLAY_AUDIO.Type =
  2173. PIONEER_TYPE_ATIME;
  2174. status = SendSrbSynchronous( deviceExtension,
  2175. &srb,
  2176. NULL,
  2177. 0
  2178. );
  2179. } while ( !NT_SUCCESS(status) && ((retry--)>0) );
  2180. if (NT_SUCCESS(status)) {
  2181. //
  2182. // Indicate the play actition is active.
  2183. //
  2184. deviceExtension->PlayActive = TRUE;
  2185. }
  2186. #if DBG
  2187. if (!NT_SUCCESS(status)) {
  2188. CdDump(( 1,
  2189. "PioneerDeviceControl => PLAY_AUDIO_MSF(stop) failed %lx\n",
  2190. status
  2191. ));
  2192. CdDump(( 3,
  2193. "PioneerDeviceControl => cdb = %p, srb = %p\n",
  2194. cdb, &srb
  2195. ));
  2196. if (CdAudioDebug>2)
  2197. DbgBreakPoint();
  2198. }
  2199. #endif
  2200. }
  2201. #if DBG
  2202. else {
  2203. CdDump(( 1,
  2204. "PioneerDeviceControl => PLAY_AUDIO_MSF(start) failed %lx\n",
  2205. status
  2206. ));
  2207. CdDump(( 3,
  2208. "PioneerDeviceControl => cdb = %p, srb = %p\n",
  2209. cdb, &srb
  2210. ));
  2211. if (CdAudioDebug>2)
  2212. DbgBreakPoint();
  2213. }
  2214. #endif
  2215. }
  2216. break;
  2217. case IOCTL_CDROM_SEEK_AUDIO_MSF: {
  2218. PCDROM_SEEK_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
  2219. CdDump(( 1,
  2220. "PioneerDeviceControl => IOCTL_CDROM_SEEK_AUDIO_MSF recv'd.\n"
  2221. ));
  2222. Irp->IoStatus.Information = 0;
  2223. if (currentIrpStack->Parameters.DeviceIoControl.InputBufferLength <
  2224. sizeof(CDROM_SEEK_AUDIO_MSF)
  2225. ) {
  2226. status = STATUS_INFO_LENGTH_MISMATCH;
  2227. break;
  2228. }
  2229. retry = 5;
  2230. do {
  2231. //
  2232. // seek to MSF and enter pause (still) mode.
  2233. //
  2234. srb.CdbLength = 10;
  2235. srb.TimeOutValue = AUDIO_TIMEOUT;
  2236. cdb->PNR_SEEK_AUDIO.OperationCode = PIONEER_AUDIO_TRACK_SEARCH_CODE;
  2237. cdb->PNR_SEEK_AUDIO.Minute = DEC_TO_BCD(inputBuffer->M);
  2238. cdb->PNR_SEEK_AUDIO.Second = DEC_TO_BCD(inputBuffer->S);
  2239. cdb->PNR_SEEK_AUDIO.Frame = DEC_TO_BCD(inputBuffer->F);
  2240. cdb->PNR_SEEK_AUDIO.Type = PIONEER_TYPE_ATIME;
  2241. CdDump(( 3,
  2242. "PioneerDeviceControl => Seek to MSF %d:%d:%d, BCD(%x:%x:%x)\n",
  2243. inputBuffer->M,
  2244. inputBuffer->S,
  2245. inputBuffer->F,
  2246. cdb->PNR_SEEK_AUDIO.Minute,
  2247. cdb->PNR_SEEK_AUDIO.Second,
  2248. cdb->PNR_SEEK_AUDIO.Frame
  2249. ));
  2250. CdDump(( 3,
  2251. "PioneerDeviceControl => Seek to MSF, cdb is %p, srb is %p\n",
  2252. cdb,
  2253. &srb
  2254. ));
  2255. #if DBG
  2256. if (CdAudioDebug>2) {
  2257. DbgBreakPoint();
  2258. }
  2259. #endif
  2260. status = SendSrbSynchronous( deviceExtension,
  2261. &srb,
  2262. NULL,
  2263. 0
  2264. );
  2265. } while ( !NT_SUCCESS(status) && ((retry--)>0) );
  2266. #if DBG
  2267. if (!NT_SUCCESS(status)) {
  2268. CdDump((1,
  2269. "PioneerDeviceControl => Seek to MSF failed %lx\n",
  2270. status
  2271. ));
  2272. if (CdAudioDebug>5) {
  2273. DbgBreakPoint();
  2274. }
  2275. }
  2276. #endif
  2277. }
  2278. break;
  2279. case IOCTL_CDROM_PAUSE_AUDIO: {
  2280. CdDump(( 3,
  2281. "PioneerDeviceControl => IOCTL_CDROM_PAUSE_AUDIO recv'd.\n"
  2282. ));
  2283. Irp->IoStatus.Information = 0;
  2284. deviceExtension->PlayActive = FALSE;
  2285. //
  2286. // Enter pause (still ) mode
  2287. //
  2288. srb.CdbLength = 10;
  2289. srb.TimeOutValue = AUDIO_TIMEOUT;
  2290. cdb->PNR_PAUSE_AUDIO.OperationCode = PIONEER_PAUSE_CODE;
  2291. cdb->PNR_PAUSE_AUDIO.Pause = 1;
  2292. status = SendSrbSynchronous( deviceExtension,
  2293. &srb,
  2294. NULL,
  2295. 0
  2296. );
  2297. }
  2298. break;
  2299. case IOCTL_CDROM_RESUME_AUDIO: {
  2300. CdDump(( 3,
  2301. "PioneerDeviceControl => IOCTL_CDROM_RESUME_AUDIO recv'd.\n"
  2302. ));
  2303. Irp->IoStatus.Information = 0;
  2304. //
  2305. // Resume Play
  2306. //
  2307. srb.CdbLength = 10;
  2308. srb.TimeOutValue = AUDIO_TIMEOUT;
  2309. cdb->PNR_PAUSE_AUDIO.OperationCode = PIONEER_PAUSE_CODE;
  2310. status = SendSrbSynchronous( deviceExtension,
  2311. &srb,
  2312. NULL,
  2313. 0
  2314. );
  2315. }
  2316. break;
  2317. case IOCTL_CDROM_READ_Q_CHANNEL: {
  2318. PSUB_Q_CURRENT_POSITION userPtr =
  2319. Irp->AssociatedIrp.SystemBuffer;
  2320. PUCHAR SubQPtr =
  2321. ExAllocatePool( NonPagedPoolCacheAligned,
  2322. PIONEER_Q_CHANNEL_TRANSFER_SIZE
  2323. );
  2324. CdDump(( 5,
  2325. "PioneerDeviceControl => IOCTL_CDROM_READ_Q_CHANNEL recv'd.\n"
  2326. ));
  2327. if (currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength <
  2328. sizeof(SUB_Q_CURRENT_POSITION)
  2329. ) {
  2330. status = STATUS_BUFFER_TOO_SMALL;
  2331. // we have transferred zero bytes
  2332. Irp->IoStatus.Information = 0;
  2333. if (SubQPtr) ExFreePool(SubQPtr);
  2334. break;
  2335. }
  2336. if (SubQPtr==NULL) {
  2337. CdDump(( 1,
  2338. "PioneerDeviceControl => READ_Q_CHANNEL, SubQPtr==NULL!\n"
  2339. ));
  2340. RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
  2341. status = STATUS_INSUFFICIENT_RESOURCES;
  2342. Irp->IoStatus.Information = 0;
  2343. goto SetStatusAndReturn;
  2344. }
  2345. if ( ((PCDROM_SUB_Q_DATA_FORMAT)userPtr)->Format!=
  2346. IOCTL_CDROM_CURRENT_POSITION) {
  2347. CdDump(( 1,
  2348. "PioneerDeviceControl => READ_Q_CHANNEL, Illegal Format (%d)!\n",
  2349. ((PCDROM_SUB_Q_DATA_FORMAT)userPtr)->Format
  2350. ));
  2351. ExFreePool( SubQPtr );
  2352. RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
  2353. Irp->IoStatus.Information = 0;
  2354. status = STATUS_INVALID_DEVICE_REQUEST;
  2355. goto SetStatusAndReturn;
  2356. }
  2357. //
  2358. // Read audio play status
  2359. //
  2360. retry = 5;
  2361. do {
  2362. srb.CdbLength = 10;
  2363. srb.TimeOutValue = AUDIO_TIMEOUT;
  2364. cdb->PNR_AUDIO_STATUS.OperationCode =
  2365. PIONEER_AUDIO_STATUS_CODE;
  2366. cdb->PNR_AUDIO_STATUS.AssignedLength =
  2367. PIONEER_AUDIO_STATUS_TRANSFER_SIZE; // Transfer Length
  2368. status = SendSrbSynchronous( deviceExtension,
  2369. &srb,
  2370. SubQPtr,
  2371. 6
  2372. );
  2373. } while ( !NT_SUCCESS(status) &&
  2374. ((retry--)>0) &&
  2375. status != STATUS_DEVICE_NOT_READY
  2376. );
  2377. if (NT_SUCCESS(status)) {
  2378. userPtr->Header.Reserved = 0;
  2379. if (SubQPtr[0]==0x00)
  2380. userPtr->Header.AudioStatus = AUDIO_STATUS_IN_PROGRESS;
  2381. else if (SubQPtr[0]==0x01) {
  2382. deviceExtension->PlayActive = FALSE;
  2383. userPtr->Header.AudioStatus = AUDIO_STATUS_PAUSED;
  2384. } else if (SubQPtr[0]==0x02) {
  2385. deviceExtension->PlayActive = FALSE;
  2386. userPtr->Header.AudioStatus = AUDIO_STATUS_PAUSED;
  2387. } else if (SubQPtr[0]==0x03) {
  2388. userPtr->Header.AudioStatus = AUDIO_STATUS_PLAY_COMPLETE;
  2389. deviceExtension->PlayActive = FALSE;
  2390. } else {
  2391. deviceExtension->PlayActive = FALSE;
  2392. }
  2393. } else {
  2394. CdDump(( 1,
  2395. "PioneerDeviceControl => read status code (Q) failed (%lx)\n",
  2396. status
  2397. ));
  2398. ExFreePool( SubQPtr );
  2399. Irp->IoStatus.Information = 0;
  2400. goto SetStatusAndReturn;
  2401. }
  2402. //
  2403. // Set up to read current position from Q Channel
  2404. //
  2405. RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
  2406. retry = 5;
  2407. do {
  2408. srb.CdbLength = 10;
  2409. srb.TimeOutValue = AUDIO_TIMEOUT;
  2410. cdb->PNR_READ_Q_CHANNEL.OperationCode =
  2411. PIONEER_READ_SUB_Q_CHANNEL_CODE;
  2412. cdb->PNR_READ_Q_CHANNEL.AssignedLength =
  2413. PIONEER_Q_CHANNEL_TRANSFER_SIZE; // Transfer Length
  2414. status = SendSrbSynchronous( deviceExtension,
  2415. &srb,
  2416. SubQPtr,
  2417. PIONEER_Q_CHANNEL_TRANSFER_SIZE
  2418. );
  2419. } while ( !NT_SUCCESS(status) && ((retry--)>0) );
  2420. if (NT_SUCCESS(status)) {
  2421. userPtr->Header.DataLength[0] = 0;
  2422. userPtr->Header.DataLength[0] = 12;
  2423. userPtr->FormatCode = 0x01;
  2424. userPtr->Control = SubQPtr[0] & 0x0F;
  2425. userPtr->ADR = 0;
  2426. userPtr->TrackNumber = BCD_TO_DEC(SubQPtr[1]);
  2427. userPtr->IndexNumber = BCD_TO_DEC(SubQPtr[2]);
  2428. userPtr->AbsoluteAddress[0] = 0;
  2429. userPtr->AbsoluteAddress[1] = BCD_TO_DEC((SubQPtr[6]));
  2430. userPtr->AbsoluteAddress[2] = BCD_TO_DEC((SubQPtr[7]));
  2431. userPtr->AbsoluteAddress[3] = BCD_TO_DEC((SubQPtr[8]));
  2432. userPtr->TrackRelativeAddress[0] = 0;
  2433. userPtr->TrackRelativeAddress[1] = BCD_TO_DEC((SubQPtr[3]));
  2434. userPtr->TrackRelativeAddress[2] = BCD_TO_DEC((SubQPtr[4]));
  2435. userPtr->TrackRelativeAddress[3] = BCD_TO_DEC((SubQPtr[5]));
  2436. Irp->IoStatus.Information = sizeof(SUB_Q_CURRENT_POSITION);
  2437. } else {
  2438. Irp->IoStatus.Information = 0;
  2439. CdDump(( 1,
  2440. "PioneerDeviceControl => read q channel failed (%lx)\n",
  2441. status
  2442. ));
  2443. }
  2444. ExFreePool( SubQPtr );
  2445. }
  2446. break;
  2447. case IOCTL_CDROM_EJECT_MEDIA: {
  2448. CdDump(( 3, "PioneerDeviceControl => "
  2449. "IOCTL_CDROM_EJECT_MEDIA recv'd. "));
  2450. Irp->IoStatus.Information = 0;
  2451. deviceExtension->PlayActive = FALSE;
  2452. //
  2453. // Build cdb to eject cartridge
  2454. //
  2455. if (deviceExtension->Active == CDAUDIO_PIONEER) {
  2456. srb.CdbLength = 10;
  2457. srb.TimeOutValue = AUDIO_TIMEOUT;
  2458. cdb->PNR_EJECT.OperationCode = PIONEER_EJECT_CODE;
  2459. cdb->PNR_EJECT.Immediate = 1;
  2460. } else {
  2461. srb.CdbLength = 6;
  2462. scsiCdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
  2463. scsiCdb->START_STOP.LoadEject = 1;
  2464. scsiCdb->START_STOP.Start = 0;
  2465. }
  2466. status = SendSrbSynchronous( deviceExtension,
  2467. &srb,
  2468. NULL,
  2469. 0
  2470. );
  2471. CdDump(( 1, "PioneerDeviceControl => "
  2472. "IOCTL_CDROM_EJECT_MEDIA returned %lx.\n",
  2473. status
  2474. ));
  2475. }
  2476. break;
  2477. case IOCTL_CDROM_GET_CONTROL:
  2478. case IOCTL_CDROM_GET_VOLUME:
  2479. case IOCTL_CDROM_SET_VOLUME:
  2480. CdDump(( 3, "PioneerDeviceControl => Not Supported yet.\n" ));
  2481. Irp->IoStatus.Information = 0;
  2482. status = STATUS_INVALID_DEVICE_REQUEST;
  2483. break;
  2484. case IOCTL_CDROM_CHECK_VERIFY:
  2485. //
  2486. // Update the play active flag.
  2487. //
  2488. CdAudioIsPlayActive(DeviceObject);
  2489. default:
  2490. CdDump((10,"PioneerDeviceControl => Unsupported device IOCTL\n"));
  2491. return CdAudioSendToNextDriver( DeviceObject, Irp );
  2492. break;
  2493. } // end switch( IOCTL )
  2494. SetStatusAndReturn:
  2495. //
  2496. // set status code and return
  2497. //
  2498. if (status == STATUS_VERIFY_REQUIRED) {
  2499. //
  2500. // If the status is verified required and the this request
  2501. // should bypass verify required then retry the request.
  2502. //
  2503. if (currentIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME) {
  2504. status = STATUS_IO_DEVICE_ERROR;
  2505. goto PioneerRestart;
  2506. }
  2507. IoSetHardErrorOrVerifyDevice( Irp,
  2508. deviceExtension->TargetDeviceObject
  2509. );
  2510. Irp->IoStatus.Information = 0;
  2511. }
  2512. Irp->IoStatus.Status = status;
  2513. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  2514. return status;
  2515. }
  2516. NTSTATUS
  2517. CdAudioDenonDeviceControl(
  2518. PDEVICE_OBJECT DeviceObject,
  2519. PIRP Irp
  2520. )
  2521. /*++
  2522. Routine Description:
  2523. This routine is called by CdAudioDeviceControl to handle
  2524. audio IOCTLs sent to DENON DRD-253 cdrom drive.
  2525. Arguments:
  2526. DeviceObject
  2527. Irp
  2528. Return Value:
  2529. NTSTATUS
  2530. --*/
  2531. {
  2532. PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
  2533. PCD_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  2534. PCDROM_TOC cdaudioDataOut = Irp->AssociatedIrp.SystemBuffer;
  2535. SCSI_PASS_THROUGH srb;
  2536. PCDB cdb = (PCDB)srb.Cdb;
  2537. NTSTATUS status;
  2538. ULONG i,bytesTransfered;
  2539. PUCHAR Toc;
  2540. DenonRestart:
  2541. //
  2542. // Clear out cdb
  2543. //
  2544. RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
  2545. //
  2546. // What IOCTL do we need to execute?
  2547. //
  2548. switch (currentIrpStack->Parameters.DeviceIoControl.IoControlCode) {
  2549. case IOCTL_CDROM_GET_LAST_SESSION:
  2550. //
  2551. // Multiple sessions are not supported.
  2552. //
  2553. status = STATUS_INVALID_DEVICE_REQUEST;
  2554. Irp->IoStatus.Information = 0;
  2555. break;
  2556. case IOCTL_CDROM_READ_TOC:
  2557. CdDump(( 3,
  2558. "DenonDeviceControl => IOCTL_CDROM_READ_TOC recv'd.\n"
  2559. ));
  2560. //
  2561. // Must have allocated at least enough buffer space
  2562. // to store how many tracks are on the disc
  2563. //
  2564. if (currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength <
  2565. ((ULONG)FIELD_OFFSET(CDROM_TOC, TrackData[0]))
  2566. ) {
  2567. status = STATUS_BUFFER_TOO_SMALL;
  2568. // we have transferred zero bytes
  2569. Irp->IoStatus.Information = 0;
  2570. break;
  2571. }
  2572. //
  2573. // If the cd is playing music then reject this request.
  2574. //
  2575. if (CdAudioIsPlayActive(DeviceObject)) {
  2576. status = STATUS_DEVICE_BUSY;
  2577. Irp->IoStatus.Information = 0;
  2578. break;
  2579. }
  2580. //
  2581. // Allocate storage to hold TOC from disc
  2582. //
  2583. Toc = (PUCHAR)ExAllocatePool( NonPagedPoolCacheAligned,
  2584. CDROM_TOC_SIZE
  2585. );
  2586. if (Toc==NULL) {
  2587. status = STATUS_INSUFFICIENT_RESOURCES;
  2588. Irp->IoStatus.Information = 0;
  2589. goto SetStatusAndReturn;
  2590. }
  2591. //
  2592. // Set up defaults
  2593. //
  2594. RtlZeroMemory( Toc, CDROM_TOC_SIZE );
  2595. //
  2596. // Fill in cdb for this operation
  2597. //
  2598. cdb->CDB6GENERIC.OperationCode = DENON_READ_TOC_CODE;
  2599. srb.TimeOutValue = AUDIO_TIMEOUT;
  2600. srb.CdbLength = 6;
  2601. status = SendSrbSynchronous( deviceExtension,
  2602. &srb,
  2603. Toc,
  2604. CDROM_TOC_SIZE
  2605. );
  2606. if (!NT_SUCCESS(status) && (status!=STATUS_DATA_OVERRUN)) {
  2607. CdDump(( 1,
  2608. "DenonDeviceControl => READ_TOC error (%lx)\n",
  2609. status ));
  2610. if (status != STATUS_DATA_OVERRUN) {
  2611. CdDump(( 1, "DenonDeviceControl => SRB ERROR (%lx)\n",
  2612. status ));
  2613. ExFreePool( Toc );
  2614. Irp->IoStatus.Information = 0;
  2615. goto SetStatusAndReturn;
  2616. }
  2617. }
  2618. //
  2619. // Set the status to success since data under runs are not an error.
  2620. //
  2621. status = STATUS_SUCCESS;
  2622. //
  2623. // Since the Denon manual didn't define the format of
  2624. // the buffer returned from this call, here it is:
  2625. //
  2626. // Byte Data (4 byte "packets")
  2627. //
  2628. // 00 a0 FT 00 00 (FT == BCD of first track number on disc)
  2629. // 04 a1 LT 00 00 (LT == BCD of last track number on disc)
  2630. // 08 a2 MM SS FF (MM SS FF == BCD of total disc time, in MSF)
  2631. //
  2632. // For each track on disc:
  2633. //
  2634. // 0C XX MM SS FF (MM SS FF == BCD MSF start position of track XX)
  2635. // 0C+4 XX+1 MM SS FF (MM SS FF == BCD MSF start position of track XX+1)
  2636. //
  2637. // etc., for each track
  2638. //
  2639. //
  2640. // Translate data into our format
  2641. //
  2642. bytesTransfered =
  2643. currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength >
  2644. srb.DataTransferLength ?
  2645. srb.DataTransferLength :
  2646. currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
  2647. cdaudioDataOut->FirstTrack = BCD_TO_DEC(Toc[1]);
  2648. cdaudioDataOut->LastTrack = BCD_TO_DEC(Toc[5]);
  2649. //
  2650. // Return only N number of tracks, where N is the number of
  2651. // full tracks of info we can stuff into the user buffer
  2652. // if tracks from 1 to 2, that means there are two tracks,
  2653. // so let i go from 0 to 1 (two tracks of info)
  2654. //
  2655. {
  2656. //
  2657. // tracksToReturn == Number of real track info to return
  2658. // tracksInBuffer == How many fit into the user-supplied buffer
  2659. // tracksOnCd == Number of tracks on the CD (not including lead-out)
  2660. //
  2661. ULONG tracksToReturn;
  2662. ULONG tracksOnCd;
  2663. ULONG tracksInBuffer;
  2664. ULONG dataLength;
  2665. tracksOnCd = (cdaudioDataOut->LastTrack - cdaudioDataOut->FirstTrack) + 1;
  2666. //
  2667. // set the length of the data per SCSI2 spec
  2668. //
  2669. dataLength = ((ULONG)FIELD_OFFSET(CDROM_TOC, TrackData[tracksOnCd])) - 2;
  2670. cdaudioDataOut->Length[0] = (UCHAR)(dataLength >> 8);
  2671. cdaudioDataOut->Length[1] = (UCHAR)(dataLength & 0xFF);
  2672. tracksInBuffer = currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength -
  2673. ((ULONG)FIELD_OFFSET(CDROM_TOC, TrackData[0]));
  2674. tracksInBuffer /= sizeof(TRACK_DATA);
  2675. // take the lesser of the two
  2676. tracksToReturn = (tracksInBuffer < tracksOnCd) ?
  2677. tracksInBuffer :
  2678. tracksOnCd;
  2679. for( i=0; i < tracksToReturn; i++ ) {
  2680. //
  2681. // Grab Information for each track
  2682. //
  2683. cdaudioDataOut->TrackData[i].Reserved = 0;
  2684. cdaudioDataOut->TrackData[i].Control = Toc[(i*4)+12];
  2685. cdaudioDataOut->TrackData[i].TrackNumber =
  2686. (UCHAR)((i + cdaudioDataOut->FirstTrack));
  2687. cdaudioDataOut->TrackData[i].Reserved1 = 0;
  2688. cdaudioDataOut->TrackData[i].Address[0] = 0;
  2689. cdaudioDataOut->TrackData[i].Address[1] =
  2690. BCD_TO_DEC((Toc[(i*4)+13]));
  2691. cdaudioDataOut->TrackData[i].Address[2] =
  2692. BCD_TO_DEC((Toc[(i*4)+14]));
  2693. cdaudioDataOut->TrackData[i].Address[3] =
  2694. BCD_TO_DEC((Toc[(i*4)+15]));
  2695. CdDump(( 4,
  2696. "CdAudioDenonDeviceControl: Track %d %d:%d:%d\n",
  2697. cdaudioDataOut->TrackData[i].TrackNumber,
  2698. cdaudioDataOut->TrackData[i].Address[1],
  2699. cdaudioDataOut->TrackData[i].Address[2],
  2700. cdaudioDataOut->TrackData[i].Address[3]
  2701. ));
  2702. }
  2703. //
  2704. // Fake "lead out track" info
  2705. // Only if all tracks have been copied...
  2706. //
  2707. if ( tracksInBuffer > tracksOnCd ) {
  2708. cdaudioDataOut->TrackData[i].Reserved = 0;
  2709. cdaudioDataOut->TrackData[i].Control = 0;
  2710. cdaudioDataOut->TrackData[i].TrackNumber = 0xaa;
  2711. cdaudioDataOut->TrackData[i].Reserved1 = 0;
  2712. cdaudioDataOut->TrackData[i].Address[0] = 0;
  2713. cdaudioDataOut->TrackData[i].Address[1] = BCD_TO_DEC(Toc[9]);
  2714. cdaudioDataOut->TrackData[i].Address[2] = BCD_TO_DEC(Toc[10]);
  2715. cdaudioDataOut->TrackData[i].Address[3] = BCD_TO_DEC(Toc[11]);
  2716. CdDump(( 4,
  2717. "CdAudioDenonDeviceControl: Track %d %d:%d:%d\n",
  2718. cdaudioDataOut->TrackData[i].TrackNumber,
  2719. cdaudioDataOut->TrackData[i].Address[1],
  2720. cdaudioDataOut->TrackData[i].Address[2],
  2721. cdaudioDataOut->TrackData[i].Address[3]
  2722. ));
  2723. i++;
  2724. }
  2725. Irp->IoStatus.Information = ((ULONG)FIELD_OFFSET(CDROM_TOC, TrackData[i]));
  2726. }
  2727. //
  2728. // Clear out deviceExtension data
  2729. //
  2730. deviceExtension->Paused = CDAUDIO_NOT_PAUSED;
  2731. deviceExtension->PausedM = 0;
  2732. deviceExtension->PausedS = 0;
  2733. deviceExtension->PausedF = 0;
  2734. deviceExtension->LastEndM = 0;
  2735. deviceExtension->LastEndS = 0;
  2736. deviceExtension->LastEndF = 0;
  2737. //
  2738. // Free storage now that we've stored it elsewhere
  2739. //
  2740. ExFreePool( Toc );
  2741. break;
  2742. case IOCTL_CDROM_PLAY_AUDIO_MSF:
  2743. case IOCTL_CDROM_STOP_AUDIO:
  2744. {
  2745. PCDROM_PLAY_AUDIO_MSF inputBuffer =
  2746. Irp->AssociatedIrp.SystemBuffer;
  2747. Irp->IoStatus.Information = 0;
  2748. deviceExtension->PlayActive = FALSE;
  2749. srb.CdbLength = 6;
  2750. srb.TimeOutValue = AUDIO_TIMEOUT;
  2751. cdb->CDB6GENERIC.OperationCode = DENON_STOP_AUDIO_CODE;
  2752. status = SendSrbSynchronous( deviceExtension,
  2753. &srb,
  2754. NULL,
  2755. 0
  2756. );
  2757. if (NT_SUCCESS(status)) {
  2758. deviceExtension->Paused = CDAUDIO_NOT_PAUSED;
  2759. deviceExtension->PausedM = 0;
  2760. deviceExtension->PausedS = 0;
  2761. deviceExtension->PausedF = 0;
  2762. deviceExtension->LastEndM = 0;
  2763. deviceExtension->LastEndS = 0;
  2764. deviceExtension->LastEndF = 0;
  2765. } else {
  2766. CdDump(( 3,
  2767. "DenonDeviceControl => STOP failed (%lx)\n",
  2768. status ));
  2769. }
  2770. if (currentIrpStack->Parameters.DeviceIoControl.IoControlCode ==
  2771. IOCTL_CDROM_STOP_AUDIO
  2772. ) {
  2773. CdDump((3,
  2774. "DenonDeviceControl => IOCTL_CDROM_STOP_AUDIO recv'd.\n"
  2775. ));
  2776. goto SetStatusAndReturn;
  2777. }
  2778. CdDump((3,
  2779. "DenonDeviceControl => IOCTL_CDROM_PLAY_AUDIO_MSF recv'd.\n"
  2780. ));
  2781. if (currentIrpStack->Parameters.DeviceIoControl.InputBufferLength <
  2782. sizeof(CDROM_PLAY_AUDIO_MSF)
  2783. ) {
  2784. status = STATUS_INFO_LENGTH_MISMATCH;
  2785. break;
  2786. }
  2787. //
  2788. // Fill in cdb for this operation
  2789. //
  2790. srb.CdbLength = 10;
  2791. srb.TimeOutValue = AUDIO_TIMEOUT;
  2792. cdb->CDB10.OperationCode = DENON_PLAY_AUDIO_EXTENDED_CODE;
  2793. cdb->CDB10.LogicalBlockByte0 = DEC_TO_BCD(inputBuffer->StartingM);
  2794. cdb->CDB10.LogicalBlockByte1 = DEC_TO_BCD(inputBuffer->StartingS);
  2795. cdb->CDB10.LogicalBlockByte2 = DEC_TO_BCD(inputBuffer->StartingF);
  2796. cdb->CDB10.LogicalBlockByte3 = DEC_TO_BCD(inputBuffer->EndingM);
  2797. cdb->CDB10.Reserved2 = DEC_TO_BCD(inputBuffer->EndingS);
  2798. cdb->CDB10.TransferBlocksMsb = DEC_TO_BCD(inputBuffer->EndingF);
  2799. status = SendSrbSynchronous( deviceExtension,
  2800. &srb,
  2801. NULL,
  2802. 0
  2803. );
  2804. if (NT_SUCCESS(status)) {
  2805. //
  2806. // Indicate the play actition is active.
  2807. //
  2808. deviceExtension->PlayActive = TRUE;
  2809. deviceExtension->Paused = CDAUDIO_NOT_PAUSED;
  2810. //
  2811. // Set last play ending address for next pause command
  2812. //
  2813. deviceExtension->LastEndM = DEC_TO_BCD(inputBuffer->EndingM);
  2814. deviceExtension->LastEndS = DEC_TO_BCD(inputBuffer->EndingS);
  2815. deviceExtension->LastEndF = DEC_TO_BCD(inputBuffer->EndingF);
  2816. CdDump(( 3,
  2817. "DenonDeviceControl => PLAY ==> BcdLastEnd set to (%x %x %x)\n",
  2818. deviceExtension->LastEndM,
  2819. deviceExtension->LastEndS,
  2820. deviceExtension->LastEndF ));
  2821. } else {
  2822. CdDump(( 3,
  2823. "DenonDeviceControl => PLAY failed (%lx)\n",
  2824. status ));
  2825. //
  2826. // The Denon drive returns STATUS_INVALD_DEVICE_REQUEST
  2827. // when we ask to play an invalid address, so we need
  2828. // to map to STATUS_NONEXISTENT_SECTOR in order to be
  2829. // consistent with the other drives.
  2830. //
  2831. if (status==STATUS_INVALID_DEVICE_REQUEST) {
  2832. status = STATUS_NONEXISTENT_SECTOR;
  2833. }
  2834. }
  2835. }
  2836. break;
  2837. case IOCTL_CDROM_SEEK_AUDIO_MSF:
  2838. {
  2839. PCDROM_SEEK_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
  2840. Irp->IoStatus.Information = 0;
  2841. if (currentIrpStack->Parameters.DeviceIoControl.InputBufferLength <
  2842. sizeof(CDROM_SEEK_AUDIO_MSF)
  2843. ) {
  2844. status = STATUS_INFO_LENGTH_MISMATCH;
  2845. break;
  2846. }
  2847. CdDump(( 3,
  2848. "DenonDeviceControl => IOCTL_CDROM_SEEK_AUDIO_MSF recv'd.\n"
  2849. ));
  2850. //
  2851. // Fill in cdb for this operation
  2852. //
  2853. srb.CdbLength = 10;
  2854. srb.TimeOutValue = AUDIO_TIMEOUT;
  2855. cdb->CDB10.OperationCode = DENON_PLAY_AUDIO_EXTENDED_CODE;
  2856. cdb->CDB10.LogicalBlockByte0 = DEC_TO_BCD(inputBuffer->M);
  2857. cdb->CDB10.LogicalBlockByte1 = DEC_TO_BCD(inputBuffer->S);
  2858. cdb->CDB10.LogicalBlockByte2 = DEC_TO_BCD(inputBuffer->F);
  2859. cdb->CDB10.LogicalBlockByte3 = DEC_TO_BCD(inputBuffer->M);
  2860. cdb->CDB10.Reserved2 = DEC_TO_BCD(inputBuffer->S);
  2861. cdb->CDB10.TransferBlocksMsb = DEC_TO_BCD(inputBuffer->F);
  2862. status = SendSrbSynchronous( deviceExtension,
  2863. &srb,
  2864. NULL,
  2865. 0
  2866. );
  2867. if (NT_SUCCESS(status)) {
  2868. deviceExtension->Paused = CDAUDIO_PAUSED;
  2869. deviceExtension->PausedM = DEC_TO_BCD(inputBuffer->M);
  2870. deviceExtension->PausedS = DEC_TO_BCD(inputBuffer->S);
  2871. deviceExtension->PausedF = DEC_TO_BCD(inputBuffer->F);
  2872. deviceExtension->LastEndM = DEC_TO_BCD(inputBuffer->M);
  2873. deviceExtension->LastEndS = DEC_TO_BCD(inputBuffer->S);
  2874. deviceExtension->LastEndF = DEC_TO_BCD(inputBuffer->F);
  2875. CdDump(( 3,
  2876. "DenonDeviceControl => SEEK, Paused (%x %x %x) LastEnd (%x %x %x)\n",
  2877. deviceExtension->PausedM,
  2878. deviceExtension->PausedS,
  2879. deviceExtension->PausedF,
  2880. deviceExtension->LastEndM,
  2881. deviceExtension->LastEndS,
  2882. deviceExtension->LastEndF ));
  2883. } else {
  2884. CdDump(( 3,
  2885. "DenonDeviceControl => SEEK failed (%lx)\n",
  2886. status ));
  2887. //
  2888. // The Denon drive returns STATUS_INVALD_DEVICE_REQUEST
  2889. // when we ask to play an invalid address, so we need
  2890. // to map to STATUS_NONEXISTENT_SECTOR in order to be
  2891. // consistent with the other drives.
  2892. //
  2893. if (status==STATUS_INVALID_DEVICE_REQUEST) {
  2894. status = STATUS_NONEXISTENT_SECTOR;
  2895. }
  2896. }
  2897. }
  2898. break;
  2899. case IOCTL_CDROM_PAUSE_AUDIO:
  2900. {
  2901. PUCHAR SubQPtr =
  2902. ExAllocatePool( NonPagedPoolCacheAligned,
  2903. 10
  2904. );
  2905. Irp->IoStatus.Information = 0;
  2906. CdDump(( 3,
  2907. "DenonDeviceControl => IOCTL_CDROM_PAUSE_AUDIO recv'd.\n"
  2908. ));
  2909. deviceExtension->PlayActive = FALSE;
  2910. if (SubQPtr==NULL) {
  2911. status = STATUS_INSUFFICIENT_RESOURCES;
  2912. goto SetStatusAndReturn;
  2913. }
  2914. //
  2915. // Enter pause (still ) mode
  2916. //
  2917. if (deviceExtension->Paused==CDAUDIO_PAUSED) {
  2918. CdDump(( 3,
  2919. "DenonDeviceControl => PAUSE: Already Paused!\n"
  2920. ));
  2921. ExFreePool( SubQPtr );
  2922. status = STATUS_SUCCESS;
  2923. goto SetStatusAndReturn;
  2924. }
  2925. //
  2926. // Since the Denon doesn't have a pause mode,
  2927. // we'll just record the current position and
  2928. // stop the drive.
  2929. //
  2930. srb.CdbLength = 6;
  2931. srb.TimeOutValue = AUDIO_TIMEOUT;
  2932. cdb->CDB6GENERIC.OperationCode = DENON_READ_SUB_Q_CHANNEL_CODE;
  2933. cdb->CDB6GENERIC.CommandUniqueBytes[2] = 10; // Transfer Length
  2934. status = SendSrbSynchronous( deviceExtension,
  2935. &srb,
  2936. SubQPtr,
  2937. 10
  2938. );
  2939. if (!NT_SUCCESS(status)) {
  2940. CdDump(( 1,
  2941. "DenonDeviceControl => Pause, Read Q Channel failed (%lx)\n",
  2942. status ));
  2943. ExFreePool( SubQPtr );
  2944. goto SetStatusAndReturn;
  2945. }
  2946. deviceExtension->PausedM = SubQPtr[7];
  2947. deviceExtension->PausedS = SubQPtr[8];
  2948. deviceExtension->PausedF = SubQPtr[9];
  2949. RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
  2950. srb.CdbLength = 6;
  2951. srb.TimeOutValue = AUDIO_TIMEOUT;
  2952. cdb->CDB6GENERIC.OperationCode = DENON_STOP_AUDIO_CODE;
  2953. status = SendSrbSynchronous( deviceExtension,
  2954. &srb,
  2955. NULL,
  2956. 0
  2957. );
  2958. if (!NT_SUCCESS(status)) {
  2959. CdDump(( 1,
  2960. "DenonDeviceControl => PAUSE, StopAudio failed! (%lx)\n",
  2961. status ));
  2962. ExFreePool( SubQPtr );
  2963. goto SetStatusAndReturn;
  2964. }
  2965. deviceExtension->Paused = CDAUDIO_PAUSED;
  2966. deviceExtension->PausedM = SubQPtr[7];
  2967. deviceExtension->PausedS = SubQPtr[8];
  2968. deviceExtension->PausedF = SubQPtr[9];
  2969. CdDump((3,
  2970. "DenonDeviceControl => PAUSE ==> Paused set to (%x %x %x)\n",
  2971. deviceExtension->PausedM,
  2972. deviceExtension->PausedS,
  2973. deviceExtension->PausedF ));
  2974. ExFreePool( SubQPtr );
  2975. }
  2976. break;
  2977. case IOCTL_CDROM_RESUME_AUDIO:
  2978. //
  2979. // Resume cdrom
  2980. //
  2981. CdDump(( 3,
  2982. "DenonDeviceControl => IOCTL_CDROM_RESUME_AUDIO recv'd.\n"
  2983. ));
  2984. Irp->IoStatus.Information = 0;
  2985. //
  2986. // Since the Denon doesn't have a resume IOCTL,
  2987. // we'll just start playing (if paused) from the
  2988. // last recored paused position to the last recorded
  2989. // "end of play" position.
  2990. //
  2991. if (deviceExtension->Paused==CDAUDIO_NOT_PAUSED) {
  2992. status = STATUS_UNSUCCESSFUL;
  2993. goto SetStatusAndReturn;
  2994. }
  2995. //
  2996. // Fill in cdb for this operation
  2997. //
  2998. srb.CdbLength = 10;
  2999. srb.TimeOutValue = AUDIO_TIMEOUT;
  3000. cdb->CDB10.OperationCode = DENON_PLAY_AUDIO_EXTENDED_CODE;
  3001. cdb->CDB10.LogicalBlockByte0 = deviceExtension->PausedM;
  3002. cdb->CDB10.LogicalBlockByte1 = deviceExtension->PausedS;
  3003. cdb->CDB10.LogicalBlockByte2 = deviceExtension->PausedF;
  3004. cdb->CDB10.LogicalBlockByte3 = deviceExtension->LastEndM;
  3005. cdb->CDB10.Reserved2 = deviceExtension->LastEndS;
  3006. cdb->CDB10.TransferBlocksMsb = deviceExtension->LastEndF;
  3007. status = SendSrbSynchronous( deviceExtension,
  3008. &srb,
  3009. NULL,
  3010. 0
  3011. );
  3012. if (NT_SUCCESS(status)) {
  3013. deviceExtension->Paused = CDAUDIO_NOT_PAUSED;
  3014. } else {
  3015. CdDump(( 1,
  3016. "DenonDeviceControl => RESUME (%x %x %x) - (%x %x %x) failed (%lx)\n",
  3017. deviceExtension->PausedM,
  3018. deviceExtension->PausedS,
  3019. deviceExtension->PausedF,
  3020. deviceExtension->LastEndM,
  3021. deviceExtension->LastEndS,
  3022. deviceExtension->LastEndF,
  3023. status ));
  3024. }
  3025. break;
  3026. case IOCTL_CDROM_READ_Q_CHANNEL:
  3027. {
  3028. PSUB_Q_CURRENT_POSITION userPtr =
  3029. Irp->AssociatedIrp.SystemBuffer;
  3030. PUCHAR SubQPtr =
  3031. ExAllocatePool( NonPagedPoolCacheAligned,
  3032. sizeof(SUB_Q_CHANNEL_DATA)
  3033. );
  3034. CdDump(( 5,
  3035. "DenonDeviceControl => IOCTL_CDROM_READ_Q_CHANNEL recv'd.\n"
  3036. ));
  3037. if (currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength <
  3038. sizeof(SUB_Q_CURRENT_POSITION)
  3039. ) {
  3040. status = STATUS_BUFFER_TOO_SMALL;
  3041. // we have transferred zero bytes
  3042. Irp->IoStatus.Information = 0;
  3043. if (SubQPtr) ExFreePool(SubQPtr);
  3044. break;
  3045. }
  3046. if (SubQPtr==NULL) {
  3047. CdDump(( 1,
  3048. "DenonDeviceControl => READ_Q_CHANNEL, SubQPtr==NULL!\n"
  3049. ));
  3050. RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
  3051. status = STATUS_INSUFFICIENT_RESOURCES;
  3052. Irp->IoStatus.Information = 0;
  3053. goto SetStatusAndReturn;
  3054. }
  3055. if ( ((PCDROM_SUB_Q_DATA_FORMAT)userPtr)->Format!=
  3056. IOCTL_CDROM_CURRENT_POSITION) {
  3057. CdDump(( 1,
  3058. "DenonDeviceControl => READ_Q_CHANNEL, illegal Format (%d)\n",
  3059. ((PCDROM_SUB_Q_DATA_FORMAT)userPtr)->Format
  3060. ));
  3061. ExFreePool( SubQPtr );
  3062. RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
  3063. status = STATUS_UNSUCCESSFUL;
  3064. Irp->IoStatus.Information = 0;
  3065. goto SetStatusAndReturn;
  3066. }
  3067. //
  3068. // Read audio play status
  3069. //
  3070. srb.CdbLength = 6;
  3071. srb.TimeOutValue = AUDIO_TIMEOUT;
  3072. cdb->CDB6GENERIC.OperationCode = DENON_READ_SUB_Q_CHANNEL_CODE;
  3073. cdb->CDB6GENERIC.CommandUniqueBytes[2] = 10; // Transfer Length
  3074. status = SendSrbSynchronous( deviceExtension,
  3075. &srb,
  3076. SubQPtr,
  3077. 10
  3078. );
  3079. if (NT_SUCCESS(status)) {
  3080. userPtr->Header.Reserved = 0;
  3081. if (deviceExtension->Paused==CDAUDIO_PAUSED) {
  3082. deviceExtension->PlayActive = FALSE;
  3083. userPtr->Header.AudioStatus = AUDIO_STATUS_PAUSED;
  3084. } else {
  3085. if (SubQPtr[0]==0x01)
  3086. userPtr->Header.AudioStatus = AUDIO_STATUS_IN_PROGRESS;
  3087. else if (SubQPtr[0]==0x00) {
  3088. userPtr->Header.AudioStatus =
  3089. AUDIO_STATUS_PLAY_COMPLETE;
  3090. deviceExtension->PlayActive = FALSE;
  3091. } else {
  3092. deviceExtension->PlayActive = FALSE;
  3093. }
  3094. }
  3095. userPtr->Header.DataLength[0] = 0;
  3096. userPtr->Header.DataLength[0] = 12;
  3097. userPtr->FormatCode = 0x01;
  3098. userPtr->Control = SubQPtr[1];
  3099. userPtr->ADR = 0;
  3100. userPtr->TrackNumber = BCD_TO_DEC(SubQPtr[2]);
  3101. userPtr->IndexNumber = BCD_TO_DEC(SubQPtr[3]);
  3102. userPtr->AbsoluteAddress[0] = 0;
  3103. userPtr->AbsoluteAddress[1] = BCD_TO_DEC((SubQPtr[7]));
  3104. userPtr->AbsoluteAddress[2] = BCD_TO_DEC((SubQPtr[8]));
  3105. userPtr->AbsoluteAddress[3] = BCD_TO_DEC((SubQPtr[9]));
  3106. userPtr->TrackRelativeAddress[0] = 0;
  3107. userPtr->TrackRelativeAddress[1] = BCD_TO_DEC((SubQPtr[4]));
  3108. userPtr->TrackRelativeAddress[2] = BCD_TO_DEC((SubQPtr[5]));
  3109. userPtr->TrackRelativeAddress[3] = BCD_TO_DEC((SubQPtr[6]));
  3110. Irp->IoStatus.Information = sizeof(SUB_Q_CURRENT_POSITION);
  3111. } else {
  3112. CdDump(( 1,
  3113. "DenonDeviceControl => READ_Q_CHANNEL failed (%lx)\n",
  3114. status
  3115. ));
  3116. Irp->IoStatus.Information = 0;
  3117. }
  3118. ExFreePool( SubQPtr );
  3119. }
  3120. break;
  3121. case IOCTL_CDROM_EJECT_MEDIA:
  3122. //
  3123. // Build cdb to eject cartridge
  3124. //
  3125. Irp->IoStatus.Information = 0;
  3126. CdDump(( 3,
  3127. "DenonDeviceControl => IOCTL_CDROM_EJECT_MEDIA recv'd.\n"
  3128. ));
  3129. deviceExtension->PlayActive = FALSE;
  3130. srb.CdbLength = 6;
  3131. srb.TimeOutValue = AUDIO_TIMEOUT;
  3132. cdb->CDB6GENERIC.OperationCode = DENON_EJECT_CODE;
  3133. status = SendSrbSynchronous( deviceExtension,
  3134. &srb,
  3135. NULL,
  3136. 0
  3137. );
  3138. break;
  3139. case IOCTL_CDROM_GET_CONTROL:
  3140. case IOCTL_CDROM_GET_VOLUME:
  3141. case IOCTL_CDROM_SET_VOLUME:
  3142. CdDump(( 3, "DenonDeviceControl => Not Supported yet.\n" ));
  3143. Irp->IoStatus.Information = 0;
  3144. status = STATUS_INVALID_DEVICE_REQUEST;
  3145. break;
  3146. case IOCTL_CDROM_CHECK_VERIFY:
  3147. //
  3148. // Update the play active flag.
  3149. //
  3150. CdAudioIsPlayActive(DeviceObject);
  3151. default:
  3152. CdDump((10,"DenonDeviceControl => Unsupported device IOCTL\n"));
  3153. return CdAudioSendToNextDriver( DeviceObject, Irp );
  3154. break;
  3155. } // end switch( IOCTL )
  3156. SetStatusAndReturn:
  3157. //
  3158. // set status code and return
  3159. //
  3160. if (status == STATUS_VERIFY_REQUIRED) {
  3161. //
  3162. // If the status is verified required and the this request
  3163. // should bypass verify required then retry the request.
  3164. //
  3165. if (currentIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME) {
  3166. status = STATUS_IO_DEVICE_ERROR;
  3167. goto DenonRestart;
  3168. }
  3169. IoSetHardErrorOrVerifyDevice( Irp,
  3170. deviceExtension->TargetDeviceObject
  3171. );
  3172. Irp->IoStatus.Information = 0;
  3173. }
  3174. Irp->IoStatus.Status = status;
  3175. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  3176. return status;
  3177. }
  3178. NTSTATUS
  3179. CdAudioHitachiSendPauseCommand(
  3180. IN PDEVICE_OBJECT DeviceObject
  3181. )
  3182. /*++
  3183. Routine Description:
  3184. This routine sends a PAUSE cdb to the Hitachi drive. The Hitachi
  3185. drive returns a "busy" condition whenever a play audio command is in
  3186. progress...so we need to bump the drive out of audio play to issue
  3187. a new command. This routine is in place for this purpose.
  3188. Arguments:
  3189. DeviceObject
  3190. Irp
  3191. Return Value:
  3192. NTSTATUS
  3193. --*/
  3194. {
  3195. PCD_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  3196. SCSI_PASS_THROUGH srb;
  3197. PHITACHICDB cdb = (PHITACHICDB)srb.Cdb;
  3198. NTSTATUS status;
  3199. PUCHAR PausePos;
  3200. //
  3201. // Allocate buffer for pause data
  3202. //
  3203. PausePos = (PUCHAR)ExAllocatePool( NonPagedPoolCacheAligned, 3 );
  3204. if (PausePos==NULL) {
  3205. return(STATUS_INSUFFICIENT_RESOURCES);
  3206. }
  3207. RtlZeroMemory( PausePos, 3 );
  3208. //
  3209. // Clear out cdb
  3210. //
  3211. RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
  3212. //
  3213. // Clear audio play command so that next command will be issued
  3214. //
  3215. srb.CdbLength = 12;
  3216. srb.TimeOutValue = AUDIO_TIMEOUT;
  3217. cdb->PAUSE_AUDIO.OperationCode = HITACHI_PAUSE_AUDIO_CODE;
  3218. status = SendSrbSynchronous( deviceExtension,
  3219. &srb,
  3220. PausePos,
  3221. 3
  3222. );
  3223. ExFreePool( PausePos );
  3224. return status;
  3225. }
  3226. NTSTATUS
  3227. CdAudioHitachiDeviceControl(
  3228. IN PDEVICE_OBJECT DeviceObject,
  3229. IN PIRP Irp
  3230. )
  3231. /*++
  3232. Routine Description:
  3233. This routine is called by CdAudioDeviceControl to handle
  3234. audio IOCTLs sent to Hitachi cdrom drives.
  3235. Arguments:
  3236. DeviceObject
  3237. Irp
  3238. Return Value:
  3239. NTSTATUS
  3240. --*/
  3241. {
  3242. PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
  3243. PCD_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  3244. PCDROM_TOC cdaudioDataOut = Irp->AssociatedIrp.SystemBuffer;
  3245. SCSI_PASS_THROUGH srb;
  3246. PHITACHICDB cdb = (PHITACHICDB)srb.Cdb;
  3247. NTSTATUS status;
  3248. ULONG i,bytesTransfered;
  3249. PUCHAR Toc;
  3250. HitachiRestart:
  3251. //
  3252. // Clear out cdb
  3253. //
  3254. RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
  3255. //
  3256. // What IOCTL do we need to execute?
  3257. //
  3258. switch (currentIrpStack->Parameters.DeviceIoControl.IoControlCode) {
  3259. case IOCTL_CDROM_READ_TOC:
  3260. CdDump(( 3,
  3261. "HitachiDeviceControl => IOCTL_CDROM_READ_TOC recv'd.\n"
  3262. ));
  3263. //
  3264. // Must have allocated at least enough buffer space
  3265. // to store how many tracks are on the disc
  3266. //
  3267. if (currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength <
  3268. ((ULONG)FIELD_OFFSET(CDROM_TOC, TrackData[0]))
  3269. ) {
  3270. status = STATUS_BUFFER_TOO_SMALL;
  3271. // we have transferred zero bytes
  3272. Irp->IoStatus.Information = 0;
  3273. break;
  3274. }
  3275. //
  3276. // If the cd is playing music then reject this request.
  3277. //
  3278. if (CdAudioIsPlayActive(DeviceObject)) {
  3279. status = STATUS_DEVICE_BUSY;
  3280. Irp->IoStatus.Information = 0;
  3281. break;
  3282. }
  3283. //
  3284. // Allocate storage to hold TOC from disc
  3285. //
  3286. Toc = (PUCHAR)ExAllocatePool( NonPagedPoolCacheAligned,
  3287. CDROM_TOC_SIZE
  3288. );
  3289. if (Toc==NULL) {
  3290. status = STATUS_INSUFFICIENT_RESOURCES;
  3291. Irp->IoStatus.Information = 0;
  3292. goto SetStatusAndReturn;
  3293. }
  3294. //
  3295. // Set up defaults
  3296. //
  3297. RtlZeroMemory( Toc, CDROM_TOC_SIZE );
  3298. srb.CdbLength = 12;
  3299. //
  3300. // Fill in CDB
  3301. //
  3302. if (deviceExtension->Active == CDAUDIO_FUJITSU) {
  3303. cdb->READ_DISC_INFO.OperationCode = FUJITSU_READ_TOC_CODE;
  3304. } else {
  3305. cdb->READ_DISC_INFO.OperationCode = HITACHI_READ_TOC_CODE;
  3306. }
  3307. cdb->READ_DISC_INFO.AllocationLength[0] = CDROM_TOC_SIZE >> 8;
  3308. cdb->READ_DISC_INFO.AllocationLength[1] = CDROM_TOC_SIZE & 0xFF;
  3309. srb.TimeOutValue = AUDIO_TIMEOUT;
  3310. status = SendSrbSynchronous( deviceExtension,
  3311. &srb,
  3312. Toc,
  3313. CDROM_TOC_SIZE
  3314. );
  3315. if (!NT_SUCCESS(status) && (status!=STATUS_DATA_OVERRUN)) {
  3316. CdDump(( 1,
  3317. "HitachiDeviceControl => READ_TOC error (%lx)\n",
  3318. status ));
  3319. if (status != STATUS_DATA_OVERRUN) {
  3320. CdDump(( 1, "HitachiDeviceControl => SRB ERROR (%lx)\n",
  3321. status ));
  3322. ExFreePool( Toc );
  3323. Irp->IoStatus.Information = 0;
  3324. goto SetStatusAndReturn;
  3325. }
  3326. } else
  3327. status = STATUS_SUCCESS;
  3328. //
  3329. // added for cdrom101 and 102 to correspondence
  3330. //
  3331. if ( deviceExtension->Active == CDAUDIO_HITACHI ) {
  3332. //
  3333. // Translate data into our format
  3334. //
  3335. bytesTransfered =
  3336. currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength >
  3337. sizeof(CDROM_TOC) ?
  3338. sizeof(CDROM_TOC) :
  3339. currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
  3340. cdaudioDataOut->FirstTrack = Toc[2];
  3341. cdaudioDataOut->LastTrack = Toc[3];
  3342. //
  3343. // Return only N number of tracks, where N is the number of
  3344. // full tracks of info we can stuff into the user buffer
  3345. // if tracks from 1 to 2, that means there are two tracks,
  3346. // so let i go from 0 to 1 (two tracks of info)
  3347. //
  3348. {
  3349. //
  3350. // tracksToReturn == Number of real track info to return
  3351. // tracksInBuffer == How many fit into the user-supplied buffer
  3352. // tracksOnCd == Number of tracks on the CD (not including lead-out)
  3353. //
  3354. ULONG tracksToReturn;
  3355. ULONG tracksOnCd;
  3356. ULONG tracksInBuffer;
  3357. ULONG dataLength;
  3358. tracksOnCd = (cdaudioDataOut->LastTrack - cdaudioDataOut->FirstTrack) + 1;
  3359. dataLength = ((ULONG)FIELD_OFFSET(CDROM_TOC, TrackData[tracksOnCd])) - 2;
  3360. cdaudioDataOut->Length[0] = (UCHAR)(dataLength >> 8);
  3361. cdaudioDataOut->Length[1] = (UCHAR)(dataLength & 0xFF);
  3362. tracksInBuffer = currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength -
  3363. ((ULONG)FIELD_OFFSET(CDROM_TOC, TrackData[0]));
  3364. tracksInBuffer /= sizeof(TRACK_DATA);
  3365. // take the lesser of the two
  3366. tracksToReturn = (tracksInBuffer < tracksOnCd) ?
  3367. tracksInBuffer :
  3368. tracksOnCd;
  3369. for( i=0; i < tracksToReturn; i++ ) {
  3370. //
  3371. // Grab Information for each track
  3372. //
  3373. cdaudioDataOut->TrackData[i].Reserved = 0;
  3374. cdaudioDataOut->TrackData[i].Control =
  3375. ((Toc[(i*4)+8] & 0x0F) << 4) | (Toc[(i*4)+8] >> 4);
  3376. cdaudioDataOut->TrackData[i].TrackNumber =
  3377. (UCHAR)((i + cdaudioDataOut->FirstTrack));
  3378. cdaudioDataOut->TrackData[i].Reserved1 = 0;
  3379. cdaudioDataOut->TrackData[i].Address[0] = 0;
  3380. cdaudioDataOut->TrackData[i].Address[1] = Toc[(i*4)+9];
  3381. cdaudioDataOut->TrackData[i].Address[2] = Toc[(i*4)+10];
  3382. cdaudioDataOut->TrackData[i].Address[3] = Toc[(i*4)+11];
  3383. CdDump(( 4,
  3384. "CdAudioHitachiDeviceControl: Track %d %d:%d:%d\n",
  3385. cdaudioDataOut->TrackData[i].TrackNumber,
  3386. cdaudioDataOut->TrackData[i].Address[1],
  3387. cdaudioDataOut->TrackData[i].Address[2],
  3388. cdaudioDataOut->TrackData[i].Address[3]
  3389. ));
  3390. }
  3391. //
  3392. // Fake "lead out track" info
  3393. // Only if all tracks have been copied...
  3394. //
  3395. if ( tracksInBuffer > tracksOnCd ) {
  3396. cdaudioDataOut->TrackData[i].Reserved = 0;
  3397. cdaudioDataOut->TrackData[i].Control = 0x10;
  3398. cdaudioDataOut->TrackData[i].TrackNumber = 0xaa;
  3399. cdaudioDataOut->TrackData[i].Reserved1 = 0;
  3400. cdaudioDataOut->TrackData[i].Address[0] = 0;
  3401. cdaudioDataOut->TrackData[i].Address[1] = Toc[5];
  3402. cdaudioDataOut->TrackData[i].Address[2] = Toc[6];
  3403. cdaudioDataOut->TrackData[i].Address[3] = Toc[7];
  3404. CdDump(( 4,
  3405. "CdAudioHitachiDeviceControl: Track %d %d:%d:%d\n",
  3406. cdaudioDataOut->TrackData[i].TrackNumber,
  3407. cdaudioDataOut->TrackData[i].Address[1],
  3408. cdaudioDataOut->TrackData[i].Address[2],
  3409. cdaudioDataOut->TrackData[i].Address[3]
  3410. ));
  3411. i++;
  3412. }
  3413. Irp->IoStatus.Information = ((ULONG)FIELD_OFFSET(CDROM_TOC, TrackData[i]));
  3414. }
  3415. //
  3416. // Clear out device extension data
  3417. //
  3418. deviceExtension->Paused = CDAUDIO_NOT_PAUSED;
  3419. deviceExtension->PausedM = 0;
  3420. deviceExtension->PausedS = 0;
  3421. deviceExtension->PausedF = 0;
  3422. deviceExtension->LastEndM = 0;
  3423. deviceExtension->LastEndS = 0;
  3424. deviceExtension->LastEndF = 0;
  3425. } else {
  3426. //
  3427. // added for cdrom101 and 102 to correspondence
  3428. //
  3429. bytesTransfered =
  3430. currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength >
  3431. sizeof(CDROM_TOC) ?
  3432. sizeof(CDROM_TOC) :
  3433. currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
  3434. cdaudioDataOut->FirstTrack = Toc[1];
  3435. cdaudioDataOut->LastTrack = Toc[2];
  3436. //
  3437. // Return only N number of tracks, where N is the number of
  3438. // full tracks of info we can stuff into the user buffer
  3439. // if tracks from 1 to 2, that means there are two tracks,
  3440. // so let i go from 0 to 1 (two tracks of info)
  3441. //
  3442. {
  3443. //
  3444. // tracksToReturn == Number of real track info to return
  3445. // tracksInBuffer == How many fit into the user-supplied buffer
  3446. // tracksOnCd == Number of tracks on the CD (not including lead-out)
  3447. //
  3448. ULONG tracksToReturn;
  3449. ULONG tracksOnCd;
  3450. ULONG tracksInBuffer;
  3451. ULONG dataLength;
  3452. tracksOnCd = (cdaudioDataOut->LastTrack - cdaudioDataOut->FirstTrack) + 1;
  3453. dataLength = ((ULONG)FIELD_OFFSET(CDROM_TOC, TrackData[tracksOnCd])) - 2;
  3454. cdaudioDataOut->Length[0] = (UCHAR)(dataLength >> 8);
  3455. cdaudioDataOut->Length[1] = (UCHAR)(dataLength & 0xFF);
  3456. tracksInBuffer = currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength -
  3457. ((ULONG)FIELD_OFFSET(CDROM_TOC, TrackData[0]));
  3458. tracksInBuffer /= sizeof(TRACK_DATA);
  3459. // take the lesser of the two
  3460. tracksToReturn = (tracksInBuffer < tracksOnCd) ?
  3461. tracksInBuffer :
  3462. tracksOnCd;
  3463. for( i=0; i < tracksToReturn; i++ ) {
  3464. //
  3465. // Grab Information for each track
  3466. //
  3467. cdaudioDataOut->TrackData[i].Reserved = 0;
  3468. if (Toc[(i*3)+6] & 0x80)
  3469. cdaudioDataOut->TrackData[i].Control = 0x04;
  3470. else
  3471. cdaudioDataOut->TrackData[i].Control = 0;
  3472. cdaudioDataOut->TrackData[i].Adr = 0;
  3473. cdaudioDataOut->TrackData[i].TrackNumber =
  3474. (UCHAR)((i + cdaudioDataOut->FirstTrack));
  3475. cdaudioDataOut->TrackData[i].Reserved1 = 0;
  3476. cdaudioDataOut->TrackData[i].Address[0] = 0;
  3477. cdaudioDataOut->TrackData[i].Address[1] = Toc[(i*3)+6] & 0x7f;
  3478. cdaudioDataOut->TrackData[i].Address[2] = Toc[(i*3)+7];
  3479. cdaudioDataOut->TrackData[i].Address[3] = Toc[(i*3)+8];
  3480. CdDump(( 4,
  3481. "CdAudioHitachiDeviceControl: Track %d %d:%d:%d\n",
  3482. cdaudioDataOut->TrackData[i].TrackNumber,
  3483. cdaudioDataOut->TrackData[i].Address[1],
  3484. cdaudioDataOut->TrackData[i].Address[2],
  3485. cdaudioDataOut->TrackData[i].Address[3]
  3486. ));
  3487. }
  3488. //
  3489. // Fake "lead out track" info
  3490. // Only if all tracks have been copied...
  3491. //
  3492. if ( tracksInBuffer > tracksOnCd ) {
  3493. cdaudioDataOut->TrackData[i].Reserved = 0;
  3494. cdaudioDataOut->TrackData[i].Control = 0x10;
  3495. cdaudioDataOut->TrackData[i].TrackNumber = 0xaa;
  3496. cdaudioDataOut->TrackData[i].Reserved1 = 0;
  3497. cdaudioDataOut->TrackData[i].Address[0] = 0;
  3498. cdaudioDataOut->TrackData[i].Address[1] = Toc[3];
  3499. cdaudioDataOut->TrackData[i].Address[2] = Toc[4];
  3500. cdaudioDataOut->TrackData[i].Address[3] = Toc[5];
  3501. CdDump(( 4,
  3502. "CdAudioHitachiDeviceControl: Track %d %d:%d:%d\n",
  3503. cdaudioDataOut->TrackData[i].TrackNumber,
  3504. cdaudioDataOut->TrackData[i].Address[1],
  3505. cdaudioDataOut->TrackData[i].Address[2],
  3506. cdaudioDataOut->TrackData[i].Address[3]
  3507. ));
  3508. i++;
  3509. }
  3510. Irp->IoStatus.Information = ((ULONG)FIELD_OFFSET(CDROM_TOC, TrackData[i]));
  3511. }
  3512. }
  3513. //
  3514. // Free storage now that we've stored it elsewhere
  3515. //
  3516. ExFreePool( Toc );
  3517. break;
  3518. case IOCTL_CDROM_STOP_AUDIO:
  3519. deviceExtension->PlayActive = FALSE;
  3520. Irp->IoStatus.Information = 0;
  3521. //
  3522. // Kill any current play operation
  3523. //
  3524. CdAudioHitachiSendPauseCommand( DeviceObject );
  3525. //
  3526. // Same as scsi-2 spec, so just send to default driver
  3527. //
  3528. deviceExtension->Paused = CDAUDIO_NOT_PAUSED;
  3529. deviceExtension->PausedM = 0;
  3530. deviceExtension->PausedS = 0;
  3531. deviceExtension->PausedF = 0;
  3532. deviceExtension->LastEndM = 0;
  3533. deviceExtension->LastEndS = 0;
  3534. deviceExtension->LastEndF = 0;
  3535. return CdAudioSendToNextDriver( DeviceObject, Irp );
  3536. break;
  3537. case IOCTL_CDROM_PLAY_AUDIO_MSF:
  3538. {
  3539. PCDROM_PLAY_AUDIO_MSF inputBuffer =
  3540. Irp->AssociatedIrp.SystemBuffer;
  3541. Irp->IoStatus.Information = 0;
  3542. if (currentIrpStack->Parameters.DeviceIoControl.InputBufferLength <
  3543. sizeof(CDROM_PLAY_AUDIO_MSF)
  3544. ) {
  3545. status = STATUS_INFO_LENGTH_MISMATCH;
  3546. break;
  3547. }
  3548. CdDump(( 3,
  3549. "HitachiDeviceControl => IOCTL_CDROM_PLAY_AUDIO_MSF recv'd.\n"
  3550. ));
  3551. //
  3552. // Kill any current play operation
  3553. //
  3554. CdAudioHitachiSendPauseCommand( DeviceObject );
  3555. //
  3556. // Fill in CDB for PLAY operation
  3557. //
  3558. srb.CdbLength = 12;
  3559. srb.TimeOutValue = AUDIO_TIMEOUT;
  3560. cdb->PLAY_AUDIO.OperationCode = HITACHI_PLAY_AUDIO_MSF_CODE;
  3561. cdb->PLAY_AUDIO.Immediate = 1;
  3562. cdb->PLAY_AUDIO.StartingM = inputBuffer->StartingM;
  3563. cdb->PLAY_AUDIO.StartingS = inputBuffer->StartingS;
  3564. cdb->PLAY_AUDIO.StartingF = inputBuffer->StartingF;
  3565. cdb->PLAY_AUDIO.EndingM = inputBuffer->EndingM;
  3566. cdb->PLAY_AUDIO.EndingS = inputBuffer->EndingS;
  3567. cdb->PLAY_AUDIO.EndingF = inputBuffer->EndingF;
  3568. status = SendSrbSynchronous( deviceExtension,
  3569. &srb,
  3570. NULL,
  3571. 0
  3572. );
  3573. if (NT_SUCCESS(status)) {
  3574. //
  3575. // Indicate the play actition is active.
  3576. //
  3577. deviceExtension->PlayActive = TRUE;
  3578. deviceExtension->Paused = CDAUDIO_NOT_PAUSED;
  3579. //
  3580. // Set last play ending address for next pause command
  3581. //
  3582. deviceExtension->PausedM = inputBuffer->StartingM;
  3583. deviceExtension->PausedS = inputBuffer->StartingS;
  3584. deviceExtension->PausedF = inputBuffer->StartingF;
  3585. deviceExtension->LastEndM = inputBuffer->EndingM;
  3586. deviceExtension->LastEndS = inputBuffer->EndingS;
  3587. deviceExtension->LastEndF = inputBuffer->EndingF;
  3588. } else {
  3589. CdDump(( 3,
  3590. "HitachiDeviceControl => PLAY failed (%lx)\n",
  3591. status ));
  3592. }
  3593. }
  3594. break;
  3595. case IOCTL_CDROM_SEEK_AUDIO_MSF:
  3596. {
  3597. PCDROM_SEEK_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
  3598. Irp->IoStatus.Information = 0;
  3599. if (currentIrpStack->Parameters.DeviceIoControl.InputBufferLength <
  3600. sizeof(CDROM_SEEK_AUDIO_MSF)
  3601. ) {
  3602. status = STATUS_INFO_LENGTH_MISMATCH;
  3603. break;
  3604. }
  3605. CdDump(( 3,
  3606. "HitachiDeviceControl => IOCTL_CDROM_SEEK_AUDIO_MSF recv'd.\n"
  3607. ));
  3608. //
  3609. // Kill any current play operation
  3610. //
  3611. CdAudioHitachiSendPauseCommand( DeviceObject );
  3612. //
  3613. // seek to MSF and enter pause (still) mode.
  3614. //
  3615. //
  3616. // Fill in CDB for PLAY operation
  3617. //
  3618. srb.CdbLength = 12;
  3619. srb.TimeOutValue = AUDIO_TIMEOUT;
  3620. cdb->PLAY_AUDIO.OperationCode = HITACHI_PLAY_AUDIO_MSF_CODE;
  3621. cdb->PLAY_AUDIO.Immediate = 1;
  3622. cdb->PLAY_AUDIO.StartingM = inputBuffer->M;
  3623. cdb->PLAY_AUDIO.StartingS = inputBuffer->S;
  3624. cdb->PLAY_AUDIO.StartingF = inputBuffer->F;
  3625. cdb->PLAY_AUDIO.EndingM = inputBuffer->M;
  3626. cdb->PLAY_AUDIO.EndingS = inputBuffer->S;
  3627. cdb->PLAY_AUDIO.EndingF = inputBuffer->F;
  3628. status = SendSrbSynchronous( deviceExtension,
  3629. &srb,
  3630. NULL,
  3631. 0
  3632. );
  3633. if (NT_SUCCESS(status)) {
  3634. deviceExtension->PausedM = inputBuffer->M;
  3635. deviceExtension->PausedS = inputBuffer->S;
  3636. deviceExtension->PausedF = inputBuffer->F;
  3637. deviceExtension->LastEndM = inputBuffer->M;
  3638. deviceExtension->LastEndS = inputBuffer->S;
  3639. deviceExtension->LastEndF = inputBuffer->F;
  3640. } else {
  3641. CdDump(( 3,
  3642. "HitachiDeviceControl => SEEK failed (%lx)\n",
  3643. status ));
  3644. }
  3645. }
  3646. break;
  3647. case IOCTL_CDROM_PAUSE_AUDIO:
  3648. {
  3649. PUCHAR PausePos = ExAllocatePool( NonPagedPoolCacheAligned, 3 );
  3650. Irp->IoStatus.Information = 0;
  3651. if (PausePos==NULL) {
  3652. status = STATUS_INSUFFICIENT_RESOURCES;
  3653. goto SetStatusAndReturn;
  3654. }
  3655. deviceExtension->PlayActive = FALSE;
  3656. RtlZeroMemory( PausePos, 3 );
  3657. CdDump(( 3,
  3658. "HitachiDeviceControl => IOCTL_CDROM_PAUSE_AUDIO recv'd.\n"
  3659. ));
  3660. //
  3661. // Enter pause (still ) mode
  3662. //
  3663. srb.CdbLength = 12;
  3664. srb.TimeOutValue = AUDIO_TIMEOUT;
  3665. cdb->PAUSE_AUDIO.OperationCode = HITACHI_PAUSE_AUDIO_CODE;
  3666. status = SendSrbSynchronous( deviceExtension,
  3667. &srb,
  3668. PausePos,
  3669. 3
  3670. );
  3671. deviceExtension->Paused = CDAUDIO_PAUSED;
  3672. deviceExtension->PausedM = PausePos[0];
  3673. deviceExtension->PausedS = PausePos[1];
  3674. deviceExtension->PausedF = PausePos[2];
  3675. ExFreePool( PausePos );
  3676. }
  3677. break;
  3678. case IOCTL_CDROM_RESUME_AUDIO:
  3679. CdDump(( 3,
  3680. "HitachiDeviceControl => IOCTL_CDROM_RESUME_AUDIO recv'd.\n"
  3681. ));
  3682. Irp->IoStatus.Information = 0;
  3683. //
  3684. // Kill any current play operation
  3685. //
  3686. CdAudioHitachiSendPauseCommand( DeviceObject );
  3687. //
  3688. // Resume play
  3689. //
  3690. //
  3691. // Fill in CDB for PLAY operation
  3692. //
  3693. srb.CdbLength = 12;
  3694. srb.TimeOutValue = AUDIO_TIMEOUT;
  3695. cdb->PLAY_AUDIO.OperationCode = HITACHI_PLAY_AUDIO_MSF_CODE;
  3696. cdb->PLAY_AUDIO.Immediate = 1;
  3697. cdb->PLAY_AUDIO.StartingM = deviceExtension->PausedM;
  3698. cdb->PLAY_AUDIO.StartingS = deviceExtension->PausedS;
  3699. cdb->PLAY_AUDIO.StartingF = deviceExtension->PausedF;
  3700. cdb->PLAY_AUDIO.EndingM = deviceExtension->LastEndM;
  3701. cdb->PLAY_AUDIO.EndingS = deviceExtension->LastEndS;
  3702. cdb->PLAY_AUDIO.EndingF = deviceExtension->LastEndF;
  3703. status = SendSrbSynchronous( deviceExtension,
  3704. &srb,
  3705. NULL,
  3706. 0
  3707. );
  3708. if (NT_SUCCESS(status)) {
  3709. deviceExtension->Paused = CDAUDIO_NOT_PAUSED;
  3710. }
  3711. break;
  3712. case IOCTL_CDROM_READ_Q_CHANNEL:
  3713. {
  3714. PSUB_Q_CURRENT_POSITION userPtr =
  3715. Irp->AssociatedIrp.SystemBuffer;
  3716. PUCHAR SubQPtr =
  3717. ExAllocatePool( NonPagedPoolCacheAligned,
  3718. sizeof(SUB_Q_CHANNEL_DATA)
  3719. );
  3720. if (currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength <
  3721. sizeof(SUB_Q_CURRENT_POSITION)
  3722. ) {
  3723. status = STATUS_BUFFER_TOO_SMALL;
  3724. // we have transferred zero bytes
  3725. Irp->IoStatus.Information = 0;
  3726. if (SubQPtr) ExFreePool(SubQPtr);
  3727. break;
  3728. }
  3729. CdDump(( 5,
  3730. "HitachiDeviceControl => IOCTL_CDROM_READ_Q_CHANNEL recv'd.\n"
  3731. ));
  3732. if (SubQPtr==NULL) {
  3733. CdDump(( 1,
  3734. "HitachiDeviceControl => READ_Q_CHANNEL, SubQPtr==NULL!\n"
  3735. ));
  3736. status = STATUS_INSUFFICIENT_RESOURCES;
  3737. Irp->IoStatus.Information = 0;
  3738. goto SetStatusAndReturn;
  3739. }
  3740. if ( ((PCDROM_SUB_Q_DATA_FORMAT)userPtr)->Format!=
  3741. IOCTL_CDROM_CURRENT_POSITION) {
  3742. CdDump(( 1,
  3743. "HitachiDeviceControl => READ_Q_CHANNEL, illegal Format (%d)\n",
  3744. ((PCDROM_SUB_Q_DATA_FORMAT)userPtr)->Format
  3745. ));
  3746. ExFreePool( SubQPtr );
  3747. status = STATUS_UNSUCCESSFUL;
  3748. Irp->IoStatus.Information = 0;
  3749. goto SetStatusAndReturn;
  3750. }
  3751. //
  3752. // Set up to read Q Channel
  3753. //
  3754. srb.CdbLength = 12;
  3755. srb.TimeOutValue = AUDIO_TIMEOUT;
  3756. cdb->AUDIO_STATUS.OperationCode = HITACHI_READ_SUB_Q_CHANNEL_CODE;
  3757. Retry:
  3758. status = SendSrbSynchronous( deviceExtension,
  3759. &srb,
  3760. SubQPtr,
  3761. sizeof(SUB_Q_CHANNEL_DATA)
  3762. );
  3763. if ((NT_SUCCESS(status)) || (status==STATUS_DATA_OVERRUN)) {
  3764. //
  3765. // While playing one track of Japanese music CDs on "CD player",
  3766. // track number is incremented unexpectedly.
  3767. // Some of SubQ data in Japanese music cd does not contain current position
  3768. // information. This is distinguished by lower 4 bits of SubQPtr[1]. If this
  3769. // data is needless, retry READ_SUB_Q_CHANNEL_CODE command until required
  3770. // information will be got.
  3771. //
  3772. if ((SubQPtr[1] & 0x0F) != 1)
  3773. goto Retry;
  3774. userPtr->Header.Reserved = 0;
  3775. if (deviceExtension->Paused == CDAUDIO_PAUSED) {
  3776. deviceExtension->PlayActive = FALSE;
  3777. userPtr->Header.AudioStatus = AUDIO_STATUS_PAUSED;
  3778. } else {
  3779. if (SubQPtr[0]==0x01)
  3780. userPtr->Header.AudioStatus = AUDIO_STATUS_IN_PROGRESS;
  3781. else if (SubQPtr[0]==0x00) {
  3782. userPtr->Header.AudioStatus = AUDIO_STATUS_PLAY_COMPLETE;
  3783. deviceExtension->PlayActive = FALSE;
  3784. } else {
  3785. deviceExtension->PlayActive = FALSE;
  3786. }
  3787. }
  3788. userPtr->Header.DataLength[0] = 0;
  3789. userPtr->Header.DataLength[0] = 12;
  3790. userPtr->FormatCode = 0x01;
  3791. userPtr->Control = ((SubQPtr[1] & 0xF0) >> 4);
  3792. userPtr->ADR = SubQPtr[1] & 0x0F;
  3793. userPtr->TrackNumber = SubQPtr[2];
  3794. userPtr->IndexNumber = SubQPtr[3];
  3795. userPtr->AbsoluteAddress[0] = 0;
  3796. userPtr->AbsoluteAddress[1] = SubQPtr[8];
  3797. userPtr->AbsoluteAddress[2] = SubQPtr[9];
  3798. userPtr->AbsoluteAddress[3] = SubQPtr[10];
  3799. userPtr->TrackRelativeAddress[0] = 0;
  3800. userPtr->TrackRelativeAddress[1] = SubQPtr[4];
  3801. userPtr->TrackRelativeAddress[2] = SubQPtr[5];
  3802. userPtr->TrackRelativeAddress[3] = SubQPtr[6];
  3803. Irp->IoStatus.Information = sizeof(SUB_Q_CURRENT_POSITION);
  3804. status = STATUS_SUCCESS;
  3805. } else {
  3806. Irp->IoStatus.Information = 0;
  3807. CdDump(( 1,
  3808. "HitachiDeviceControl => READ_Q_CHANNEL failed (%lx)\n",
  3809. status
  3810. ));
  3811. }
  3812. ExFreePool( SubQPtr );
  3813. }
  3814. break;
  3815. case IOCTL_CDROM_EJECT_MEDIA:
  3816. {
  3817. PUCHAR EjectStatus = ExAllocatePool( NonPagedPoolCacheAligned, 1 );
  3818. Irp->IoStatus.Information = 0;
  3819. if (EjectStatus==NULL) {
  3820. status = STATUS_INSUFFICIENT_RESOURCES;
  3821. goto SetStatusAndReturn;
  3822. }
  3823. deviceExtension->PlayActive = FALSE;
  3824. CdDump(( 3,
  3825. "HitachiDeviceControl => IOCTL_CDROM_EJECT_MEDIA recv'd.\n"
  3826. ));
  3827. //
  3828. // Set up to EJECT disc
  3829. //
  3830. srb.CdbLength = 12;
  3831. srb.TimeOutValue = AUDIO_TIMEOUT;
  3832. cdb->EJECT.OperationCode = HITACHI_EJECT_CODE;
  3833. cdb->EJECT.Eject = 1; // Set Eject flag
  3834. status = SendSrbSynchronous( deviceExtension,
  3835. &srb,
  3836. EjectStatus,
  3837. 1
  3838. );
  3839. if (NT_SUCCESS(status)) {
  3840. deviceExtension->Paused = CDAUDIO_NOT_PAUSED;
  3841. deviceExtension->PausedM = 0;
  3842. deviceExtension->PausedS = 0;
  3843. deviceExtension->PausedF = 0;
  3844. deviceExtension->LastEndM = 0;
  3845. deviceExtension->LastEndS = 0;
  3846. deviceExtension->LastEndF = 0;
  3847. }
  3848. ExFreePool( EjectStatus );
  3849. }
  3850. break;
  3851. case IOCTL_CDROM_GET_CONTROL:
  3852. case IOCTL_CDROM_GET_VOLUME:
  3853. case IOCTL_CDROM_SET_VOLUME:
  3854. CdDump(( 3, "CdAudioHitachieviceControl: Not Supported yet.\n" ));
  3855. Irp->IoStatus.Information = 0;
  3856. status = STATUS_INVALID_DEVICE_REQUEST;
  3857. break;
  3858. case IOCTL_CDROM_CHECK_VERIFY:
  3859. //
  3860. // Update the play active flag.
  3861. //
  3862. CdAudioIsPlayActive(DeviceObject);
  3863. default:
  3864. CdDump((10,"HitachiDeviceControl => Unsupported device IOCTL\n"));
  3865. return CdAudioSendToNextDriver( DeviceObject, Irp );
  3866. break;
  3867. } // end switch( IOCTL )
  3868. SetStatusAndReturn:
  3869. //
  3870. // set status code and return
  3871. //
  3872. if (status == STATUS_VERIFY_REQUIRED) {
  3873. //
  3874. // If the status is verified required and the this request
  3875. // should bypass verify required then retry the request.
  3876. //
  3877. if (currentIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME) {
  3878. status = STATUS_IO_DEVICE_ERROR;
  3879. goto HitachiRestart;
  3880. }
  3881. IoSetHardErrorOrVerifyDevice( Irp,
  3882. deviceExtension->TargetDeviceObject
  3883. );
  3884. Irp->IoStatus.Information = 0;
  3885. }
  3886. Irp->IoStatus.Status = status;
  3887. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  3888. return status;
  3889. }
  3890. NTSTATUS
  3891. CdAudio535DeviceControl(
  3892. PDEVICE_OBJECT DeviceObject,
  3893. PIRP Irp
  3894. )
  3895. /*++
  3896. Routine Description:
  3897. This routine is called by CdAudioDeviceControl to handle
  3898. audio IOCTLs sent to Chinon CDS-535 cdrom drive.
  3899. Arguments:
  3900. DeviceObject
  3901. Irp
  3902. Return Value:
  3903. NTSTATUS
  3904. --*/
  3905. {
  3906. PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
  3907. PCD_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  3908. PCDROM_TOC cdaudioDataOut = Irp->AssociatedIrp.SystemBuffer;
  3909. SCSI_PASS_THROUGH srb;
  3910. PREAD_CAPACITY_DATA lastSession;
  3911. PCDB cdb = (PCDB)srb.Cdb;
  3912. NTSTATUS status;
  3913. ULONG i,bytesTransfered;
  3914. PUCHAR Toc;
  3915. ULONG destblock;
  3916. //
  3917. // Clear out cdb
  3918. //
  3919. RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
  3920. //
  3921. // What IOCTL do we need to execute?
  3922. //
  3923. switch (currentIrpStack->Parameters.DeviceIoControl.IoControlCode) {
  3924. case IOCTL_CDROM_GET_LAST_SESSION:
  3925. //
  3926. // If the cd is playing music then reject this request.
  3927. //
  3928. if (CdAudioIsPlayActive(DeviceObject)) {
  3929. status = STATUS_DEVICE_BUSY;
  3930. Irp->IoStatus.Information = 0;
  3931. break;
  3932. }
  3933. if (currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength <
  3934. (ULONG)(FIELD_OFFSET(CDROM_TOC, TrackData[1]))) {
  3935. status = STATUS_BUFFER_TOO_SMALL;
  3936. // we have transferred zero bytes
  3937. Irp->IoStatus.Information = 0;
  3938. break;
  3939. }
  3940. // Allocate storage to hold lastSession from disc
  3941. //
  3942. lastSession = ExAllocatePool( NonPagedPoolCacheAligned,
  3943. sizeof(READ_CAPACITY_DATA)
  3944. );
  3945. if (lastSession==NULL) {
  3946. status = STATUS_INSUFFICIENT_RESOURCES;
  3947. Irp->IoStatus.Information = 0;
  3948. goto SetStatusAndReturn;
  3949. }
  3950. //
  3951. // Set up defaults
  3952. //
  3953. RtlZeroMemory( lastSession, sizeof(READ_CAPACITY_DATA));
  3954. srb.CdbLength = 10;
  3955. //
  3956. // Fill in CDB
  3957. //
  3958. cdb->CDB10.OperationCode = CDS535_GET_LAST_SESSION;
  3959. srb.TimeOutValue = AUDIO_TIMEOUT;
  3960. status = SendSrbSynchronous( deviceExtension,
  3961. &srb,
  3962. lastSession,
  3963. sizeof(READ_CAPACITY_DATA)
  3964. );
  3965. if (!NT_SUCCESS(status)) {
  3966. CdDump(( 1,
  3967. "535DeviceControl => READ_TOC error (%lx)\n",
  3968. status ));
  3969. ExFreePool( lastSession );
  3970. Irp->IoStatus.Information = 0;
  3971. goto SetStatusAndReturn;
  3972. } else {
  3973. status = STATUS_SUCCESS;
  3974. }
  3975. //
  3976. // Translate data into our format.
  3977. //
  3978. bytesTransfered = FIELD_OFFSET(CDROM_TOC, TrackData[1]);
  3979. Irp->IoStatus.Information = bytesTransfered;
  3980. RtlZeroMemory(cdaudioDataOut, bytesTransfered);
  3981. cdaudioDataOut->Length[0] = (UCHAR)((bytesTransfered-2) >> 8);
  3982. cdaudioDataOut->Length[1] = (UCHAR)((bytesTransfered-2) & 0xFF);
  3983. //
  3984. // Determine if this is a multisession cd.
  3985. //
  3986. if (lastSession->LogicalBlockAddress == 0) {
  3987. //
  3988. // This is a single session disk. Just return.
  3989. //
  3990. ExFreePool(lastSession);
  3991. break;
  3992. }
  3993. //
  3994. // Fake the session information.
  3995. //
  3996. cdaudioDataOut->FirstTrack = 1;
  3997. cdaudioDataOut->LastTrack = 2;
  3998. CdDump(( 4,
  3999. "535DeviceControl => Tracks %d - %d, (%x bytes)\n",
  4000. cdaudioDataOut->FirstTrack,
  4001. cdaudioDataOut->LastTrack,
  4002. bytesTransfered
  4003. ));
  4004. //
  4005. // Grab Information for the last session.
  4006. //
  4007. *((ULONG *)&cdaudioDataOut->TrackData[0].Address[0]) =
  4008. lastSession->LogicalBlockAddress;
  4009. //
  4010. // Free storage now that we've stored it elsewhere
  4011. //
  4012. ExFreePool( lastSession );
  4013. break;
  4014. case IOCTL_CDROM_READ_TOC:
  4015. CdDump(( 3,
  4016. "535DeviceControl => IOCTL_CDROM_READ_TOC recv'd.\n"
  4017. ));
  4018. //
  4019. // Must have allocated at least enough buffer space
  4020. // to store how many tracks are on the disc
  4021. //
  4022. if (currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength <
  4023. ((ULONG)FIELD_OFFSET(CDROM_TOC, TrackData[0]))
  4024. ) {
  4025. status = STATUS_BUFFER_TOO_SMALL;
  4026. // we have transferred zero bytes
  4027. Irp->IoStatus.Information = 0;
  4028. break;
  4029. }
  4030. //
  4031. // If the cd is playing music then reject this request.
  4032. //
  4033. if (CdAudioIsPlayActive(DeviceObject)) {
  4034. status = STATUS_DEVICE_BUSY;
  4035. Irp->IoStatus.Information = 0;
  4036. break;
  4037. }
  4038. //
  4039. // Allocate storage to hold TOC from disc
  4040. //
  4041. Toc = (PUCHAR)ExAllocatePool( NonPagedPoolCacheAligned,
  4042. CDROM_TOC_SIZE
  4043. );
  4044. if (Toc==NULL) {
  4045. status = STATUS_INSUFFICIENT_RESOURCES;
  4046. Irp->IoStatus.Information = 0;
  4047. goto SetStatusAndReturn;
  4048. }
  4049. //
  4050. // Set up defaults
  4051. //
  4052. RtlZeroMemory( Toc, CDROM_TOC_SIZE );
  4053. //
  4054. // Fill in cdb for this operation
  4055. //
  4056. cdb->CDB10.OperationCode = CDS535_READ_TOC_CODE;
  4057. cdb->CDB10.Reserved1 = 1; // MSF mode
  4058. cdb->CDB10.TransferBlocksMsb = (CDROM_TOC_SIZE >> 8);
  4059. cdb->CDB10.TransferBlocksLsb = (CDROM_TOC_SIZE & 0xFF);
  4060. srb.TimeOutValue = AUDIO_TIMEOUT;
  4061. srb.CdbLength = 10;
  4062. status = SendSrbSynchronous( deviceExtension,
  4063. &srb,
  4064. Toc,
  4065. CDROM_TOC_SIZE
  4066. );
  4067. if (!NT_SUCCESS(status) && (status!=STATUS_DATA_OVERRUN)) {
  4068. CdDump(( 1,
  4069. "535DeviceControl => READ_TOC error (%lx)\n",
  4070. status ));
  4071. if (status != STATUS_DATA_OVERRUN) {
  4072. CdDump(( 1, "535DeviceControl => SRB ERROR (%lx)\n",
  4073. status ));
  4074. ExFreePool( Toc );
  4075. Irp->IoStatus.Information = 0;
  4076. goto SetStatusAndReturn;
  4077. }
  4078. } else {
  4079. status = STATUS_SUCCESS;
  4080. }
  4081. //
  4082. // Translate data into SCSI-II format
  4083. // (track numbers, except 0xAA, must be converted from BCD)
  4084. bytesTransfered =
  4085. currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength >
  4086. sizeof(CDROM_TOC) ?
  4087. sizeof(CDROM_TOC) :
  4088. currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
  4089. cdaudioDataOut->Length[0] = Toc[0];
  4090. cdaudioDataOut->Length[1] = Toc[1];
  4091. cdaudioDataOut->FirstTrack = BCD_TO_DEC(Toc[2]);
  4092. cdaudioDataOut->LastTrack = BCD_TO_DEC(Toc[3]);
  4093. //
  4094. // Return only N number of tracks, where N is the number of
  4095. // full tracks of info we can stuff into the user buffer
  4096. // if tracks from 1 to 2, that means there are two tracks,
  4097. // so let i go from 0 to 1 (two tracks of info)
  4098. //
  4099. {
  4100. //
  4101. // tracksToReturn == Number of real track info to return
  4102. // tracksInBuffer == How many fit into the user-supplied buffer
  4103. // tracksOnCd == Number of tracks on the CD (not including lead-out)
  4104. //
  4105. ULONG tracksToReturn;
  4106. ULONG tracksOnCd;
  4107. ULONG tracksInBuffer;
  4108. tracksOnCd = (cdaudioDataOut->LastTrack - cdaudioDataOut->FirstTrack) + 1;
  4109. tracksInBuffer = currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength -
  4110. ((ULONG)FIELD_OFFSET(CDROM_TOC, TrackData[0]));
  4111. tracksInBuffer /= sizeof(TRACK_DATA);
  4112. // take the lesser of the two
  4113. tracksToReturn = (tracksInBuffer < tracksOnCd) ?
  4114. tracksInBuffer :
  4115. tracksOnCd;
  4116. for( i=0; i < tracksToReturn; i++ ) {
  4117. //
  4118. // Grab Information for each track
  4119. //
  4120. cdaudioDataOut->TrackData[i].Reserved = 0;
  4121. cdaudioDataOut->TrackData[i].Control = Toc[(i*8)+4+1];
  4122. cdaudioDataOut->TrackData[i].TrackNumber =
  4123. BCD_TO_DEC(Toc[(i*8)+4+2]);
  4124. cdaudioDataOut->TrackData[i].Reserved1 = 0;
  4125. cdaudioDataOut->TrackData[i].Address[0] = 0;
  4126. cdaudioDataOut->TrackData[i].Address[1] = Toc[(i*8)+4+5];
  4127. cdaudioDataOut->TrackData[i].Address[2] = Toc[(i*8)+4+6];
  4128. cdaudioDataOut->TrackData[i].Address[3] = Toc[(i*8)+4+7];
  4129. CdDump(( 4,
  4130. "CdAudio535DeviceControl: Track %d %d:%d:%d\n",
  4131. cdaudioDataOut->TrackData[i].TrackNumber,
  4132. cdaudioDataOut->TrackData[i].Address[1],
  4133. cdaudioDataOut->TrackData[i].Address[2],
  4134. cdaudioDataOut->TrackData[i].Address[3]
  4135. ));
  4136. }
  4137. //
  4138. // Fake "lead out track" info
  4139. // Only if all tracks have been copied...
  4140. //
  4141. if ( tracksInBuffer > tracksOnCd ) {
  4142. cdaudioDataOut->TrackData[i].Reserved = 0;
  4143. cdaudioDataOut->TrackData[i].Control = Toc[(i*8)+4+1];
  4144. cdaudioDataOut->TrackData[i].TrackNumber = Toc[(i*8)+4+2]; // leave as 0xAA
  4145. cdaudioDataOut->TrackData[i].Reserved1 = 0;
  4146. cdaudioDataOut->TrackData[i].Address[0] = 0;
  4147. cdaudioDataOut->TrackData[i].Address[1] = Toc[(i*8)+4+5];
  4148. cdaudioDataOut->TrackData[i].Address[2] = Toc[(i*8)+4+6];
  4149. cdaudioDataOut->TrackData[i].Address[3] = Toc[(i*8)+4+7];
  4150. CdDump(( 4,
  4151. "CdAudio535DeviceControl: Track %d %d:%d:%d\n",
  4152. cdaudioDataOut->TrackData[i].TrackNumber,
  4153. cdaudioDataOut->TrackData[i].Address[1],
  4154. cdaudioDataOut->TrackData[i].Address[2],
  4155. cdaudioDataOut->TrackData[i].Address[3]
  4156. ));
  4157. i++;
  4158. }
  4159. Irp->IoStatus.Information = ((ULONG)FIELD_OFFSET(CDROM_TOC, TrackData[i]));
  4160. }
  4161. //
  4162. // Free storage now that we've stored it elsewhere
  4163. //
  4164. ExFreePool( Toc );
  4165. break;
  4166. case IOCTL_CDROM_READ_Q_CHANNEL:
  4167. {
  4168. PSUB_Q_CURRENT_POSITION userPtr =
  4169. Irp->AssociatedIrp.SystemBuffer;
  4170. PUCHAR SubQPtr =
  4171. ExAllocatePool( NonPagedPoolCacheAligned,
  4172. sizeof(SUB_Q_CURRENT_POSITION)
  4173. );
  4174. if (currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength <
  4175. sizeof(SUB_Q_CURRENT_POSITION)
  4176. ) {
  4177. status = STATUS_BUFFER_TOO_SMALL;
  4178. // we have transferred zero bytes
  4179. Irp->IoStatus.Information = 0;
  4180. if (SubQPtr) ExFreePool(SubQPtr);
  4181. break;
  4182. }
  4183. CdDump(( 5,
  4184. "535DeviceControl => IOCTL_CDROM_READ_Q_CHANNEL recv'd.\n"
  4185. ));
  4186. if (SubQPtr==NULL) {
  4187. CdDump(( 1,
  4188. "535DeviceControl => READ_Q_CHANNEL, SubQPtr==NULL!\n"
  4189. ));
  4190. RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
  4191. status = STATUS_INSUFFICIENT_RESOURCES;
  4192. Irp->IoStatus.Information = 0;
  4193. goto SetStatusAndReturn;
  4194. }
  4195. if ( ((PCDROM_SUB_Q_DATA_FORMAT)userPtr)->Format!=
  4196. IOCTL_CDROM_CURRENT_POSITION) {
  4197. CdDump(( 1,
  4198. "535DeviceControl => READ_Q_CHANNEL, illegal Format (%d)\n",
  4199. ((PCDROM_SUB_Q_DATA_FORMAT)userPtr)->Format
  4200. ));
  4201. ExFreePool( SubQPtr );
  4202. RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
  4203. status = STATUS_UNSUCCESSFUL;
  4204. Irp->IoStatus.Information = 0;
  4205. goto SetStatusAndReturn;
  4206. }
  4207. //
  4208. // Get Current Position
  4209. //
  4210. srb.CdbLength = 10;
  4211. srb.TimeOutValue = AUDIO_TIMEOUT;
  4212. cdb->SUBCHANNEL.OperationCode = CDS535_READ_SUB_Q_CHANNEL_CODE;
  4213. cdb->SUBCHANNEL.Msf = 1;
  4214. cdb->SUBCHANNEL.SubQ = 1;
  4215. cdb->SUBCHANNEL.Format = 1;
  4216. cdb->SUBCHANNEL.AllocationLength[1] = sizeof(SUB_Q_CURRENT_POSITION);
  4217. status = SendSrbSynchronous( deviceExtension,
  4218. &srb,
  4219. SubQPtr,
  4220. sizeof(SUB_Q_CURRENT_POSITION)
  4221. );
  4222. //
  4223. // Copy current position, converting track and index from BCD
  4224. //
  4225. if (NT_SUCCESS(status)) {
  4226. if (SubQPtr[1] == 0x11) deviceExtension->PlayActive = TRUE;
  4227. else deviceExtension->PlayActive = FALSE;
  4228. userPtr->Header.Reserved = 0;
  4229. userPtr->Header.AudioStatus = SubQPtr[1];
  4230. userPtr->Header.DataLength[0] = 0;
  4231. userPtr->Header.DataLength[1] = 12;
  4232. userPtr->FormatCode = 0x01;
  4233. userPtr->Control = SubQPtr[5];
  4234. userPtr->ADR = 0;
  4235. userPtr->TrackNumber = BCD_TO_DEC(SubQPtr[6]);
  4236. userPtr->IndexNumber = BCD_TO_DEC(SubQPtr[7]);
  4237. userPtr->AbsoluteAddress[0] = 0;
  4238. userPtr->AbsoluteAddress[1] = SubQPtr[9];
  4239. userPtr->AbsoluteAddress[2] = SubQPtr[10];
  4240. userPtr->AbsoluteAddress[3] = SubQPtr[11];
  4241. userPtr->TrackRelativeAddress[0] = 0;
  4242. userPtr->TrackRelativeAddress[1] = SubQPtr[13];
  4243. userPtr->TrackRelativeAddress[2] = SubQPtr[14];
  4244. userPtr->TrackRelativeAddress[3] = SubQPtr[15];
  4245. Irp->IoStatus.Information = sizeof(SUB_Q_CURRENT_POSITION);
  4246. } else {
  4247. Irp->IoStatus.Information = 0;
  4248. CdDump(( 1,
  4249. "535DeviceControl => READ_Q_CHANNEL failed (%lx)\n",
  4250. status
  4251. ));
  4252. }
  4253. ExFreePool( SubQPtr );
  4254. }
  4255. break;
  4256. case IOCTL_CDROM_PLAY_AUDIO_MSF:
  4257. {
  4258. PCDROM_PLAY_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
  4259. Irp->IoStatus.Information = 0;
  4260. //
  4261. // Play Audio MSF
  4262. //
  4263. CdDump((2,"535DeviceControl: Play audio MSF\n"));
  4264. if (currentIrpStack->Parameters.DeviceIoControl.InputBufferLength <
  4265. sizeof(CDROM_PLAY_AUDIO_MSF)
  4266. ) {
  4267. status = STATUS_INFO_LENGTH_MISMATCH;
  4268. break;
  4269. }
  4270. if (inputBuffer->StartingM == inputBuffer->EndingM &&
  4271. inputBuffer->StartingS == inputBuffer->EndingS &&
  4272. inputBuffer->StartingF == inputBuffer->EndingF) {
  4273. cdb->PAUSE_RESUME.OperationCode = SCSIOP_PAUSE_RESUME;
  4274. cdb->PAUSE_RESUME.Action = CDB_AUDIO_PAUSE;
  4275. } else {
  4276. cdb->PLAY_AUDIO_MSF.OperationCode = SCSIOP_PLAY_AUDIO_MSF;
  4277. cdb->PLAY_AUDIO_MSF.StartingM = inputBuffer->StartingM;
  4278. cdb->PLAY_AUDIO_MSF.StartingS = inputBuffer->StartingS;
  4279. cdb->PLAY_AUDIO_MSF.StartingF = inputBuffer->StartingF;
  4280. cdb->PLAY_AUDIO_MSF.EndingM = inputBuffer->EndingM;
  4281. cdb->PLAY_AUDIO_MSF.EndingS = inputBuffer->EndingS;
  4282. cdb->PLAY_AUDIO_MSF.EndingF = inputBuffer->EndingF;
  4283. }
  4284. srb.CdbLength = 10;
  4285. //
  4286. // Set timeout value.
  4287. //
  4288. srb.TimeOutValue = AUDIO_TIMEOUT;
  4289. status = SendSrbSynchronous(deviceExtension,
  4290. &srb,
  4291. NULL,
  4292. 0);
  4293. if (NT_SUCCESS(status) &&
  4294. cdb->PLAY_AUDIO_MSF.OperationCode == SCSIOP_PLAY_AUDIO_MSF) {
  4295. deviceExtension->PlayActive = TRUE;
  4296. }
  4297. }
  4298. break;
  4299. case IOCTL_CDROM_SEEK_AUDIO_MSF:
  4300. {
  4301. PCDROM_SEEK_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
  4302. CdDump(( 3,
  4303. "535DeviceControl => IOCTL_CDROM_SEEK_AUDIO_MSF recv'd.\n"
  4304. ));
  4305. Irp->IoStatus.Information = 0;
  4306. if (currentIrpStack->Parameters.DeviceIoControl.InputBufferLength <
  4307. sizeof(CDROM_SEEK_AUDIO_MSF)
  4308. ) {
  4309. status = STATUS_INFO_LENGTH_MISMATCH;
  4310. break;
  4311. }
  4312. //
  4313. // Use the data seek command to move the pickup
  4314. // NOTE: This blithely assumes logical block size == 2048 bytes.
  4315. //
  4316. destblock = ((((ULONG)(inputBuffer->M) * 60)
  4317. + (ULONG)(inputBuffer->S)) * 75)
  4318. + (ULONG)(inputBuffer->F)
  4319. - 150;
  4320. srb.CdbLength = 10;
  4321. srb.TimeOutValue = AUDIO_TIMEOUT;
  4322. cdb->SEEK.OperationCode = SCSIOP_SEEK;
  4323. cdb->SEEK.LogicalBlockAddress[0] = (UCHAR)(destblock >> 24) & 0xFF;
  4324. cdb->SEEK.LogicalBlockAddress[1] = (UCHAR)(destblock >> 16) & 0xFF;
  4325. cdb->SEEK.LogicalBlockAddress[2] = (UCHAR)(destblock >> 8) & 0xFF;
  4326. cdb->SEEK.LogicalBlockAddress[3] = (UCHAR)(destblock & 0xFF);
  4327. status = SendSrbSynchronous( deviceExtension,
  4328. &srb,
  4329. NULL,
  4330. 0
  4331. );
  4332. if (!NT_SUCCESS(status)) {
  4333. CdDump(( 3,
  4334. "535DeviceControl => SEEK failed (%lx)\n",
  4335. status ));
  4336. }
  4337. }
  4338. break;
  4339. case IOCTL_CDROM_EJECT_MEDIA:
  4340. //
  4341. // Build cdb to eject cartridge
  4342. //
  4343. CdDump(( 3,
  4344. "535DeviceControl => IOCTL_CDROM_EJECT_MEDIA recv'd.\n"
  4345. ));
  4346. Irp->IoStatus.Information = 0;
  4347. deviceExtension->PlayActive = FALSE;
  4348. srb.CdbLength = 10;
  4349. srb.TimeOutValue = AUDIO_TIMEOUT;
  4350. cdb->CDB10.OperationCode = CDS535_EJECT_CODE;
  4351. status = SendSrbSynchronous( deviceExtension,
  4352. &srb,
  4353. NULL,
  4354. 0
  4355. );
  4356. break;
  4357. case IOCTL_CDROM_GET_CONTROL:
  4358. case IOCTL_CDROM_GET_VOLUME:
  4359. case IOCTL_CDROM_SET_VOLUME:
  4360. CdDump(( 3, "535DeviceControl => Not Supported yet.\n" ));
  4361. Irp->IoStatus.Information = 0;
  4362. status = STATUS_INVALID_DEVICE_REQUEST;
  4363. break;
  4364. case IOCTL_CDROM_CHECK_VERIFY:
  4365. //
  4366. // Update the play active flag.
  4367. //
  4368. CdAudioIsPlayActive(DeviceObject);
  4369. default:
  4370. CdDump((10,"535DeviceControl => Unsupported device IOCTL\n"));
  4371. return CdAudioSendToNextDriver( DeviceObject, Irp );
  4372. break;
  4373. } // end switch( IOCTL )
  4374. SetStatusAndReturn:
  4375. //
  4376. // set status code and return
  4377. //
  4378. if (status == STATUS_VERIFY_REQUIRED) {
  4379. IoSetHardErrorOrVerifyDevice( Irp,
  4380. deviceExtension->TargetDeviceObject
  4381. );
  4382. Irp->IoStatus.Information = 0;
  4383. }
  4384. Irp->IoStatus.Status = status;
  4385. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  4386. return status;
  4387. }
  4388. NTSTATUS
  4389. CdAudio435DeviceControl(
  4390. PDEVICE_OBJECT DeviceObject,
  4391. PIRP Irp
  4392. )
  4393. /*++
  4394. Routine Description:
  4395. This routine is called by CdAudioDeviceControl to handle
  4396. audio IOCTLs sent to Chinon CDS-435 cdrom drive.
  4397. Arguments:
  4398. DeviceObject
  4399. Irp
  4400. Return Value:
  4401. NTSTATUS
  4402. --*/
  4403. {
  4404. PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
  4405. PCD_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  4406. PCDROM_TOC cdaudioDataOut = Irp->AssociatedIrp.SystemBuffer;
  4407. SCSI_PASS_THROUGH srb;
  4408. PCDB cdb = (PCDB)srb.Cdb;
  4409. NTSTATUS status;
  4410. ULONG i,bytesTransfered;
  4411. PUCHAR Toc;
  4412. //
  4413. // Clear out cdb
  4414. //
  4415. RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
  4416. //
  4417. // What IOCTL do we need to execute?
  4418. //
  4419. switch (currentIrpStack->Parameters.DeviceIoControl.IoControlCode) {
  4420. case IOCTL_CDROM_READ_TOC:
  4421. CdDump(( 3,
  4422. "435DeviceControl => IOCTL_CDROM_READ_TOC recv'd.\n"
  4423. ));
  4424. //
  4425. // Must have allocated at least enough buffer space
  4426. // to store how many tracks are on the disc
  4427. //
  4428. if (currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength <
  4429. ((ULONG)FIELD_OFFSET(CDROM_TOC, TrackData[0]))
  4430. ) {
  4431. status = STATUS_BUFFER_TOO_SMALL;
  4432. Irp->IoStatus.Information = 0;
  4433. break;
  4434. }
  4435. //
  4436. // If the cd is playing music then reject this request.
  4437. //
  4438. if (CdAudioIsPlayActive(DeviceObject)) {
  4439. status = STATUS_DEVICE_BUSY;
  4440. Irp->IoStatus.Information = 0;
  4441. break;
  4442. }
  4443. //
  4444. // Allocate storage to hold TOC from disc
  4445. //
  4446. Toc = (PUCHAR)ExAllocatePool( NonPagedPoolCacheAligned,
  4447. CDROM_TOC_SIZE
  4448. );
  4449. if (Toc==NULL) {
  4450. status = STATUS_INSUFFICIENT_RESOURCES;
  4451. Irp->IoStatus.Information = 0;
  4452. goto SetStatusAndReturn;
  4453. }
  4454. //
  4455. // Set up defaults
  4456. //
  4457. RtlZeroMemory( Toc, CDROM_TOC_SIZE );
  4458. //
  4459. // Fill in cdb for this operation
  4460. //
  4461. cdb->READ_TOC.OperationCode = CDS435_READ_TOC_CODE;
  4462. cdb->READ_TOC.Msf = 1;
  4463. cdb->READ_TOC.AllocationLength[0] = (CDROM_TOC_SIZE >> 8);
  4464. cdb->READ_TOC.AllocationLength[1] = (CDROM_TOC_SIZE & 0xFF);
  4465. srb.TimeOutValue = AUDIO_TIMEOUT;
  4466. srb.CdbLength = 10;
  4467. status = SendSrbSynchronous( deviceExtension,
  4468. &srb,
  4469. Toc,
  4470. CDROM_TOC_SIZE
  4471. );
  4472. if (!NT_SUCCESS(status) && (status!=STATUS_DATA_OVERRUN)) {
  4473. CdDump(( 1,
  4474. "435DeviceControl => READ_TOC error (%lx)\n",
  4475. status ));
  4476. if (status != STATUS_DATA_OVERRUN) {
  4477. CdDump(( 1, "435DeviceControl => SRB ERROR (%lx)\n",
  4478. status ));
  4479. ExFreePool( Toc );
  4480. Irp->IoStatus.Information = 0;
  4481. goto SetStatusAndReturn;
  4482. }
  4483. } else {
  4484. status = STATUS_SUCCESS;
  4485. }
  4486. //
  4487. // Translate data into SCSI-II format
  4488. // (track numbers, except 0xAA, must be converted from BCD)
  4489. bytesTransfered =
  4490. currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength >
  4491. sizeof(CDROM_TOC) ?
  4492. sizeof(CDROM_TOC) :
  4493. currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
  4494. cdaudioDataOut->Length[0] = Toc[0];
  4495. cdaudioDataOut->Length[1] = Toc[1];
  4496. cdaudioDataOut->FirstTrack = BCD_TO_DEC(Toc[2]);
  4497. cdaudioDataOut->LastTrack = BCD_TO_DEC(Toc[3]);
  4498. //
  4499. // Return only N number of tracks, where N is the number of
  4500. // full tracks of info we can stuff into the user buffer
  4501. // if tracks from 1 to 2, that means there are two tracks,
  4502. // so let i go from 0 to 1 (two tracks of info)
  4503. //
  4504. {
  4505. //
  4506. // tracksToReturn == Number of real track info to return
  4507. // tracksInBuffer == How many fit into the user-supplied buffer
  4508. // tracksOnCd == Number of tracks on the CD (not including lead-out)
  4509. //
  4510. ULONG tracksToReturn;
  4511. ULONG tracksOnCd;
  4512. ULONG tracksInBuffer;
  4513. tracksOnCd = (cdaudioDataOut->LastTrack - cdaudioDataOut->FirstTrack) + 1;
  4514. tracksInBuffer = currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength -
  4515. ((ULONG)FIELD_OFFSET(CDROM_TOC, TrackData[0]));
  4516. tracksInBuffer /= sizeof(TRACK_DATA);
  4517. // take the lesser of the two
  4518. tracksToReturn = (tracksInBuffer < tracksOnCd) ?
  4519. tracksInBuffer :
  4520. tracksOnCd;
  4521. for( i=0; i < tracksToReturn; i++ ) {
  4522. //
  4523. // Grab Information for each track
  4524. //
  4525. cdaudioDataOut->TrackData[i].Reserved = 0;
  4526. cdaudioDataOut->TrackData[i].Control = Toc[(i*8)+4+1];
  4527. cdaudioDataOut->TrackData[i].TrackNumber =
  4528. BCD_TO_DEC(Toc[(i*8)+4+2]);
  4529. cdaudioDataOut->TrackData[i].Reserved1 = 0;
  4530. cdaudioDataOut->TrackData[i].Address[0] = 0;
  4531. cdaudioDataOut->TrackData[i].Address[1] = Toc[(i*8)+4+5];
  4532. cdaudioDataOut->TrackData[i].Address[2] = Toc[(i*8)+4+6];
  4533. cdaudioDataOut->TrackData[i].Address[3] = Toc[(i*8)+4+7];
  4534. CdDump(( 4,
  4535. "CdAudio435DeviceControl: Track %d %d:%d:%d\n",
  4536. cdaudioDataOut->TrackData[i].TrackNumber,
  4537. cdaudioDataOut->TrackData[i].Address[1],
  4538. cdaudioDataOut->TrackData[i].Address[2],
  4539. cdaudioDataOut->TrackData[i].Address[3]
  4540. ));
  4541. }
  4542. //
  4543. // Fake "lead out track" info
  4544. // Only if all tracks have been copied...
  4545. //
  4546. if ( tracksInBuffer > tracksOnCd ) {
  4547. cdaudioDataOut->TrackData[i].Reserved = 0;
  4548. cdaudioDataOut->TrackData[i].Control = Toc[(i*8)+4+1];
  4549. cdaudioDataOut->TrackData[i].TrackNumber = Toc[(i*8)+4+2]; // leave as 0xAA
  4550. cdaudioDataOut->TrackData[i].Reserved1 = 0;
  4551. cdaudioDataOut->TrackData[i].Address[0] = 0;
  4552. cdaudioDataOut->TrackData[i].Address[1] = Toc[(i*8)+4+5];
  4553. cdaudioDataOut->TrackData[i].Address[2] = Toc[(i*8)+4+6];
  4554. cdaudioDataOut->TrackData[i].Address[3] = Toc[(i*8)+4+7];
  4555. CdDump(( 4,
  4556. "CdAudio435DeviceControl: Track %d %d:%d:%d\n",
  4557. cdaudioDataOut->TrackData[i].TrackNumber,
  4558. cdaudioDataOut->TrackData[i].Address[1],
  4559. cdaudioDataOut->TrackData[i].Address[2],
  4560. cdaudioDataOut->TrackData[i].Address[3]
  4561. ));
  4562. i++;
  4563. }
  4564. Irp->IoStatus.Information = ((ULONG)FIELD_OFFSET(CDROM_TOC, TrackData[i]));
  4565. }
  4566. //
  4567. // Clear out deviceExtension data
  4568. //
  4569. deviceExtension->Paused = CDAUDIO_NOT_PAUSED;
  4570. deviceExtension->PausedM = 0;
  4571. deviceExtension->PausedS = 0;
  4572. deviceExtension->PausedF = 0;
  4573. deviceExtension->LastEndM = 0;
  4574. deviceExtension->LastEndS = 0;
  4575. deviceExtension->LastEndF = 0;
  4576. //
  4577. // Free storage now that we've stored it elsewhere
  4578. //
  4579. ExFreePool( Toc );
  4580. break;
  4581. case IOCTL_CDROM_PLAY_AUDIO_MSF:
  4582. case IOCTL_CDROM_STOP_AUDIO:
  4583. {
  4584. PCDROM_PLAY_AUDIO_MSF inputBuffer =
  4585. Irp->AssociatedIrp.SystemBuffer;
  4586. Irp->IoStatus.Information = 0;
  4587. srb.CdbLength = 10;
  4588. srb.TimeOutValue = AUDIO_TIMEOUT;
  4589. cdb->CDB10.OperationCode = CDS435_STOP_AUDIO_CODE;
  4590. status = SendSrbSynchronous( deviceExtension,
  4591. &srb,
  4592. NULL,
  4593. 0
  4594. );
  4595. if (NT_SUCCESS(status)) {
  4596. deviceExtension->PlayActive = FALSE;
  4597. deviceExtension->Paused = CDAUDIO_NOT_PAUSED;
  4598. deviceExtension->PausedM = 0;
  4599. deviceExtension->PausedS = 0;
  4600. deviceExtension->PausedF = 0;
  4601. deviceExtension->LastEndM = 0;
  4602. deviceExtension->LastEndS = 0;
  4603. deviceExtension->LastEndF = 0;
  4604. } else {
  4605. CdDump(( 3,
  4606. "435DeviceControl => STOP failed (%lx)\n",
  4607. status ));
  4608. }
  4609. if (currentIrpStack->Parameters.DeviceIoControl.IoControlCode ==
  4610. IOCTL_CDROM_STOP_AUDIO
  4611. ) {
  4612. CdDump(( 3,
  4613. "435DeviceControl => IOCTL_CDROM_STOP_AUDIO recv'd.\n"
  4614. ));
  4615. goto SetStatusAndReturn;
  4616. }
  4617. CdDump(( 3,
  4618. "435DeviceControl => IOCTL_CDROM_PLAY_AUDIO_MSF recv'd.\n"
  4619. ));
  4620. if (currentIrpStack->Parameters.DeviceIoControl.InputBufferLength <
  4621. sizeof(CDROM_PLAY_AUDIO_MSF)
  4622. ) {
  4623. status = STATUS_INFO_LENGTH_MISMATCH;
  4624. break;
  4625. }
  4626. //
  4627. // Fill in cdb for this operation
  4628. //
  4629. srb.CdbLength = 10;
  4630. srb.TimeOutValue = AUDIO_TIMEOUT;
  4631. cdb->PLAY_AUDIO_MSF.OperationCode =
  4632. CDS435_PLAY_AUDIO_EXTENDED_CODE;
  4633. cdb->PLAY_AUDIO_MSF.StartingM = inputBuffer->StartingM;
  4634. cdb->PLAY_AUDIO_MSF.StartingS = inputBuffer->StartingS;
  4635. cdb->PLAY_AUDIO_MSF.StartingF = inputBuffer->StartingF;
  4636. cdb->PLAY_AUDIO_MSF.EndingM = inputBuffer->EndingM;
  4637. cdb->PLAY_AUDIO_MSF.EndingS = inputBuffer->EndingS;
  4638. cdb->PLAY_AUDIO_MSF.EndingF = inputBuffer->EndingF;
  4639. status = SendSrbSynchronous( deviceExtension,
  4640. &srb,
  4641. NULL,
  4642. 0
  4643. );
  4644. if (NT_SUCCESS(status)) {
  4645. deviceExtension->PlayActive = TRUE;
  4646. deviceExtension->Paused = CDAUDIO_NOT_PAUSED;
  4647. //
  4648. // Set last play ending address for next pause command
  4649. //
  4650. deviceExtension->LastEndM = inputBuffer->EndingM;
  4651. deviceExtension->LastEndS = inputBuffer->EndingS;
  4652. deviceExtension->LastEndF = inputBuffer->EndingF;
  4653. CdDump(( 3,
  4654. "435DeviceControl => PLAY ==> BcdLastEnd set to (%x %x %x)\n",
  4655. deviceExtension->LastEndM,
  4656. deviceExtension->LastEndS,
  4657. deviceExtension->LastEndF ));
  4658. } else {
  4659. CdDump(( 3,
  4660. "435DeviceControl => PLAY failed (%lx)\n",
  4661. status ));
  4662. }
  4663. }
  4664. break;
  4665. case IOCTL_CDROM_SEEK_AUDIO_MSF:
  4666. {
  4667. PCDROM_SEEK_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
  4668. Irp->IoStatus.Information = 0;
  4669. CdDump(( 3,
  4670. "435DeviceControl => IOCTL_CDROM_SEEK_AUDIO_MSF recv'd.\n"
  4671. ));
  4672. if (currentIrpStack->Parameters.DeviceIoControl.InputBufferLength <
  4673. sizeof(CDROM_SEEK_AUDIO_MSF)
  4674. ) {
  4675. status = STATUS_INFO_LENGTH_MISMATCH;
  4676. break;
  4677. }
  4678. //
  4679. // Fill in cdb for this operation
  4680. //
  4681. srb.CdbLength = 10;
  4682. srb.TimeOutValue = AUDIO_TIMEOUT;
  4683. cdb->CDB10.OperationCode = CDS435_PLAY_AUDIO_EXTENDED_CODE;
  4684. cdb->PLAY_AUDIO_MSF.StartingM = inputBuffer->M;
  4685. cdb->PLAY_AUDIO_MSF.StartingS = inputBuffer->S;
  4686. cdb->PLAY_AUDIO_MSF.StartingF = inputBuffer->F;
  4687. cdb->PLAY_AUDIO_MSF.EndingM = inputBuffer->M;
  4688. cdb->PLAY_AUDIO_MSF.EndingS = inputBuffer->S;
  4689. cdb->PLAY_AUDIO_MSF.EndingF = inputBuffer->F;
  4690. status = SendSrbSynchronous( deviceExtension,
  4691. &srb,
  4692. NULL,
  4693. 0
  4694. );
  4695. if (NT_SUCCESS(status)) {
  4696. deviceExtension->Paused = CDAUDIO_PAUSED;
  4697. deviceExtension->PausedM = inputBuffer->M;
  4698. deviceExtension->PausedS = inputBuffer->S;
  4699. deviceExtension->PausedF = inputBuffer->F;
  4700. deviceExtension->LastEndM = inputBuffer->M;
  4701. deviceExtension->LastEndS = inputBuffer->S;
  4702. deviceExtension->LastEndF = inputBuffer->F;
  4703. CdDump(( 3,
  4704. "435DeviceControl => SEEK, Paused (%x %x %x) LastEnd (%x %x %x)\n",
  4705. deviceExtension->PausedM,
  4706. deviceExtension->PausedS,
  4707. deviceExtension->PausedF,
  4708. deviceExtension->LastEndM,
  4709. deviceExtension->LastEndS,
  4710. deviceExtension->LastEndF ));
  4711. } else {
  4712. CdDump(( 3,
  4713. "435DeviceControl => SEEK failed (%lx)\n",
  4714. status ));
  4715. //
  4716. // The CDS-435 drive returns STATUS_INVALID_DEVICE_REQUEST
  4717. // when we ask to play an invalid address, so we need
  4718. // to map to STATUS_NONEXISTENT_SECTOR in order to be
  4719. // consistent with the other drives.
  4720. //
  4721. if (status==STATUS_INVALID_DEVICE_REQUEST) {
  4722. status = STATUS_NONEXISTENT_SECTOR;
  4723. }
  4724. }
  4725. }
  4726. break;
  4727. case IOCTL_CDROM_PAUSE_AUDIO:
  4728. {
  4729. PUCHAR SubQPtr =
  4730. ExAllocatePool( NonPagedPoolCacheAligned,
  4731. sizeof(SUB_Q_CHANNEL_DATA)
  4732. );
  4733. Irp->IoStatus.Information = 0;
  4734. CdDump(( 3,
  4735. "435DeviceControl => IOCTL_CDROM_PAUSE_AUDIO recv'd.\n"
  4736. ));
  4737. if (SubQPtr==NULL) {
  4738. status = STATUS_INSUFFICIENT_RESOURCES;
  4739. goto SetStatusAndReturn;
  4740. }
  4741. //
  4742. // Enter pause (still ) mode
  4743. //
  4744. if (deviceExtension->Paused==CDAUDIO_PAUSED) {
  4745. CdDump(( 3,
  4746. "435DeviceControl => PAUSE: Already Paused!\n"
  4747. ));
  4748. ExFreePool( SubQPtr );
  4749. status = STATUS_SUCCESS;
  4750. goto SetStatusAndReturn;
  4751. }
  4752. //
  4753. // Since the CDS-435 doesn't have a pause mode,
  4754. // we'll just record the current position and
  4755. // stop the drive.
  4756. //
  4757. srb.CdbLength = 10;
  4758. srb.TimeOutValue = AUDIO_TIMEOUT;
  4759. cdb->SUBCHANNEL.OperationCode = CDS435_READ_SUB_Q_CHANNEL_CODE;
  4760. cdb->SUBCHANNEL.Msf = 1;
  4761. cdb->SUBCHANNEL.SubQ = 1;
  4762. cdb->SUBCHANNEL.AllocationLength[1] = sizeof(SUB_Q_CHANNEL_DATA);
  4763. status = SendSrbSynchronous( deviceExtension,
  4764. &srb,
  4765. SubQPtr,
  4766. sizeof(SUB_Q_CHANNEL_DATA)
  4767. );
  4768. if (!NT_SUCCESS(status)) {
  4769. CdDump(( 1,
  4770. "435DeviceControl => Pause, Read Q Channel failed (%lx)\n",
  4771. status ));
  4772. ExFreePool( SubQPtr );
  4773. goto SetStatusAndReturn;
  4774. }
  4775. deviceExtension->PausedM = SubQPtr[9];
  4776. deviceExtension->PausedS = SubQPtr[10];
  4777. deviceExtension->PausedF = SubQPtr[11];
  4778. //
  4779. // now stop audio
  4780. //
  4781. RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
  4782. srb.CdbLength = 10;
  4783. srb.TimeOutValue = AUDIO_TIMEOUT;
  4784. cdb->CDB10.OperationCode = CDS435_STOP_AUDIO_CODE;
  4785. status = SendSrbSynchronous( deviceExtension,
  4786. &srb,
  4787. NULL,
  4788. 0
  4789. );
  4790. if (!NT_SUCCESS(status)) {
  4791. CdDump(( 1,
  4792. "435DeviceControl => PAUSE, StopAudio failed! (%lx)\n",
  4793. status ));
  4794. ExFreePool( SubQPtr );
  4795. goto SetStatusAndReturn;
  4796. }
  4797. deviceExtension->PlayActive = FALSE;
  4798. deviceExtension->Paused = CDAUDIO_PAUSED;
  4799. deviceExtension->PausedM = SubQPtr[9];
  4800. deviceExtension->PausedS = SubQPtr[10];
  4801. deviceExtension->PausedF = SubQPtr[11];
  4802. CdDump((3,
  4803. "435DeviceControl => PAUSE ==> Paused set to (%x %x %x)\n",
  4804. deviceExtension->PausedM,
  4805. deviceExtension->PausedS,
  4806. deviceExtension->PausedF ));
  4807. ExFreePool( SubQPtr );
  4808. }
  4809. break;
  4810. case IOCTL_CDROM_RESUME_AUDIO:
  4811. //
  4812. // Resume cdrom
  4813. //
  4814. CdDump(( 3,
  4815. "435DeviceControl => IOCTL_CDROM_RESUME_AUDIO recv'd.\n"
  4816. ));
  4817. Irp->IoStatus.Information = 0;
  4818. //
  4819. // Since the CDS-435 doesn't have a resume IOCTL,
  4820. // we'll just start playing (if paused) from the
  4821. // last recored paused position to the last recorded
  4822. // "end of play" position.
  4823. //
  4824. if (deviceExtension->Paused==CDAUDIO_NOT_PAUSED) {
  4825. status = STATUS_UNSUCCESSFUL;
  4826. goto SetStatusAndReturn;
  4827. }
  4828. //
  4829. // Fill in cdb for this operation
  4830. //
  4831. srb.CdbLength = 10;
  4832. srb.TimeOutValue = AUDIO_TIMEOUT;
  4833. cdb->PLAY_AUDIO_MSF.OperationCode = CDS435_PLAY_AUDIO_EXTENDED_CODE;
  4834. cdb->PLAY_AUDIO_MSF.StartingM = deviceExtension->PausedM;
  4835. cdb->PLAY_AUDIO_MSF.StartingS = deviceExtension->PausedS;
  4836. cdb->PLAY_AUDIO_MSF.StartingF = deviceExtension->PausedF;
  4837. cdb->PLAY_AUDIO_MSF.EndingM = deviceExtension->LastEndM;
  4838. cdb->PLAY_AUDIO_MSF.EndingS = deviceExtension->LastEndS;
  4839. cdb->PLAY_AUDIO_MSF.EndingF = deviceExtension->LastEndF;
  4840. status = SendSrbSynchronous( deviceExtension,
  4841. &srb,
  4842. NULL,
  4843. 0
  4844. );
  4845. if (NT_SUCCESS(status)) {
  4846. deviceExtension->PlayActive = TRUE;
  4847. deviceExtension->Paused = CDAUDIO_NOT_PAUSED;
  4848. } else {
  4849. CdDump(( 1,
  4850. "435DeviceControl => RESUME (%x %x %x) - (%x %x %x) failed (%lx)\n",
  4851. deviceExtension->PausedM,
  4852. deviceExtension->PausedS,
  4853. deviceExtension->PausedF,
  4854. deviceExtension->LastEndM,
  4855. deviceExtension->LastEndS,
  4856. deviceExtension->LastEndF,
  4857. status ));
  4858. }
  4859. break;
  4860. case IOCTL_CDROM_READ_Q_CHANNEL:
  4861. {
  4862. PSUB_Q_CURRENT_POSITION userPtr =
  4863. Irp->AssociatedIrp.SystemBuffer;
  4864. PUCHAR SubQPtr =
  4865. ExAllocatePool( NonPagedPoolCacheAligned,
  4866. sizeof(SUB_Q_CHANNEL_DATA)
  4867. );
  4868. if (currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength <
  4869. sizeof(SUB_Q_CURRENT_POSITION)
  4870. ) {
  4871. status = STATUS_BUFFER_TOO_SMALL;
  4872. Irp->IoStatus.Information = 0;
  4873. if (SubQPtr) ExFreePool(SubQPtr);
  4874. break;
  4875. }
  4876. CdDump(( 5,
  4877. "435DeviceControl => IOCTL_CDROM_READ_Q_CHANNEL recv'd.\n"
  4878. ));
  4879. if (SubQPtr==NULL) {
  4880. CdDump(( 1,
  4881. "435DeviceControl => READ_Q_CHANNEL, SubQPtr==NULL!\n"
  4882. ));
  4883. RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
  4884. status = STATUS_INSUFFICIENT_RESOURCES;
  4885. Irp->IoStatus.Information = 0;
  4886. goto SetStatusAndReturn;
  4887. }
  4888. if ( ((PCDROM_SUB_Q_DATA_FORMAT)userPtr)->Format!=
  4889. IOCTL_CDROM_CURRENT_POSITION) {
  4890. CdDump(( 1,
  4891. "435DeviceControl => READ_Q_CHANNEL, illegal Format (%d)\n",
  4892. ((PCDROM_SUB_Q_DATA_FORMAT)userPtr)->Format
  4893. ));
  4894. ExFreePool( SubQPtr );
  4895. RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
  4896. status = STATUS_UNSUCCESSFUL;
  4897. Irp->IoStatus.Information = 0;
  4898. goto SetStatusAndReturn;
  4899. }
  4900. //
  4901. // Read audio play status
  4902. //
  4903. srb.CdbLength = 10;
  4904. srb.TimeOutValue = AUDIO_TIMEOUT;
  4905. cdb->SUBCHANNEL.OperationCode = CDS435_READ_SUB_Q_CHANNEL_CODE;
  4906. cdb->SUBCHANNEL.Msf = 1;
  4907. cdb->SUBCHANNEL.SubQ = 1;
  4908. cdb->SUBCHANNEL.AllocationLength[1] = sizeof(SUB_Q_CHANNEL_DATA);
  4909. status = SendSrbSynchronous( deviceExtension,
  4910. &srb,
  4911. SubQPtr,
  4912. sizeof(SUB_Q_CHANNEL_DATA)
  4913. );
  4914. if (NT_SUCCESS(status)) {
  4915. userPtr->Header.Reserved = 0;
  4916. if (deviceExtension->Paused==CDAUDIO_PAUSED) {
  4917. deviceExtension->PlayActive = FALSE;
  4918. userPtr->Header.AudioStatus = AUDIO_STATUS_PAUSED;
  4919. } else {
  4920. if (SubQPtr[1] == 0x11) {
  4921. deviceExtension->PlayActive = TRUE;
  4922. userPtr->Header.AudioStatus = AUDIO_STATUS_IN_PROGRESS;
  4923. } else {
  4924. deviceExtension->PlayActive = FALSE;
  4925. userPtr->Header.AudioStatus = AUDIO_STATUS_PLAY_COMPLETE;
  4926. }
  4927. }
  4928. userPtr->Header.DataLength[0] = 0;
  4929. userPtr->Header.DataLength[1] = 12;
  4930. userPtr->FormatCode = 0x01;
  4931. userPtr->Control = SubQPtr[5];
  4932. userPtr->ADR = 0;
  4933. userPtr->TrackNumber = BCD_TO_DEC(SubQPtr[6]);
  4934. userPtr->IndexNumber = BCD_TO_DEC(SubQPtr[7]);
  4935. userPtr->AbsoluteAddress[0] = 0;
  4936. userPtr->AbsoluteAddress[1] = SubQPtr[9];
  4937. userPtr->AbsoluteAddress[2] = SubQPtr[10];
  4938. userPtr->AbsoluteAddress[3] = SubQPtr[11];
  4939. userPtr->TrackRelativeAddress[0] = 0;
  4940. userPtr->TrackRelativeAddress[1] = SubQPtr[13];
  4941. userPtr->TrackRelativeAddress[2] = SubQPtr[14];
  4942. userPtr->TrackRelativeAddress[3] = SubQPtr[15];
  4943. Irp->IoStatus.Information = sizeof(SUB_Q_CURRENT_POSITION);
  4944. } else {
  4945. Irp->IoStatus.Information = 0;
  4946. CdDump(( 1,
  4947. "435DeviceControl => READ_Q_CHANNEL failed (%lx)\n",
  4948. status
  4949. ));
  4950. }
  4951. ExFreePool( SubQPtr );
  4952. }
  4953. break;
  4954. case IOCTL_CDROM_EJECT_MEDIA:
  4955. //
  4956. // Build cdb to eject cartridge
  4957. //
  4958. CdDump(( 3,
  4959. "435DeviceControl => IOCTL_CDROM_EJECT_MEDIA recv'd.\n"
  4960. ));
  4961. Irp->IoStatus.Information = 0;
  4962. srb.CdbLength = 10;
  4963. srb.TimeOutValue = AUDIO_TIMEOUT;
  4964. cdb->CDB10.OperationCode = CDS435_EJECT_CODE;
  4965. status = SendSrbSynchronous( deviceExtension,
  4966. &srb,
  4967. NULL,
  4968. 0
  4969. );
  4970. deviceExtension->Paused = CDAUDIO_NOT_PAUSED;
  4971. deviceExtension->PausedM = 0;
  4972. deviceExtension->PausedS = 0;
  4973. deviceExtension->PausedF = 0;
  4974. deviceExtension->LastEndM = 0;
  4975. deviceExtension->LastEndS = 0;
  4976. deviceExtension->LastEndF = 0;
  4977. break;
  4978. case IOCTL_CDROM_GET_CONTROL:
  4979. case IOCTL_CDROM_GET_VOLUME:
  4980. case IOCTL_CDROM_SET_VOLUME:
  4981. CdDump(( 3, "435DeviceControl => Not Supported yet.\n" ));
  4982. Irp->IoStatus.Information = 0;
  4983. status = STATUS_INVALID_DEVICE_REQUEST;
  4984. break;
  4985. case IOCTL_CDROM_CHECK_VERIFY:
  4986. CdDump(( 3, "435DeviceControl => IOCTL_CDROM_CHECK_VERIFY recv'd.\n"
  4987. ));
  4988. //
  4989. // Update the play active flag.
  4990. //
  4991. if (CdAudioIsPlayActive(DeviceObject) == TRUE) {
  4992. deviceExtension->PlayActive = TRUE;
  4993. status = STATUS_SUCCESS; // media must be in place if audio
  4994. Irp->IoStatus.Information = 0; // is playing
  4995. goto SetStatusAndReturn;
  4996. } else {
  4997. deviceExtension->PlayActive = FALSE;
  4998. return CdAudioSendToNextDriver( DeviceObject, Irp );
  4999. }
  5000. break;
  5001. default:
  5002. CdDump((10,"435DeviceControl => Unsupported device IOCTL\n"));
  5003. return CdAudioSendToNextDriver( DeviceObject, Irp );
  5004. break;
  5005. } // end switch( IOCTL )
  5006. SetStatusAndReturn:
  5007. //
  5008. // set status code and return
  5009. //
  5010. if (status == STATUS_VERIFY_REQUIRED) {
  5011. IoSetHardErrorOrVerifyDevice( Irp,
  5012. deviceExtension->TargetDeviceObject
  5013. );
  5014. Irp->IoStatus.Information = 0;
  5015. }
  5016. Irp->IoStatus.Status = status;
  5017. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  5018. return status;
  5019. }
  5020. NTSTATUS
  5021. CdAudioAtapiDeviceControl(
  5022. IN PDEVICE_OBJECT DeviceObject,
  5023. IN PIRP Irp
  5024. )
  5025. {
  5026. NTSTATUS status;
  5027. PCD_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  5028. PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
  5029. SCSI_PASS_THROUGH srb;
  5030. PHITACHICDB cdb = (PHITACHICDB)srb.Cdb;
  5031. CdDump ((3,"AtapiDeviceControl => IoControl %x.\n",
  5032. currentIrpStack->Parameters.DeviceIoControl.IoControlCode));
  5033. //
  5034. // The Atapi devices supported only need remapping of IOCTL_CDROM_STOP_AUDIO
  5035. //
  5036. if (currentIrpStack->Parameters.DeviceIoControl.IoControlCode ==
  5037. IOCTL_CDROM_STOP_AUDIO
  5038. ) {
  5039. Irp->IoStatus.Information = 0;
  5040. deviceExtension->PlayActive = FALSE;
  5041. //
  5042. // Zero and fill in new Srb
  5043. //
  5044. RtlZeroMemory(&srb, sizeof(SCSI_PASS_THROUGH));
  5045. //
  5046. // Issue the Atapi STOP_PLAY command.
  5047. //
  5048. cdb->STOP_PLAY.OperationCode = 0x4E;
  5049. srb.CdbLength = 12;
  5050. //
  5051. // Set timeout value.
  5052. //
  5053. srb.TimeOutValue = AUDIO_TIMEOUT;
  5054. status = SendSrbSynchronous(deviceExtension,
  5055. &srb,
  5056. NULL,
  5057. 0);
  5058. if (!NT_SUCCESS(status)) {
  5059. CdDump(( 1,
  5060. "AtapiDeviceControl => STOP_AUDIO error (%lx)\n",
  5061. status ));
  5062. Irp->IoStatus.Status = status;
  5063. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  5064. return status;
  5065. }
  5066. } else {
  5067. return CdAudioSendToNextDriver( DeviceObject, Irp );
  5068. }
  5069. Irp->IoStatus.Status = status;
  5070. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  5071. return status;
  5072. }
  5073. VOID
  5074. HpCdrProcessLastSession(
  5075. IN PCDROM_TOC Toc
  5076. )
  5077. /*++
  5078. Routine Description:
  5079. This routine fixes up the multi session table of contents when the
  5080. session data is returned for HP CDR 4020i drives.
  5081. Arguments:
  5082. Toc - the table of contents buffer returned from the drive.
  5083. Return Value:
  5084. None
  5085. --*/
  5086. {
  5087. ULONG index;
  5088. PUCHAR cp;
  5089. index = Toc->FirstTrack;
  5090. if (index) {
  5091. index--;
  5092. //
  5093. // Fix up the TOC information from the HP method to how it is
  5094. // interpreted by the file systems.
  5095. //
  5096. Toc->FirstTrack = Toc->TrackData[0].Reserved;
  5097. Toc->LastTrack = Toc->TrackData[index].Reserved;
  5098. Toc->TrackData[0] = Toc->TrackData[index];
  5099. } else {
  5100. Toc->FirstTrack = Toc->LastTrack = 0;
  5101. }
  5102. CdDump((2, "HP TOC data for last session\n"));
  5103. for (cp = (PUCHAR) Toc, index = 0; index < 12; index++, cp++) {
  5104. CdDump((2, "%2x ", *cp));
  5105. }
  5106. CdDump((2, "\n"));
  5107. }
  5108. NTSTATUS
  5109. HPCdrCompletion(
  5110. IN PDEVICE_OBJECT DeviceObject,
  5111. IN PIRP Irp,
  5112. IN PVOID Context
  5113. )
  5114. /*++
  5115. Routine Description:
  5116. This routine is called when the I/O request has completed.
  5117. Arguments:
  5118. DeviceObject - SimBad device object.
  5119. Irp - Completed request.
  5120. Context - not used. Set up to also be a pointer to the DeviceObject.
  5121. Return Value:
  5122. NTSTATUS
  5123. --*/
  5124. {
  5125. UNREFERENCED_PARAMETER(Context);
  5126. UNREFERENCED_PARAMETER(DeviceObject);
  5127. if (Irp->PendingReturned) {
  5128. IoMarkIrpPending( Irp );
  5129. }
  5130. if (NT_SUCCESS(Irp->IoStatus.Status)) {
  5131. HpCdrProcessLastSession((PCDROM_TOC)Irp->AssociatedIrp.SystemBuffer);
  5132. }
  5133. return Irp->IoStatus.Status;
  5134. }
  5135. NTSTATUS
  5136. CdAudioHPCdrDeviceControl(
  5137. PDEVICE_OBJECT DeviceObject,
  5138. PIRP Irp
  5139. )
  5140. /*++
  5141. Routine Description:
  5142. This routine is called by CdAudioDeviceControl to handle
  5143. audio IOCTLs sent to the HPCdr device - this specifically handles
  5144. session data for multi session support.
  5145. Arguments:
  5146. DeviceObject
  5147. Irp
  5148. Return Value:
  5149. NTSTATUS
  5150. --*/
  5151. {
  5152. PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
  5153. PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
  5154. PCD_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  5155. //
  5156. // Is this a GET_LAST_SESSION request
  5157. //
  5158. if (currentIrpStack->Parameters.DeviceIoControl.IoControlCode ==
  5159. IOCTL_CDROM_GET_LAST_SESSION
  5160. ) {
  5161. //
  5162. // Copy stack parameters to next stack.
  5163. //
  5164. IoCopyCurrentIrpStackLocationToNext( Irp );
  5165. //
  5166. // Set IRP so IoComplete calls our completion routine.
  5167. //
  5168. IoSetCompletionRoutine(Irp,
  5169. HPCdrCompletion,
  5170. deviceExtension,
  5171. TRUE,
  5172. TRUE,
  5173. TRUE);
  5174. //
  5175. // Send this to next driver layer and process on completion.
  5176. //
  5177. return IoCallDriver(deviceExtension->TargetDeviceObject, Irp);
  5178. } else {
  5179. return CdAudioSendToNextDriver( DeviceObject, Irp );
  5180. }
  5181. //
  5182. // Cannot get here
  5183. //
  5184. return STATUS_UNSUCCESSFUL;
  5185. }
  5186. NTSTATUS
  5187. CdAudioForwardIrpSynchronous(
  5188. IN PDEVICE_OBJECT DeviceObject,
  5189. IN PIRP Irp
  5190. )
  5191. /*++
  5192. Routine Description:
  5193. This routine sends the Irp to the next driver in line
  5194. when the Irp needs to be processed by the lower drivers
  5195. prior to being processed by this one.
  5196. Arguments:
  5197. DeviceObject
  5198. Irp
  5199. Return Value:
  5200. NTSTATUS
  5201. --*/
  5202. {
  5203. PCD_DEVICE_EXTENSION deviceExtension;
  5204. KEVENT event;
  5205. NTSTATUS status;
  5206. KeInitializeEvent(&event, NotificationEvent, FALSE);
  5207. deviceExtension = (PCD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
  5208. //
  5209. // copy the irpstack for the next device
  5210. //
  5211. IoCopyCurrentIrpStackLocationToNext(Irp);
  5212. //
  5213. // set a completion routine
  5214. //
  5215. IoSetCompletionRoutine(Irp, CdAudioSignalCompletion,
  5216. &event, TRUE, TRUE, TRUE);
  5217. //
  5218. // call the next lower device
  5219. //
  5220. status = IoCallDriver(deviceExtension->TargetDeviceObject, Irp);
  5221. //
  5222. // wait for the actual completion
  5223. //
  5224. if (status == STATUS_PENDING) {
  5225. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  5226. status = Irp->IoStatus.Status;
  5227. }
  5228. return status;
  5229. } // end DiskPerfForwardIrpSynchronous()
  5230. VOID CdAudioUnload(
  5231. IN PDRIVER_OBJECT DriverObject
  5232. )
  5233. /*++
  5234. Routine Description:
  5235. This routine is called when the control panel "Unloads"
  5236. the CDROM device.
  5237. Arguments:
  5238. DeviceObject
  5239. Return Value:
  5240. void
  5241. --*/
  5242. {
  5243. CdDump((1,
  5244. "Unload => Unloading for DeviceObject %p\n",
  5245. DriverObject->DeviceObject
  5246. ));
  5247. ASSERT(!DriverObject->DeviceObject);
  5248. return;
  5249. }
  5250. NTSTATUS
  5251. CdAudioPower(
  5252. IN PDEVICE_OBJECT DeviceObject,
  5253. IN PIRP Irp
  5254. )
  5255. {
  5256. PCD_DEVICE_EXTENSION deviceExtension;
  5257. PoStartNextPowerIrp(Irp);
  5258. IoSkipCurrentIrpStackLocation(Irp);
  5259. deviceExtension = (PCD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
  5260. return PoCallDriver(deviceExtension->TargetDeviceObject, Irp);
  5261. }
  5262. #if DBG
  5263. #include "stdarg.h"
  5264. #define DBGHDR "[cdaudio] "
  5265. VOID
  5266. CdAudioDebugPrint(
  5267. ULONG DebugPrintLevel,
  5268. PCCHAR DebugMessage,
  5269. ...
  5270. )
  5271. /*++
  5272. Routine Description:
  5273. Debug print for CdAudio driver
  5274. Arguments:
  5275. Debug print level between 0 and 3, with 3 being the most verbose.
  5276. Return Value:
  5277. None
  5278. --*/
  5279. {
  5280. va_list ap;
  5281. va_start( ap, DebugMessage );
  5282. if (DebugPrintLevel <= CdAudioDebug) {
  5283. char buffer[128];
  5284. DbgPrint(DBGHDR);
  5285. vsprintf(buffer, DebugMessage, ap);
  5286. DbgPrint(buffer);
  5287. }
  5288. va_end(ap);
  5289. }
  5290. #endif // DBG