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