|
|
1.1 ! root 1: /*++ ! 2: ! 3: Copyright (c) 1991 Microsoft Corporation ! 4: ! 5: Module Name: ! 6: ! 7: cdrom.c ! 8: ! 9: Abstract: ! 10: ! 11: The CDROM class driver tranlates IRPs to SRBs with embedded CDBs ! 12: and sends them to its devices through the port driver. ! 13: ! 14: Author: ! 15: ! 16: Mike Glass (mglass) ! 17: ! 18: Environment: ! 19: ! 20: kernel mode only ! 21: ! 22: Notes: ! 23: ! 24: SCSI Tape, CDRom and Disk class drivers share common routines ! 25: that can be found in the CLASS directory (..\ntos\dd\class). ! 26: ! 27: Revision History: ! 28: ! 29: --*/ ! 30: ! 31: #include "ntddk.h" ! 32: #include "scsi.h" ! 33: #include "class.h" ! 34: #include "string.h" ! 35: ! 36: #define DEVICE_EXTENSION_SIZE sizeof(DEVICE_EXTENSION) + sizeof(BOOLEAN) ! 37: #define SCSI_CDROM_TIMEOUT 10 ! 38: #define HITACHI_MODE_DATA_SIZE 12 ! 39: #define MODE_DATA_SIZE 64 ! 40: ! 41: #define PLAY_ACTIVE(DeviceExtension) *((PBOOLEAN) (DeviceExtension+1)) ! 42: ! 43: ! 44: NTSTATUS ! 45: DriverEntry( ! 46: IN PDRIVER_OBJECT DriverObject, ! 47: IN PUNICODE_STRING RegistryPath ! 48: ); ! 49: ! 50: BOOLEAN ! 51: FindScsiCdRoms( ! 52: IN PDRIVER_OBJECT DriveObject, ! 53: IN PDEVICE_OBJECT PortDeviceObject, ! 54: IN UCHAR PortNumber ! 55: ); ! 56: ! 57: NTSTATUS ! 58: ScsiCdRomOpenClose( ! 59: IN PDEVICE_OBJECT DeviceObject, ! 60: IN PIRP Irp ! 61: ); ! 62: ! 63: NTSTATUS ! 64: ScsiCdRomRead( ! 65: IN PDEVICE_OBJECT DeviceObject, ! 66: IN PIRP Irp ! 67: ); ! 68: ! 69: NTSTATUS ! 70: ScsiCdRomDeviceControl( ! 71: IN PDEVICE_OBJECT DeviceObject, ! 72: IN PIRP Irp ! 73: ); ! 74: ! 75: NTSTATUS ! 76: CreateCdRomDeviceObject( ! 77: IN PDRIVER_OBJECT DriverObject, ! 78: IN PDEVICE_OBJECT PortDeviceObject, ! 79: IN UCHAR PortNumber, ! 80: IN PULONG DeviceCount, ! 81: PIO_SCSI_CAPABILITIES PortCapabilities, ! 82: IN PSCSI_INQUIRY_DATA LunInfo ! 83: ); ! 84: ! 85: NTSTATUS ! 86: GetTableOfContents( ! 87: IN PDEVICE_OBJECT DeviceObject ! 88: ); ! 89: ! 90: VOID ! 91: ScanForSpecial( ! 92: PDEVICE_OBJECT DeviceObject, ! 93: PINQUIRYDATA InquiryData, ! 94: PIO_SCSI_CAPABILITIES PortCapabilities ! 95: ); ! 96: ! 97: BOOLEAN ! 98: CdRomIsPlayActive( ! 99: IN PDEVICE_OBJECT DeviceObject ! 100: ); ! 101: ! 102: VOID ! 103: HitachProcessError( ! 104: PDEVICE_OBJECT DeviceObject, ! 105: PSCSI_REQUEST_BLOCK Srb, ! 106: NTSTATUS *Status, ! 107: BOOLEAN *Retry ! 108: ); ! 109: ! 110: #ifdef ALLOC_PRAGMA ! 111: #pragma alloc_text(init, DriverEntry) ! 112: #pragma alloc_text(init, FindScsiCdRoms) ! 113: #pragma alloc_text(init, CreateCdRomDeviceObject) ! 114: #pragma alloc_text(init, ScanForSpecial) ! 115: #endif ! 116: ! 117: ! 118: NTSTATUS ! 119: DriverEntry( ! 120: IN PDRIVER_OBJECT DriverObject, ! 121: IN PUNICODE_STRING RegistryPath ! 122: ) ! 123: ! 124: /*++ ! 125: ! 126: Routine Description: ! 127: ! 128: This routine initializes the CD-Rom class driver. The class ! 129: driver opens the port driver by name and then receives ! 130: configuration information used to attach to the CDROM devices. ! 131: ! 132: Arguments: ! 133: ! 134: DriverObject ! 135: ! 136: Return Value: ! 137: ! 138: NT Status ! 139: ! 140: --*/ ! 141: ! 142: { ! 143: UCHAR portNumber = 0; ! 144: NTSTATUS status; ! 145: PFILE_OBJECT fileObject; ! 146: PDEVICE_OBJECT portDeviceObject; ! 147: STRING deviceNameString; ! 148: CCHAR deviceNameBuffer[256]; ! 149: UNICODE_STRING unicodeDeviceName; ! 150: BOOLEAN foundOne = FALSE; ! 151: ! 152: DebugPrint((1,"\n\nSCSI CdRom Class Driver\n")); ! 153: ! 154: // ! 155: // Set up the device driver entry points. ! 156: // ! 157: ! 158: DriverObject->MajorFunction[IRP_MJ_CREATE] = ScsiCdRomOpenClose; ! 159: DriverObject->MajorFunction[IRP_MJ_CLOSE] = ScsiCdRomOpenClose; ! 160: DriverObject->MajorFunction[IRP_MJ_READ] = ScsiCdRomRead; ! 161: DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScsiCdRomDeviceControl; ! 162: DriverObject->MajorFunction[IRP_MJ_SCSI] = ScsiClassInternalIoControl; ! 163: ! 164: ! 165: // ! 166: // Open port driver device objects by name. ! 167: // ! 168: ! 169: do { ! 170: ! 171: // ! 172: // Create port driver name. ! 173: // ! 174: ! 175: sprintf(deviceNameBuffer, ! 176: "\\Device\\ScsiPort%d", ! 177: portNumber); ! 178: ! 179: DebugPrint((2,"ScsiCdRomInitialize: Open %s\n", ! 180: deviceNameBuffer)); ! 181: ! 182: RtlInitString(&deviceNameString, ! 183: deviceNameBuffer); ! 184: ! 185: status = RtlAnsiStringToUnicodeString(&unicodeDeviceName, ! 186: &deviceNameString, ! 187: TRUE); ! 188: ! 189: if (!NT_SUCCESS(status)) { ! 190: break; ! 191: } ! 192: ! 193: status = IoGetDeviceObjectPointer(&unicodeDeviceName, ! 194: FILE_READ_ATTRIBUTES, ! 195: &fileObject, ! 196: &portDeviceObject); ! 197: ! 198: RtlFreeUnicodeString(&unicodeDeviceName); ! 199: ! 200: if (NT_SUCCESS(status)) { ! 201: ! 202: // ! 203: // SCSI port driver exists. ! 204: // ! 205: ! 206: if (FindScsiCdRoms(DriverObject, ! 207: portDeviceObject, ! 208: portNumber++)) { ! 209: ! 210: foundOne = TRUE; ! 211: } ! 212: ! 213: // ! 214: // Dereference the file object since the port device pointer is no ! 215: // longer needed. The claim device code references the port driver ! 216: // pointer that is actually being used. ! 217: // ! 218: ! 219: ObDereferenceObject(fileObject); ! 220: } ! 221: ! 222: } while (NT_SUCCESS(status)); ! 223: ! 224: if (foundOne) { ! 225: return STATUS_SUCCESS; ! 226: } else { ! 227: return STATUS_NO_SUCH_DEVICE; ! 228: } ! 229: ! 230: } // end DriverEntry() ! 231: ! 232: ! 233: BOOLEAN ! 234: FindScsiCdRoms( ! 235: IN PDRIVER_OBJECT DriverObject, ! 236: IN PDEVICE_OBJECT PortDeviceObject, ! 237: IN UCHAR PortNumber ! 238: ) ! 239: ! 240: /*++ ! 241: ! 242: Routine Description: ! 243: ! 244: Connect to SCSI port driver. Get adapter capabilities and ! 245: SCSI bus configuration information. Search inquiry data ! 246: for CDROM devices to process. ! 247: ! 248: Arguments: ! 249: ! 250: DriverObject - CDROM class driver object. ! 251: PortDeviceObject - SCSI port driver device object. ! 252: PortNumber - The system ordinal for this scsi adapter. ! 253: ! 254: Return Value: ! 255: ! 256: TRUE if CDROM device present on this SCSI adapter. ! 257: ! 258: --*/ ! 259: ! 260: { ! 261: PIO_SCSI_CAPABILITIES portCapabilities; ! 262: PULONG cdRomCount; ! 263: PCHAR buffer; ! 264: PSCSI_INQUIRY_DATA lunInfo; ! 265: PSCSI_ADAPTER_BUS_INFO adapterInfo; ! 266: PINQUIRYDATA inquiryData; ! 267: ULONG scsiBus; ! 268: NTSTATUS status; ! 269: BOOLEAN foundDevice = FALSE; ! 270: ! 271: // ! 272: // Call port driver to get adapter capabilities. ! 273: // ! 274: ! 275: status = ScsiClassGetCapabilities(PortDeviceObject, &portCapabilities); ! 276: ! 277: if (!NT_SUCCESS(status)) { ! 278: DebugPrint((1,"FindScsiDevices: ScsiClassGetCapabilities failed\n")); ! 279: return foundDevice; ! 280: } ! 281: ! 282: // ! 283: // Call port driver to get inquiry information to find cdroms. ! 284: // ! 285: ! 286: status = ScsiClassGetInquiryData(PortDeviceObject, (PSCSI_ADAPTER_BUS_INFO *) &buffer); ! 287: ! 288: if (!NT_SUCCESS(status)) { ! 289: DebugPrint((1,"FindScsiDevices: ScsiClassGetInquiryData failed\n")); ! 290: return foundDevice; ! 291: } ! 292: ! 293: // ! 294: // Get the address of the count of the number of cdroms already initialized. ! 295: // ! 296: ! 297: cdRomCount = &IoGetConfigurationInformation()->CdRomCount; ! 298: adapterInfo = (PVOID) buffer; ! 299: ! 300: // ! 301: // For each SCSI bus this adapter supports ... ! 302: // ! 303: ! 304: for (scsiBus=0; scsiBus < adapterInfo->NumberOfBuses; scsiBus++) { ! 305: ! 306: // ! 307: // Get the SCSI bus scan data for this bus. ! 308: // ! 309: ! 310: lunInfo = (PVOID) (buffer + adapterInfo->BusData[scsiBus].InquiryDataOffset); ! 311: ! 312: // ! 313: // Search list for unclaimed disk devices. ! 314: // ! 315: ! 316: while (adapterInfo->BusData[scsiBus].InquiryDataOffset) { ! 317: ! 318: inquiryData = (PVOID)lunInfo->InquiryData; ! 319: ! 320: if ((inquiryData->DeviceType == READ_ONLY_DIRECT_ACCESS_DEVICE) && ! 321: (!lunInfo->DeviceClaimed)) { ! 322: ! 323: DebugPrint((1,"FindScsiDevices: Vendor string is %.24s\n", ! 324: inquiryData->VendorId)); ! 325: ! 326: // ! 327: // Create device objects for cdrom ! 328: // ! 329: ! 330: status = CreateCdRomDeviceObject(DriverObject, ! 331: PortDeviceObject, ! 332: PortNumber, ! 333: cdRomCount, ! 334: portCapabilities, ! 335: lunInfo); ! 336: ! 337: if (NT_SUCCESS(status)) { ! 338: ! 339: // ! 340: // Increment system cdrom device count. ! 341: // ! 342: ! 343: (*cdRomCount)++; ! 344: ! 345: // ! 346: // Indicate that a cdrom device was found. ! 347: // ! 348: ! 349: foundDevice = TRUE; ! 350: } ! 351: } ! 352: ! 353: // ! 354: // Get next LunInfo. ! 355: // ! 356: ! 357: if (lunInfo->NextInquiryDataOffset == 0) { ! 358: break; ! 359: } ! 360: ! 361: lunInfo = (PVOID) (buffer + lunInfo->NextInquiryDataOffset); ! 362: } ! 363: } ! 364: ! 365: ExFreePool(buffer); ! 366: ! 367: return foundDevice; ! 368: ! 369: } // end FindScsiCdRoms() ! 370: ! 371: ! 372: NTSTATUS ! 373: CreateCdRomDeviceObject( ! 374: IN PDRIVER_OBJECT DriverObject, ! 375: IN PDEVICE_OBJECT PortDeviceObject, ! 376: IN UCHAR PortNumber, ! 377: IN PULONG DeviceCount, ! 378: IN PIO_SCSI_CAPABILITIES PortCapabilities, ! 379: IN PSCSI_INQUIRY_DATA LunInfo ! 380: ) ! 381: ! 382: /*++ ! 383: ! 384: Routine Description: ! 385: ! 386: This routine creates an object for the device and then calls the ! 387: SCSI port driver for media capacity and sector size. ! 388: ! 389: Arguments: ! 390: ! 391: DriverObject - Pointer to driver object created by system. ! 392: PortDeviceObject - to connect to SCSI port driver. ! 393: DeviceCount - Number of previously installed CDROMs. ! 394: PortCapabilities - Pointer to structure returned by SCSI port ! 395: driver describing adapter capabilites (and limitations). ! 396: LunInfo - Pointer to configuration information for this device. ! 397: ! 398: Return Value: ! 399: ! 400: NTSTATUS ! 401: ! 402: --*/ ! 403: { ! 404: UCHAR ntNameBuffer[64]; ! 405: UCHAR arcNameBuffer[64]; ! 406: STRING ntNameString; ! 407: STRING arcNameString; ! 408: UNICODE_STRING ntUnicodeString; ! 409: UNICODE_STRING arcUnicodeString; ! 410: NTSTATUS status; ! 411: PDEVICE_OBJECT deviceObject = NULL; ! 412: PDEVICE_EXTENSION deviceExtension; ! 413: PVOID senseData = NULL; ! 414: ! 415: // ! 416: // Claim the device. ! 417: // ! 418: ! 419: status = ScsiClassClaimDevice( ! 420: PortDeviceObject, ! 421: LunInfo, ! 422: FALSE, ! 423: &PortDeviceObject ! 424: ); ! 425: ! 426: if (!NT_SUCCESS(status)) { ! 427: return(status); ! 428: } ! 429: ! 430: ! 431: // ! 432: // Create device object for this device. ! 433: // ! 434: ! 435: sprintf(ntNameBuffer, ! 436: "\\Device\\CdRom%d", ! 437: *DeviceCount); ! 438: ! 439: RtlInitString(&ntNameString, ! 440: ntNameBuffer); ! 441: ! 442: DebugPrint((2,"CreateCdRomDeviceObjects: Create device object %s\n", ! 443: ntNameBuffer)); ! 444: ! 445: // ! 446: // Convert ANSI string to Unicode. ! 447: // ! 448: ! 449: status = RtlAnsiStringToUnicodeString(&ntUnicodeString, ! 450: &ntNameString, ! 451: TRUE); ! 452: ! 453: if (!NT_SUCCESS(status)) { ! 454: ! 455: DebugPrint((1, ! 456: "CreateDiskDeviceObjects: Cannot convert string %s\n", ! 457: ntNameBuffer)); ! 458: ! 459: // ! 460: // Release the device since an error occured. ! 461: // ! 462: ! 463: ScsiClassClaimDevice( ! 464: PortDeviceObject, ! 465: LunInfo, ! 466: TRUE, ! 467: NULL ! 468: ); ! 469: ! 470: return(status); ! 471: } ! 472: ! 473: // ! 474: // Create device object for this CDROM. ! 475: // ! 476: ! 477: status = IoCreateDevice(DriverObject, ! 478: DEVICE_EXTENSION_SIZE, ! 479: &ntUnicodeString, ! 480: FILE_DEVICE_CD_ROM, ! 481: FILE_REMOVABLE_MEDIA | FILE_READ_ONLY_DEVICE, ! 482: FALSE, ! 483: &deviceObject); ! 484: ! 485: ! 486: if (!NT_SUCCESS(status)) { ! 487: DebugPrint((1,"CreateCdRomDeviceObjects: Can not create device %s\n", ! 488: ntNameBuffer)); ! 489: ! 490: RtlFreeUnicodeString(&ntUnicodeString); ! 491: deviceObject = NULL; ! 492: goto CreateCdRomDeviceObjectExit; ! 493: } ! 494: ! 495: // ! 496: // Indicate that IRPs should include MDLs. ! 497: // ! 498: ! 499: deviceObject->Flags |= DO_DIRECT_IO; ! 500: ! 501: // ! 502: // Set up required stack size in device object. ! 503: // ! 504: ! 505: deviceObject->StackSize = PortDeviceObject->StackSize + 1; ! 506: ! 507: deviceExtension = deviceObject->DeviceExtension; ! 508: ! 509: // ! 510: // Allocate spinlock for split request completion. ! 511: // ! 512: ! 513: KeInitializeSpinLock(&deviceExtension->SplitRequestSpinLock); ! 514: ! 515: // ! 516: // This is the physical device. ! 517: // ! 518: ! 519: deviceExtension->PhysicalDevice = deviceObject; ! 520: ! 521: // ! 522: // Copy port device object to device extension. ! 523: // ! 524: ! 525: deviceExtension->PortDeviceObject = PortDeviceObject; ! 526: ! 527: // ! 528: // Set the alignment requirements for the device based on the ! 529: // host adapter requirements ! 530: // ! 531: ! 532: if (PortDeviceObject->AlignmentRequirement > deviceObject->AlignmentRequirement) { ! 533: deviceObject->AlignmentRequirement = PortDeviceObject->AlignmentRequirement; ! 534: } ! 535: ! 536: // ! 537: // Save address of port driver capabilities. ! 538: // ! 539: ! 540: deviceExtension->PortCapabilities = PortCapabilities; ! 541: ! 542: // ! 543: // Disable synchronous transfer for CDROM requests. ! 544: // ! 545: ! 546: deviceExtension->SrbFlags = SRB_FLAGS_DISABLE_SYNCH_TRANSFER; ! 547: ! 548: // ! 549: // Allocate request sense buffer. ! 550: // ! 551: ! 552: senseData = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE); ! 553: ! 554: if (senseData == NULL) { ! 555: ! 556: // ! 557: // The buffer cannot be allocated. ! 558: // ! 559: ! 560: status = STATUS_INSUFFICIENT_RESOURCES; ! 561: goto CreateCdRomDeviceObjectExit; ! 562: } ! 563: ! 564: // ! 565: // Set the sense data pointer in the device extension. ! 566: // ! 567: ! 568: deviceExtension->SenseData = senseData; ! 569: ! 570: // ! 571: // CDROMs are not partitionable so starting offset is 0. ! 572: // ! 573: ! 574: deviceExtension->StartingOffset.LowPart = 0; ! 575: deviceExtension->StartingOffset.HighPart = 0; ! 576: ! 577: // ! 578: // Path/TargetId/LUN describes a device location on the SCSI bus. ! 579: // This information comes from the LunInfo buffer. ! 580: // ! 581: ! 582: deviceExtension->PortNumber = PortNumber; ! 583: deviceExtension->PathId = LunInfo->PathId; ! 584: deviceExtension->TargetId = LunInfo->TargetId; ! 585: deviceExtension->Lun = LunInfo->Lun; ! 586: ! 587: // ! 588: // Set timeout value in seconds. ! 589: // ! 590: ! 591: deviceExtension->TimeOutValue = SCSI_CDROM_TIMEOUT; ! 592: ! 593: // ! 594: // Back pointer to device object. ! 595: // ! 596: ! 597: deviceExtension->DeviceObject = deviceObject; ! 598: ! 599: // ! 600: // Create a symbolic link from the cdrom name to the corresponding ! 601: // ARC name, to be used if we're booting off the cdrom. This will ! 602: // fail if it's not system initialization time; that's fine. The ! 603: // ARC name looks something like \ArcName\scsi(0)cdrom(0)fdisk(0). ! 604: // ! 605: ! 606: sprintf(arcNameBuffer, ! 607: "\\ArcName\\scsi(%d)cdrom(%d)fdisk(%d)", ! 608: PortNumber, ! 609: LunInfo->TargetId + LunInfo->PathId * SCSI_MAXIMUM_TARGETS_PER_BUS, ! 610: LunInfo->Lun); ! 611: ! 612: RtlInitString(&arcNameString, arcNameBuffer); ! 613: ! 614: status = RtlAnsiStringToUnicodeString(&arcUnicodeString, ! 615: &arcNameString, ! 616: TRUE); ! 617: ! 618: if (!NT_SUCCESS(status)) { ! 619: ! 620: DebugPrint((1, ! 621: "CreateCdRomDeviceObjects: Cannot convert string %s\n", ! 622: arcNameBuffer)); ! 623: ! 624: RtlFreeUnicodeString(&ntUnicodeString); ! 625: ! 626: goto CreateCdRomDeviceObjectExit; ! 627: } ! 628: ! 629: IoAssignArcName(&arcUnicodeString, &ntUnicodeString); ! 630: ! 631: RtlFreeUnicodeString(&ntUnicodeString); ! 632: RtlFreeUnicodeString(&arcUnicodeString); ! 633: ! 634: // ! 635: // Allocate buffer for drive geometry. ! 636: // ! 637: ! 638: deviceExtension->DiskGeometry = ! 639: ExAllocatePool(NonPagedPool, sizeof(DISK_GEOMETRY)); ! 640: ! 641: if (deviceExtension->DiskGeometry == NULL) { ! 642: ! 643: status = STATUS_INSUFFICIENT_RESOURCES; ! 644: goto CreateCdRomDeviceObjectExit; ! 645: } ! 646: ! 647: // ! 648: // Scan for Scsi controllers that require special processing. ! 649: // ! 650: ! 651: ScanForSpecial(deviceObject, ! 652: (PINQUIRYDATA) LunInfo->InquiryData, ! 653: PortCapabilities); ! 654: ! 655: // ! 656: // Do READ CAPACITY. This SCSI command ! 657: // returns the last sector address on the device ! 658: // and the bytes per sector. ! 659: // These are used to calculate the drive capacity ! 660: // in bytes. ! 661: // ! 662: ! 663: status = ScsiClassReadDriveCapacity(deviceObject); ! 664: ! 665: if ((!NT_SUCCESS(status)) || ! 666: (deviceExtension->DiskGeometry->BytesPerSector == 0)) { ! 667: ! 668: DebugPrint((1, ! 669: "CreateCdRomDeviceObjects: Can't read capacity for device %s\n", ! 670: ntNameBuffer)); ! 671: ! 672: // ! 673: // Set disk geometry to default values (per ISO 9660). ! 674: // ! 675: ! 676: deviceExtension->DiskGeometry->BytesPerSector = 2048; ! 677: deviceExtension->SectorShift = 11; ! 678: ! 679: } ! 680: ! 681: return(STATUS_SUCCESS); ! 682: ! 683: CreateCdRomDeviceObjectExit: ! 684: ! 685: // ! 686: // Release the device since an error occured. ! 687: // ! 688: ! 689: ScsiClassClaimDevice( ! 690: PortDeviceObject, ! 691: LunInfo, ! 692: TRUE, ! 693: NULL ! 694: ); ! 695: ! 696: if (senseData != NULL) { ! 697: ExFreePool(senseData); ! 698: } ! 699: ! 700: if (deviceExtension->DiskGeometry != NULL) { ! 701: ExFreePool(deviceExtension->DiskGeometry); ! 702: } ! 703: ! 704: if (deviceObject != NULL) { ! 705: IoDeleteDevice(deviceObject); ! 706: } ! 707: ! 708: ! 709: return status; ! 710: ! 711: } // end CreateCdromDeviceObject() ! 712: ! 713: ! 714: NTSTATUS ! 715: ScsiCdRomOpenClose( ! 716: IN PDEVICE_OBJECT DeviceObject, ! 717: IN PIRP Irp ! 718: ) ! 719: ! 720: /*++ ! 721: ! 722: Routine Description: ! 723: ! 724: This routine is called to establish a connection to the CDROM ! 725: class driver. It does no more than return STATUS_SUCCESS. ! 726: ! 727: Arguments: ! 728: ! 729: DeviceObject - Device object for CDROM drive ! 730: Irp - Open or Close request packet ! 731: ! 732: Return Value: ! 733: ! 734: NT Status - STATUS_SUCCESS ! 735: ! 736: --*/ ! 737: ! 738: { ! 739: // ! 740: // Set status in Irp. ! 741: // ! 742: ! 743: Irp->IoStatus.Status = STATUS_SUCCESS; ! 744: ! 745: // ! 746: // Complete request at raised IRQ. ! 747: // ! 748: ! 749: IoCompleteRequest(Irp, IO_NO_INCREMENT); ! 750: return STATUS_SUCCESS; ! 751: ! 752: } // end ScsiCdRomOpenClose() ! 753: ! 754: ! 755: NTSTATUS ! 756: ScsiCdRomRead( ! 757: IN PDEVICE_OBJECT DeviceObject, ! 758: IN PIRP Irp ! 759: ) ! 760: ! 761: /*++ ! 762: ! 763: Routine Description: ! 764: ! 765: This is the entry called by the I/O system for read requests. ! 766: It builds the SRB and sends it to the port driver. ! 767: ! 768: Arguments: ! 769: ! 770: DeviceObject - the system object for the device. ! 771: Irp - IRP involved. ! 772: ! 773: Return Value: ! 774: ! 775: NT Status ! 776: ! 777: --*/ ! 778: ! 779: { ! 780: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; ! 781: PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp); ! 782: ULONG transferByteCount = currentIrpStack->Parameters.Read.Length; ! 783: LARGE_INTEGER startingOffset; ! 784: ULONG maximumTransferLength = ! 785: deviceExtension->PortCapabilities->MaximumTransferLength; ! 786: ULONG transferPages; ! 787: ! 788: // ! 789: // If the cd is playing music then reject this request. ! 790: // ! 791: ! 792: if (PLAY_ACTIVE(deviceExtension)) { ! 793: Irp->IoStatus.Status = STATUS_DEVICE_BUSY; ! 794: IoCompleteRequest(Irp, IO_NO_INCREMENT); ! 795: return STATUS_DEVICE_BUSY; ! 796: } ! 797: ! 798: // ! 799: // Check if volume needs verification. ! 800: // ! 801: ! 802: if ((DeviceObject->Flags & DO_VERIFY_VOLUME) && ! 803: !(currentIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME)) { ! 804: ! 805: // ! 806: // if DO_VERIFY_VOLUME bit is set ! 807: // in device object flags, fail request. ! 808: // ! 809: ! 810: DebugPrint((2,"ScsiCdRomRead: Volume verfication needed\n")); ! 811: ! 812: IoSetHardErrorOrVerifyDevice(Irp, DeviceObject); ! 813: ! 814: Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED; ! 815: Irp->IoStatus.Information = 0; ! 816: ! 817: IoCompleteRequest(Irp, IO_NO_INCREMENT); ! 818: return STATUS_VERIFY_REQUIRED; ! 819: } ! 820: ! 821: // ! 822: // Verify parameters of this request. ! 823: // Check that ending sector is on disc and ! 824: // that number of bytes to transfer is a multiple of ! 825: // the sector size. ! 826: // ! 827: ! 828: startingOffset = LiFromUlong(transferByteCount); ! 829: startingOffset = LiAdd(startingOffset, ! 830: currentIrpStack->Parameters.Read.ByteOffset); ! 831: ! 832: if (LiGtr( startingOffset, deviceExtension->PartitionLength) || ! 833: (transferByteCount & deviceExtension->DiskGeometry->BytesPerSector - 1)) { ! 834: ! 835: DebugPrint((1,"ScsiCdRomRead: Invalid I/O parameters\n")); ! 836: ! 837: // ! 838: // Fail request with status of invalid parameters. ! 839: // ! 840: ! 841: Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; ! 842: ! 843: IoCompleteRequest(Irp, IO_NO_INCREMENT); ! 844: return STATUS_INVALID_PARAMETER; ! 845: } ! 846: ! 847: // ! 848: // Mark IRP with status pending. ! 849: // ! 850: ! 851: IoMarkIrpPending(Irp); ! 852: ! 853: // ! 854: // Calculate number of pages in this transfer. ! 855: // ! 856: ! 857: transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES( ! 858: MmGetMdlVirtualAddress(Irp->MdlAddress), ! 859: currentIrpStack->Parameters.Read.Length); ! 860: ! 861: // ! 862: // Check if request length is greater than the maximum number of ! 863: // bytes that the hardware can transfer. ! 864: // ! 865: ! 866: if (currentIrpStack->Parameters.Read.Length > maximumTransferLength || ! 867: transferPages > deviceExtension->PortCapabilities->MaximumPhysicalPages) { ! 868: ! 869: DebugPrint((2,"ScsiCdromRead: Request greater than maximum\n")); ! 870: DebugPrint((2,"ScsiCdromRead: Maximum is %lx\n", ! 871: maximumTransferLength)); ! 872: DebugPrint((2,"ScsiCdromRead: Byte count is %lx\n", ! 873: currentIrpStack->Parameters.Read.Length)); ! 874: ! 875: transferPages = ! 876: deviceExtension->PortCapabilities->MaximumPhysicalPages - 1; ! 877: ! 878: if (maximumTransferLength > transferPages << PAGE_SHIFT ) { ! 879: maximumTransferLength = transferPages << PAGE_SHIFT; ! 880: } ! 881: ! 882: // ! 883: // Check that maximum transfer size is not zero. ! 884: // ! 885: ! 886: if (maximumTransferLength == 0) { ! 887: maximumTransferLength = PAGE_SIZE; ! 888: } ! 889: ! 890: // ! 891: // Mark IRP with status pending. ! 892: // ! 893: ! 894: IoMarkIrpPending(Irp); ! 895: ! 896: // ! 897: // Request greater than port driver maximum. ! 898: // Break up into smaller routines. ! 899: // ! 900: ! 901: ScsiClassSplitRequest(DeviceObject, Irp, maximumTransferLength); ! 902: ! 903: ! 904: return STATUS_PENDING; ! 905: } ! 906: ! 907: // ! 908: // Build SRB and CDB for this IRP. ! 909: // ! 910: ! 911: ScsiClassBuildRequest(DeviceObject, Irp); ! 912: ! 913: // ! 914: // Return the results of the call to the port driver. ! 915: // ! 916: ! 917: return IoCallDriver(deviceExtension->PortDeviceObject, Irp); ! 918: ! 919: } // end ScsiCdRomRead() ! 920: ! 921: ! 922: NTSTATUS ! 923: ScsiCdRomDeviceControl( ! 924: IN PDEVICE_OBJECT DeviceObject, ! 925: IN PIRP Irp ! 926: ) ! 927: ! 928: /*++ ! 929: ! 930: Routine Description: ! 931: ! 932: This is the NT device control handler for CDROMs. ! 933: ! 934: Arguments: ! 935: ! 936: DeviceObject - for this CDROM ! 937: ! 938: Irp - IO Request packet ! 939: ! 940: Return Value: ! 941: ! 942: NTSTATUS ! 943: ! 944: --*/ ! 945: ! 946: { ! 947: PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); ! 948: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; ! 949: SCSI_REQUEST_BLOCK srb; ! 950: PCDB cdb = (PCDB)srb.Cdb; ! 951: PVOID outputBuffer; ! 952: ULONG bytesTransferred = 0; ! 953: NTSTATUS status; ! 954: NTSTATUS status2; ! 955: ! 956: RetryControl: ! 957: ! 958: // ! 959: // Zero the SRB on stack. ! 960: // ! 961: ! 962: RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK)); ! 963: ! 964: Irp->IoStatus.Information = 0; ! 965: ! 966: switch (irpStack->Parameters.DeviceIoControl.IoControlCode) { ! 967: ! 968: case IOCTL_CDROM_GET_DRIVE_GEOMETRY: ! 969: ! 970: DebugPrint((2,"ScsiCdRomDeviceControl: Get drive geometry\n")); ! 971: ! 972: if ( irpStack->Parameters.DeviceIoControl.OutputBufferLength < ! 973: sizeof( DISK_GEOMETRY ) ) { ! 974: ! 975: status = STATUS_INFO_LENGTH_MISMATCH; ! 976: break; ! 977: } ! 978: ! 979: // ! 980: // Issue ReadCapacity to update device extension ! 981: // with information for current media. ! 982: // ! 983: ! 984: status = ScsiClassReadDriveCapacity(DeviceObject); ! 985: ! 986: if ((!NT_SUCCESS(status)) || ! 987: (deviceExtension->DiskGeometry->BytesPerSector == 0)) { ! 988: ! 989: // ! 990: // Set disk geometry to default values (per ISO 9660). ! 991: // ! 992: ! 993: deviceExtension->DiskGeometry->BytesPerSector = 2048; ! 994: deviceExtension->SectorShift = 11; ! 995: } ! 996: ! 997: // ! 998: // Copy drive geometry information from device extension. ! 999: // ! 1000: ! 1001: RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer, ! 1002: deviceExtension->DiskGeometry, ! 1003: sizeof(DISK_GEOMETRY)); ! 1004: ! 1005: status = STATUS_SUCCESS; ! 1006: Irp->IoStatus.Information = sizeof(DISK_GEOMETRY); ! 1007: ! 1008: break; ! 1009: ! 1010: case IOCTL_CDROM_GET_LAST_SESSION: ! 1011: ! 1012: // ! 1013: // Set format to return first and last session numbers. ! 1014: // ! 1015: ! 1016: cdb->READ_TOC.Format = GET_LAST_SESSION; ! 1017: ! 1018: // ! 1019: // Fall through to READ TOC code. ! 1020: // ! 1021: ! 1022: case IOCTL_CDROM_READ_TOC: ! 1023: ! 1024: { ! 1025: PCDROM_TOC toc = Irp->AssociatedIrp.SystemBuffer; ! 1026: ULONG transferBytes; ! 1027: ! 1028: DebugPrint((2,"CdRomDeviceControl: Read TOC\n")); ! 1029: ! 1030: // ! 1031: // If the cd is playing music then reject this request. ! 1032: // ! 1033: ! 1034: if (CdRomIsPlayActive(DeviceObject)) { ! 1035: Irp->IoStatus.Status = STATUS_DEVICE_BUSY; ! 1036: IoCompleteRequest(Irp, IO_NO_INCREMENT); ! 1037: return STATUS_DEVICE_BUSY; ! 1038: } ! 1039: ! 1040: // ! 1041: // Read TOC is 10 byte CDB. ! 1042: // ! 1043: ! 1044: srb.CdbLength = 10; ! 1045: ! 1046: cdb->READ_TOC.OperationCode = SCSIOP_READ_TOC; ! 1047: ! 1048: if (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_READ_TOC) { ! 1049: ! 1050: // ! 1051: // Use MSF addressing if not request for session information. ! 1052: // ! 1053: ! 1054: cdb->READ_TOC.Msf = CDB_USE_MSF; ! 1055: } ! 1056: ! 1057: // ! 1058: // Start at beginning of disc. ! 1059: // ! 1060: ! 1061: cdb->READ_TOC.StartingTrack = 0; ! 1062: ! 1063: // ! 1064: // Set size of TOC structure. ! 1065: // ! 1066: ! 1067: transferBytes = ! 1068: irpStack->Parameters.Read.Length > ! 1069: sizeof(CDROM_TOC) ? sizeof(CDROM_TOC): ! 1070: irpStack->Parameters.Read.Length; ! 1071: ! 1072: cdb->READ_TOC.AllocationLength[0] = (UCHAR) (transferBytes >> 8); ! 1073: cdb->READ_TOC.AllocationLength[1] = (UCHAR) (transferBytes & 0xFF); ! 1074: ! 1075: cdb->READ_TOC.Control = 0; ! 1076: ! 1077: // ! 1078: // Set timeout value. ! 1079: // ! 1080: ! 1081: srb.TimeOutValue = deviceExtension->TimeOutValue; ! 1082: ! 1083: status = ScsiClassSendSrbSynchronous(DeviceObject, ! 1084: &srb, ! 1085: toc, ! 1086: transferBytes, ! 1087: FALSE); ! 1088: ! 1089: // ! 1090: // Check for data underrun. ! 1091: // ! 1092: ! 1093: if (status==STATUS_DATA_OVERRUN) { ! 1094: status = STATUS_SUCCESS; ! 1095: } ! 1096: ! 1097: Irp->IoStatus.Information = srb.DataTransferLength; ! 1098: } ! 1099: ! 1100: break; ! 1101: ! 1102: case IOCTL_CDROM_PLAY_AUDIO_MSF: ! 1103: ! 1104: { ! 1105: PCDROM_PLAY_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer; ! 1106: ! 1107: // ! 1108: // Play Audio MSF ! 1109: // ! 1110: ! 1111: DebugPrint((2,"ScsiCdRomDeviceControl: Play audio MSF\n")); ! 1112: ! 1113: if (irpStack->Parameters.DeviceIoControl.InputBufferLength < ! 1114: sizeof(CDROM_PLAY_AUDIO_MSF)) { ! 1115: ! 1116: // ! 1117: // Indicate unsuccessful status. ! 1118: // ! 1119: ! 1120: status = STATUS_BUFFER_TOO_SMALL; ! 1121: break; ! 1122: } ! 1123: ! 1124: cdb->PLAY_AUDIO_MSF.OperationCode = SCSIOP_PLAY_AUDIO_MSF; ! 1125: ! 1126: cdb->PLAY_AUDIO_MSF.StartingM = inputBuffer->StartingM; ! 1127: cdb->PLAY_AUDIO_MSF.StartingS = inputBuffer->StartingS; ! 1128: cdb->PLAY_AUDIO_MSF.StartingF = inputBuffer->StartingF; ! 1129: ! 1130: cdb->PLAY_AUDIO_MSF.EndingM = inputBuffer->EndingM; ! 1131: cdb->PLAY_AUDIO_MSF.EndingS = inputBuffer->EndingS; ! 1132: cdb->PLAY_AUDIO_MSF.EndingF = inputBuffer->EndingF; ! 1133: ! 1134: srb.CdbLength = 10; ! 1135: ! 1136: // ! 1137: // Set timeout value. ! 1138: // ! 1139: ! 1140: srb.TimeOutValue = deviceExtension->TimeOutValue; ! 1141: ! 1142: status = ScsiClassSendSrbSynchronous(DeviceObject, ! 1143: &srb, ! 1144: NULL, ! 1145: 0, ! 1146: FALSE); ! 1147: ! 1148: if (NT_SUCCESS(status)) { ! 1149: PLAY_ACTIVE(deviceExtension) = TRUE; ! 1150: } ! 1151: } ! 1152: ! 1153: break; ! 1154: ! 1155: case IOCTL_CDROM_SEEK_AUDIO_MSF: ! 1156: ! 1157: { ! 1158: PCDROM_SEEK_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer; ! 1159: ! 1160: // ! 1161: // Seek Audio MSF ! 1162: // ! 1163: ! 1164: DebugPrint((2,"ScsiCdRomDeviceControl: Seek audio MSF\n")); ! 1165: ! 1166: if (irpStack->Parameters.DeviceIoControl.InputBufferLength < ! 1167: sizeof(CDROM_SEEK_AUDIO_MSF)) { ! 1168: ! 1169: // ! 1170: // Indicate unsuccessful status. ! 1171: // ! 1172: ! 1173: status = STATUS_BUFFER_TOO_SMALL; ! 1174: break; ! 1175: } ! 1176: ! 1177: cdb->PLAY_AUDIO_MSF.OperationCode = SCSIOP_PLAY_AUDIO_MSF; ! 1178: ! 1179: cdb->PLAY_AUDIO_MSF.StartingM = inputBuffer->M; ! 1180: cdb->PLAY_AUDIO_MSF.StartingS = inputBuffer->S; ! 1181: cdb->PLAY_AUDIO_MSF.StartingF = inputBuffer->F; ! 1182: ! 1183: cdb->PLAY_AUDIO_MSF.EndingM = inputBuffer->M; ! 1184: cdb->PLAY_AUDIO_MSF.EndingS = inputBuffer->S; ! 1185: cdb->PLAY_AUDIO_MSF.EndingF = inputBuffer->F; ! 1186: ! 1187: srb.CdbLength = 10; ! 1188: ! 1189: // ! 1190: // Set timeout value. ! 1191: // ! 1192: ! 1193: srb.TimeOutValue = deviceExtension->TimeOutValue; ! 1194: ! 1195: status = ScsiClassSendSrbSynchronous(DeviceObject, ! 1196: &srb, ! 1197: NULL, ! 1198: 0, ! 1199: FALSE); ! 1200: ! 1201: } ! 1202: ! 1203: break; ! 1204: ! 1205: case IOCTL_CDROM_PAUSE_AUDIO: ! 1206: ! 1207: // ! 1208: // Pause audio ! 1209: // ! 1210: ! 1211: DebugPrint((2, "ScsiCdRomDeviceControl: Pause audio\n")); ! 1212: ! 1213: PLAY_ACTIVE(deviceExtension) = FALSE; ! 1214: ! 1215: cdb->PAUSE_RESUME.OperationCode = SCSIOP_PAUSE_RESUME; ! 1216: ! 1217: cdb->PAUSE_RESUME.Action = CDB_AUDIO_PAUSE; ! 1218: ! 1219: srb.CdbLength = 10; ! 1220: ! 1221: // ! 1222: // Set timeout value. ! 1223: // ! 1224: ! 1225: srb.TimeOutValue = deviceExtension->TimeOutValue; ! 1226: ! 1227: status = ScsiClassSendSrbSynchronous(DeviceObject, ! 1228: &srb, ! 1229: NULL, ! 1230: 0, ! 1231: FALSE); ! 1232: ! 1233: break; ! 1234: ! 1235: case IOCTL_CDROM_RESUME_AUDIO: ! 1236: ! 1237: // ! 1238: // Resume audio ! 1239: // ! 1240: ! 1241: DebugPrint((2, "ScsiCdRomDeviceControl: Resume audio\n")); ! 1242: ! 1243: cdb->PAUSE_RESUME.OperationCode = SCSIOP_PAUSE_RESUME; ! 1244: ! 1245: cdb->PAUSE_RESUME.Action = CDB_AUDIO_RESUME; ! 1246: ! 1247: srb.CdbLength = 10; ! 1248: ! 1249: // ! 1250: // Set timeout value. ! 1251: // ! 1252: ! 1253: srb.TimeOutValue = deviceExtension->TimeOutValue; ! 1254: ! 1255: status = ScsiClassSendSrbSynchronous(DeviceObject, ! 1256: &srb, ! 1257: NULL, ! 1258: 0, ! 1259: FALSE); ! 1260: ! 1261: break; ! 1262: ! 1263: case IOCTL_CDROM_READ_Q_CHANNEL: ! 1264: ! 1265: { ! 1266: ! 1267: PSUB_Q_CHANNEL_DATA userChannelData = ! 1268: Irp->AssociatedIrp.SystemBuffer; ! 1269: PCDROM_SUB_Q_DATA_FORMAT inputBuffer = ! 1270: Irp->AssociatedIrp.SystemBuffer; ! 1271: PSUB_Q_CHANNEL_DATA subQPtr; ! 1272: ! 1273: // ! 1274: // Allocate buffer for subq channel information. ! 1275: // ! 1276: ! 1277: subQPtr = ExAllocatePool(NonPagedPoolCacheAligned, ! 1278: sizeof(SUB_Q_CHANNEL_DATA)); ! 1279: ! 1280: if (!subQPtr) { ! 1281: status = STATUS_INSUFFICIENT_RESOURCES; ! 1282: Irp->IoStatus.Information = 0; ! 1283: break; ! 1284: } ! 1285: ! 1286: // ! 1287: // Read Subchannel Q ! 1288: // ! 1289: ! 1290: DebugPrint((2, ! 1291: "ScsiCdRomDeviceControl: Read channel Q Format %u\n", inputBuffer->Format )); ! 1292: ! 1293: cdb->SUBCHANNEL.OperationCode = SCSIOP_READ_SUB_CHANNEL; ! 1294: ! 1295: // ! 1296: // Always logical unit 0, but only use MSF addressing ! 1297: // for IOCTL_CDROM_CURRENT_POSITION ! 1298: // ! 1299: ! 1300: if (inputBuffer->Format==IOCTL_CDROM_CURRENT_POSITION) ! 1301: cdb->SUBCHANNEL.Msf = CDB_USE_MSF; ! 1302: ! 1303: // ! 1304: // Return subchannel data ! 1305: // ! 1306: ! 1307: cdb->SUBCHANNEL.SubQ = CDB_SUBCHANNEL_BLOCK; ! 1308: ! 1309: // ! 1310: // Specify format of informatin to return ! 1311: // ! 1312: ! 1313: cdb->SUBCHANNEL.Format = inputBuffer->Format; ! 1314: ! 1315: // ! 1316: // Specify which track to access (only used by Track ISRC reads) ! 1317: // ! 1318: ! 1319: if (inputBuffer->Format==IOCTL_CDROM_TRACK_ISRC) ! 1320: cdb->SUBCHANNEL.TrackNumber = inputBuffer->Track; ! 1321: ! 1322: // ! 1323: // Set size of channel data -- however, this is dependent on ! 1324: // what information we are requesting (which Format) ! 1325: // ! 1326: ! 1327: switch( inputBuffer->Format ) { ! 1328: ! 1329: case IOCTL_CDROM_CURRENT_POSITION: ! 1330: bytesTransferred = sizeof(SUB_Q_CURRENT_POSITION); ! 1331: break; ! 1332: ! 1333: case IOCTL_CDROM_MEDIA_CATALOG: ! 1334: bytesTransferred = sizeof(SUB_Q_MEDIA_CATALOG_NUMBER); ! 1335: break; ! 1336: ! 1337: case IOCTL_CDROM_TRACK_ISRC: ! 1338: bytesTransferred = sizeof(SUB_Q_TRACK_ISRC); ! 1339: break; ! 1340: } ! 1341: ! 1342: cdb->SUBCHANNEL.AllocationLength[0] = (UCHAR) (bytesTransferred >> 8); ! 1343: cdb->SUBCHANNEL.AllocationLength[1] = (UCHAR) (bytesTransferred & 0xFF); ! 1344: ! 1345: srb.CdbLength = 10; ! 1346: ! 1347: // ! 1348: // Set timeout value. ! 1349: // ! 1350: ! 1351: srb.TimeOutValue = deviceExtension->TimeOutValue; ! 1352: ! 1353: status = ScsiClassSendSrbSynchronous(DeviceObject, ! 1354: &srb, ! 1355: subQPtr, ! 1356: bytesTransferred, ! 1357: FALSE); ! 1358: ! 1359: if (NT_SUCCESS(status)) { ! 1360: #if DBG ! 1361: switch( inputBuffer->Format ) { ! 1362: ! 1363: case IOCTL_CDROM_CURRENT_POSITION: ! 1364: DebugPrint((3,"ScsiCdromDeviceControl: Audio Status is %u\n", subQPtr->CurrentPosition.Header.AudioStatus )); ! 1365: DebugPrint((3,"ScsiCdromDeviceControl: ADR = 0x%x\n", subQPtr->CurrentPosition.ADR )); ! 1366: DebugPrint((3,"ScsiCdromDeviceControl: Control = 0x%x\n", subQPtr->CurrentPosition.Control )); ! 1367: DebugPrint((3,"ScsiCdromDeviceControl: Track = %u\n", subQPtr->CurrentPosition.TrackNumber )); ! 1368: DebugPrint((3,"ScsiCdromDeviceControl: Index = %u\n", subQPtr->CurrentPosition.IndexNumber )); ! 1369: break; ! 1370: ! 1371: case IOCTL_CDROM_MEDIA_CATALOG: ! 1372: DebugPrint((3,"ScsiCdromDeviceControl: Audio Status is %u\n", subQPtr->MediaCatalog.Header.AudioStatus )); ! 1373: DebugPrint((3,"ScsiCdromDeviceControl: Mcval is %u\n", subQPtr->MediaCatalog.Mcval )); ! 1374: break; ! 1375: ! 1376: case IOCTL_CDROM_TRACK_ISRC: ! 1377: DebugPrint((3,"ScsiCdromDeviceControl: Audio Status is %u\n", subQPtr->TrackIsrc.Header.AudioStatus )); ! 1378: DebugPrint((3,"ScsiCdromDeviceControl: Tcval is %u\n", subQPtr->TrackIsrc.Tcval )); ! 1379: break; ! 1380: ! 1381: } ! 1382: #endif ! 1383: ! 1384: // ! 1385: // Update the play active status. ! 1386: // ! 1387: ! 1388: if (subQPtr->CurrentPosition.Header.AudioStatus == AUDIO_STATUS_IN_PROGRESS) { ! 1389: ! 1390: PLAY_ACTIVE(deviceExtension) = TRUE; ! 1391: ! 1392: } else { ! 1393: ! 1394: PLAY_ACTIVE(deviceExtension) = FALSE; ! 1395: ! 1396: } ! 1397: ! 1398: // ! 1399: // Check if output buffer is large enough to contain ! 1400: // the data. ! 1401: // ! 1402: ! 1403: if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < ! 1404: bytesTransferred) { ! 1405: ! 1406: bytesTransferred = ! 1407: irpStack->Parameters.DeviceIoControl.OutputBufferLength; ! 1408: } ! 1409: ! 1410: RtlMoveMemory(userChannelData, ! 1411: subQPtr, ! 1412: bytesTransferred); ! 1413: ! 1414: Irp->IoStatus.Information = bytesTransferred; ! 1415: } else { ! 1416: ! 1417: PLAY_ACTIVE(deviceExtension) = FALSE; ! 1418: ! 1419: } ! 1420: ! 1421: ExFreePool(subQPtr); ! 1422: ! 1423: break; ! 1424: ! 1425: } ! 1426: ! 1427: case IOCTL_CDROM_GET_CONTROL: ! 1428: ! 1429: DebugPrint((2, "ScsiCdRomDeviceControl: Get audio control\n")); ! 1430: ! 1431: // ! 1432: // Verify user buffer is large enough for the data. ! 1433: // ! 1434: ! 1435: if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < ! 1436: sizeof(CDROM_AUDIO_CONTROL)) { ! 1437: ! 1438: // ! 1439: // Indicate unsuccessful status and no data transferred. ! 1440: // ! 1441: ! 1442: status = STATUS_BUFFER_TOO_SMALL; ! 1443: Irp->IoStatus.Information = 0; ! 1444: ! 1445: } else { ! 1446: ! 1447: PAUDIO_OUTPUT audioOutput; ! 1448: PCDROM_AUDIO_CONTROL audioControl = Irp->AssociatedIrp.SystemBuffer; ! 1449: ! 1450: // ! 1451: // Allocate buffer for volume control information. ! 1452: // ! 1453: ! 1454: outputBuffer = ExAllocatePool(NonPagedPoolCacheAligned, ! 1455: MODE_DATA_SIZE); ! 1456: ! 1457: if (!outputBuffer) { ! 1458: status = STATUS_INSUFFICIENT_RESOURCES; ! 1459: Irp->IoStatus.Information = 0; ! 1460: break; ! 1461: } ! 1462: ! 1463: // ! 1464: // Get audio control information ! 1465: // ! 1466: ! 1467: cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE; ! 1468: cdb->MODE_SENSE.PageCode = CDROM_AUDIO_CONTROL_PAGE; ! 1469: cdb->MODE_SENSE.AllocationLength = MODE_DATA_SIZE; ! 1470: ! 1471: // ! 1472: // Disable block descriptors. ! 1473: // ! 1474: ! 1475: cdb->MODE_SENSE.Dbd = TRUE; ! 1476: ! 1477: srb.CdbLength = 6; ! 1478: ! 1479: // ! 1480: // Set timeout value. ! 1481: // ! 1482: ! 1483: srb.TimeOutValue = deviceExtension->TimeOutValue; ! 1484: ! 1485: status = ScsiClassSendSrbSynchronous(DeviceObject, ! 1486: &srb, ! 1487: outputBuffer, ! 1488: MODE_DATA_SIZE, ! 1489: FALSE); ! 1490: ! 1491: if (SRB_STATUS(srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN) { ! 1492: status = STATUS_SUCCESS; ! 1493: } ! 1494: ! 1495: if (NT_SUCCESS(status)) { ! 1496: ! 1497: audioOutput = ScsiClassFindModePage( outputBuffer, ! 1498: srb.DataTransferLength, ! 1499: CDROM_AUDIO_CONTROL_PAGE); ! 1500: // ! 1501: // Verify the page is as big as expected. ! 1502: // ! 1503: ! 1504: bytesTransferred = (PCHAR) audioOutput - (PCHAR) outputBuffer + ! 1505: sizeof(AUDIO_OUTPUT); ! 1506: ! 1507: if (audioOutput != NULL && ! 1508: srb.DataTransferLength >= bytesTransferred) { ! 1509: ! 1510: audioControl->LbaFormat = audioOutput->LbaFormat; ! 1511: ! 1512: audioControl->LogicalBlocksPerSecond = ! 1513: (audioOutput->LogicalBlocksPerSecond[0] << (UCHAR)8) | ! 1514: audioOutput->LogicalBlocksPerSecond[1]; ! 1515: ! 1516: Irp->IoStatus.Information = sizeof(CDROM_AUDIO_CONTROL); ! 1517: ! 1518: } else { ! 1519: status = STATUS_INVALID_DEVICE_REQUEST; ! 1520: } ! 1521: ! 1522: } ! 1523: ! 1524: ExFreePool(outputBuffer); ! 1525: } ! 1526: ! 1527: break; ! 1528: ! 1529: case IOCTL_CDROM_GET_VOLUME: ! 1530: ! 1531: DebugPrint((2, "ScsiCdRomDeviceControl: Get volume control\n")); ! 1532: ! 1533: // ! 1534: // Verify user buffer is large enough for data. ! 1535: // ! 1536: ! 1537: if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < ! 1538: sizeof(VOLUME_CONTROL)) { ! 1539: ! 1540: // ! 1541: // Indicate unsuccessful status and no data transferred. ! 1542: // ! 1543: ! 1544: status = STATUS_BUFFER_TOO_SMALL; ! 1545: Irp->IoStatus.Information = 0; ! 1546: ! 1547: } else { ! 1548: ! 1549: PAUDIO_OUTPUT audioOutput; ! 1550: PVOLUME_CONTROL volumeControl = Irp->AssociatedIrp.SystemBuffer; ! 1551: ULONG i; ! 1552: ! 1553: // ! 1554: // Allocate buffer for volume control information. ! 1555: // ! 1556: ! 1557: outputBuffer = ExAllocatePool(NonPagedPoolCacheAligned, ! 1558: MODE_DATA_SIZE); ! 1559: ! 1560: if (!outputBuffer) { ! 1561: status = STATUS_INSUFFICIENT_RESOURCES; ! 1562: Irp->IoStatus.Information = 0; ! 1563: break; ! 1564: } ! 1565: ! 1566: // ! 1567: // In case not as much as expected is returned zero ! 1568: // all of this. ! 1569: // ! 1570: ! 1571: RtlZeroMemory(outputBuffer, MODE_DATA_SIZE); ! 1572: ! 1573: // ! 1574: // Get volume control information ! 1575: // ! 1576: ! 1577: cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE; ! 1578: cdb->MODE_SENSE.PageCode = CDROM_AUDIO_CONTROL_PAGE; ! 1579: cdb->MODE_SENSE.AllocationLength = MODE_DATA_SIZE; ! 1580: ! 1581: srb.CdbLength = 6; ! 1582: ! 1583: // ! 1584: // Set timeout value. ! 1585: // ! 1586: ! 1587: srb.TimeOutValue = deviceExtension->TimeOutValue; ! 1588: ! 1589: status = ScsiClassSendSrbSynchronous(DeviceObject, ! 1590: &srb, ! 1591: outputBuffer, ! 1592: MODE_DATA_SIZE, ! 1593: FALSE); ! 1594: ! 1595: if (SRB_STATUS(srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN) { ! 1596: status = STATUS_SUCCESS; ! 1597: } ! 1598: ! 1599: if (NT_SUCCESS(status)) { ! 1600: ! 1601: audioOutput = ScsiClassFindModePage( outputBuffer, ! 1602: srb.DataTransferLength, ! 1603: CDROM_AUDIO_CONTROL_PAGE); ! 1604: ! 1605: // ! 1606: // Verify the page is as big as expected. ! 1607: // ! 1608: ! 1609: bytesTransferred = (PCHAR) audioOutput - (PCHAR) outputBuffer + ! 1610: sizeof(AUDIO_OUTPUT); ! 1611: ! 1612: if (audioOutput != NULL && ! 1613: srb.DataTransferLength >= bytesTransferred) { ! 1614: ! 1615: for (i=0; i<4; i++) { ! 1616: volumeControl->PortVolume[i] = ! 1617: audioOutput->PortOutput[i].Volume; ! 1618: } ! 1619: ! 1620: // ! 1621: // Set bytes transferred in IRP. ! 1622: // ! 1623: ! 1624: Irp->IoStatus.Information = sizeof(VOLUME_CONTROL); ! 1625: ! 1626: } else { ! 1627: status = STATUS_INVALID_DEVICE_REQUEST; ! 1628: } ! 1629: ! 1630: } ! 1631: ! 1632: // ! 1633: // Free buffer. ! 1634: // ! 1635: ! 1636: ExFreePool(outputBuffer); ! 1637: } ! 1638: ! 1639: break; ! 1640: ! 1641: case IOCTL_CDROM_SET_VOLUME: ! 1642: ! 1643: DebugPrint((2, "ScsiCdRomDeviceControl: Set volume control\n")); ! 1644: ! 1645: { ! 1646: ! 1647: PAUDIO_OUTPUT audioOutput; ! 1648: PAUDIO_OUTPUT audioInput; ! 1649: PVOID inputBuffer; ! 1650: PVOLUME_CONTROL volumeControl = Irp->AssociatedIrp.SystemBuffer; ! 1651: ULONG i; ! 1652: ! 1653: if (irpStack->Parameters.DeviceIoControl.InputBufferLength < ! 1654: sizeof(VOLUME_CONTROL)) { ! 1655: ! 1656: // ! 1657: // Indicate unsuccessful status. ! 1658: // ! 1659: ! 1660: status = STATUS_BUFFER_TOO_SMALL; ! 1661: break; ! 1662: } ! 1663: ! 1664: // ! 1665: // Get the current audio contorl information so that the ! 1666: // port control information can be filled in. ! 1667: // Allocate buffer for volume control information. ! 1668: // ! 1669: ! 1670: inputBuffer = ExAllocatePool(NonPagedPoolCacheAligned, ! 1671: MODE_DATA_SIZE); ! 1672: ! 1673: if (!inputBuffer) { ! 1674: status = STATUS_INSUFFICIENT_RESOURCES; ! 1675: Irp->IoStatus.Information = 0; ! 1676: break; ! 1677: } ! 1678: ! 1679: // ! 1680: // In case not as much as expected is returned zero ! 1681: // all of this. ! 1682: // ! 1683: ! 1684: RtlZeroMemory(inputBuffer, MODE_DATA_SIZE); ! 1685: ! 1686: // ! 1687: // Get volume control information ! 1688: // ! 1689: ! 1690: cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE; ! 1691: cdb->MODE_SENSE.PageCode = CDROM_AUDIO_CONTROL_PAGE; ! 1692: cdb->MODE_SENSE.AllocationLength = MODE_DATA_SIZE; ! 1693: ! 1694: srb.CdbLength = 6; ! 1695: ! 1696: // ! 1697: // Set timeout value. ! 1698: // ! 1699: ! 1700: srb.TimeOutValue = deviceExtension->TimeOutValue; ! 1701: ! 1702: status = ScsiClassSendSrbSynchronous(DeviceObject, ! 1703: &srb, ! 1704: inputBuffer, ! 1705: MODE_DATA_SIZE, ! 1706: FALSE); ! 1707: ! 1708: if (SRB_STATUS(srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN) { ! 1709: status = STATUS_SUCCESS; ! 1710: } ! 1711: ! 1712: if (NT_SUCCESS(status)) { ! 1713: ! 1714: audioInput = ScsiClassFindModePage( inputBuffer, ! 1715: srb.DataTransferLength, ! 1716: CDROM_AUDIO_CONTROL_PAGE); ! 1717: ! 1718: if (audioInput == NULL) { ! 1719: status = STATUS_INVALID_DEVICE_REQUEST; ! 1720: } ! 1721: ! 1722: // ! 1723: // Verify the page is as big as expected. ! 1724: // ! 1725: ! 1726: i = (PCHAR) audioInput - (PCHAR) inputBuffer + sizeof(AUDIO_OUTPUT); ! 1727: ! 1728: if (srb.DataTransferLength < i) { ! 1729: status = STATUS_INVALID_DEVICE_REQUEST; ! 1730: } ! 1731: ! 1732: } ! 1733: ! 1734: if (!NT_SUCCESS(status)) { ! 1735: ! 1736: // ! 1737: // Free buffer. ! 1738: // ! 1739: ! 1740: ExFreePool(inputBuffer); ! 1741: ! 1742: break; ! 1743: } ! 1744: ! 1745: // ! 1746: // Mode select buffer is the size of the audio page plus a ! 1747: // mode parameter header. ! 1748: // ! 1749: ! 1750: bytesTransferred = sizeof(AUDIO_OUTPUT) + sizeof(MODE_PARAMETER_HEADER); ! 1751: ! 1752: // ! 1753: // Allocate buffer for volume control information. ! 1754: // ! 1755: ! 1756: outputBuffer = ExAllocatePool(NonPagedPoolCacheAligned, ! 1757: bytesTransferred); ! 1758: ! 1759: if (!outputBuffer) { ! 1760: status = STATUS_INSUFFICIENT_RESOURCES; ! 1761: Irp->IoStatus.Information = 0; ! 1762: break; ! 1763: } ! 1764: ! 1765: // ! 1766: // Zero the buffer. The mode parameter header will be left as zeros. ! 1767: // Also clear the srb again. ! 1768: // ! 1769: ! 1770: RtlZeroMemory(outputBuffer, bytesTransferred); ! 1771: RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK)); ! 1772: ! 1773: // ! 1774: // Set volume control information ! 1775: // ! 1776: ! 1777: cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT; ! 1778: cdb->MODE_SELECT.ParameterListLength = (UCHAR) bytesTransferred; ! 1779: cdb->MODE_SELECT.PFBit = 1; ! 1780: ! 1781: srb.CdbLength = 6; ! 1782: ! 1783: audioOutput = (PAUDIO_OUTPUT) ((PCHAR) outputBuffer ! 1784: + sizeof(MODE_PARAMETER_HEADER)); ! 1785: ! 1786: // ! 1787: // Fill in the volume setting and the port control. ! 1788: // ! 1789: ! 1790: for (i=0; i<4; i++) { ! 1791: audioOutput->PortOutput[i].Volume = ! 1792: volumeControl->PortVolume[i]; ! 1793: audioOutput->PortOutput[i].ChannelSelection = ! 1794: audioInput->PortOutput[i].ChannelSelection; ! 1795: } ! 1796: ! 1797: audioOutput->CodePage = CDROM_AUDIO_CONTROL_PAGE; ! 1798: audioOutput->ParameterLength = sizeof(AUDIO_OUTPUT) - 2; ! 1799: audioOutput->Immediate = MODE_SELECT_IMMEDIATE; ! 1800: ! 1801: // ! 1802: // Set timeout value. ! 1803: // ! 1804: ! 1805: srb.TimeOutValue = deviceExtension->TimeOutValue; ! 1806: ! 1807: status = ScsiClassSendSrbSynchronous(DeviceObject, ! 1808: &srb, ! 1809: outputBuffer, ! 1810: bytesTransferred, ! 1811: TRUE); ! 1812: ! 1813: // ! 1814: // Set bytes transferred in IRP. ! 1815: // ! 1816: ! 1817: Irp->IoStatus.Information = sizeof(VOLUME_CONTROL); ! 1818: ! 1819: // ! 1820: // Free buffers. ! 1821: // ! 1822: ! 1823: ExFreePool(inputBuffer); ! 1824: ExFreePool(outputBuffer); ! 1825: ! 1826: break; ! 1827: } ! 1828: ! 1829: case IOCTL_CDROM_STOP_AUDIO: ! 1830: ! 1831: // ! 1832: // Stop play. ! 1833: // ! 1834: ! 1835: DebugPrint((2, "ScsiCdRomDeviceControl: Stop audio\n")); ! 1836: ! 1837: PLAY_ACTIVE(deviceExtension) = FALSE; ! 1838: ! 1839: cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT; ! 1840: ! 1841: cdb->START_STOP.Immediate = 1; ! 1842: cdb->START_STOP.Start = 0; ! 1843: cdb->START_STOP.LoadEject = 0; ! 1844: ! 1845: srb.CdbLength = 6; ! 1846: ! 1847: // ! 1848: // Set timeout value. ! 1849: // ! 1850: ! 1851: srb.TimeOutValue = deviceExtension->TimeOutValue; ! 1852: ! 1853: status = ScsiClassSendSrbSynchronous(DeviceObject, ! 1854: &srb, ! 1855: NULL, ! 1856: 0, ! 1857: FALSE); ! 1858: break; ! 1859: ! 1860: case IOCTL_CDROM_CHECK_VERIFY: ! 1861: ! 1862: srb.CdbLength = 6; ! 1863: ! 1864: cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY; ! 1865: ! 1866: // ! 1867: // Set timeout value. ! 1868: // ! 1869: ! 1870: srb.TimeOutValue = deviceExtension->TimeOutValue * 2; ! 1871: ! 1872: status = ScsiClassSendSrbSynchronous(DeviceObject, ! 1873: &srb, ! 1874: NULL, ! 1875: 0, ! 1876: FALSE); ! 1877: ! 1878: // ! 1879: // If the status is verify required, redo the test unit ready to ! 1880: // verify that the cd-rom is done spinning up. ! 1881: // ScsiClassSendSrbSynchronous will wait for a while for the device to ! 1882: // spin up. ! 1883: // ! 1884: ! 1885: if (status == STATUS_VERIFY_REQUIRED) { ! 1886: ! 1887: srb.CdbLength = 6; ! 1888: ! 1889: cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY; ! 1890: ! 1891: // ! 1892: // Set timeout value. ! 1893: // ! 1894: ! 1895: srb.TimeOutValue = deviceExtension->TimeOutValue * 2; ! 1896: ! 1897: status2 = ScsiClassSendSrbSynchronous(DeviceObject, ! 1898: &srb, ! 1899: NULL, ! 1900: 0, ! 1901: FALSE); ! 1902: ! 1903: DebugPrint((1, "ScsiCdromDeviceControl: Status from second test unit ready is: %lx\n", status2)); ! 1904: } ! 1905: ! 1906: // ! 1907: // Update the play active flag. ! 1908: // ! 1909: ! 1910: if (!CdRomIsPlayActive(DeviceObject) && ! 1911: LiEqlZero(deviceExtension->PartitionLength)) { ! 1912: ! 1913: // ! 1914: // If play is not active and the volume needs verification then ! 1915: // get read capicity again. ! 1916: // ! 1917: ! 1918: status2 = ScsiClassReadDriveCapacity(DeviceObject); ! 1919: ! 1920: if ((!NT_SUCCESS(status2)) || ! 1921: (deviceExtension->DiskGeometry->BytesPerSector == 0)) { ! 1922: ! 1923: // ! 1924: // Set disk geometry to default values (per ISO 9660). ! 1925: // ! 1926: ! 1927: deviceExtension->DiskGeometry->BytesPerSector = 2048; ! 1928: deviceExtension->SectorShift = 11; ! 1929: } ! 1930: } ! 1931: ! 1932: break; ! 1933: ! 1934: default: ! 1935: ! 1936: // ! 1937: // Pass the request to the common device control routine. ! 1938: // ! 1939: ! 1940: return(ScsiClassDeviceControl(DeviceObject, Irp)); ! 1941: ! 1942: break; ! 1943: ! 1944: } // end switch() ! 1945: ! 1946: if (status == STATUS_VERIFY_REQUIRED) { ! 1947: ! 1948: // ! 1949: // If the status is verified required and the this request ! 1950: // should bypass verify required then retry the request. ! 1951: // ! 1952: ! 1953: if (irpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME) { ! 1954: ! 1955: status = STATUS_IO_DEVICE_ERROR; ! 1956: goto RetryControl; ! 1957: ! 1958: } ! 1959: ! 1960: } ! 1961: ! 1962: if (IoIsErrorUserInduced(status)) { ! 1963: ! 1964: IoSetHardErrorOrVerifyDevice(Irp, DeviceObject); ! 1965: ! 1966: } ! 1967: ! 1968: // ! 1969: // Update IRP with completion status. ! 1970: // ! 1971: ! 1972: Irp->IoStatus.Status = status; ! 1973: ! 1974: // ! 1975: // Complete the request. ! 1976: // ! 1977: ! 1978: IoCompleteRequest(Irp, IO_DISK_INCREMENT); ! 1979: DebugPrint((2, "ScsiCdromDeviceControl: Status is %lx\n", status)); ! 1980: return status; ! 1981: ! 1982: } // end ScsiCdromDeviceControl() ! 1983: ! 1984: ! 1985: VOID ! 1986: ScanForSpecial( ! 1987: PDEVICE_OBJECT DeviceObject, ! 1988: PINQUIRYDATA InquiryData, ! 1989: PIO_SCSI_CAPABILITIES PortCapabilities ! 1990: ) ! 1991: ! 1992: /*++ ! 1993: ! 1994: Routine Description: ! 1995: ! 1996: This function checks to see if an SCSI logical unit requires an special ! 1997: initialization or error processing. ! 1998: ! 1999: Arguments: ! 2000: ! 2001: DeviceObject - Supplies the device object to be tested. ! 2002: ! 2003: InquiryData - Supplies the inquiry data returned by the device of interest. ! 2004: ! 2005: PortCapabilities - Supplies the capabilities of the device object. ! 2006: ! 2007: Return Value: ! 2008: ! 2009: None. ! 2010: ! 2011: --*/ ! 2012: ! 2013: { ! 2014: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; ! 2015: ! 2016: // ! 2017: // Look for a Hitachi CDR-1750. Read-ahead must be disabled in order ! 2018: // to get this cdrom drive to work on scsi adapters that use PIO. ! 2019: // ! 2020: ! 2021: if ((strncmp(InquiryData->VendorId, "HITACHI CDR-1750S", strlen("HITACHI CDR-1750S")) == 0 || ! 2022: strncmp(InquiryData->VendorId, "HITACHI CDR-3650/1650S", strlen("HITACHI CDR-3650/1650S")) == 0) ! 2023: && PortCapabilities->AdapterUsesPio) { ! 2024: ! 2025: DebugPrint((1, "ScsiCdrom ScanForSpecial: Found Hitachi CDR-1750S.\n")); ! 2026: ! 2027: // ! 2028: // Setup an error handler to reinitialize the cd rom after it is reset. ! 2029: // ! 2030: ! 2031: deviceExtension->ClassError = HitachProcessError; ! 2032: } ! 2033: ! 2034: return; ! 2035: } ! 2036: ! 2037: VOID ! 2038: HitachProcessError( ! 2039: PDEVICE_OBJECT DeviceObject, ! 2040: PSCSI_REQUEST_BLOCK Srb, ! 2041: NTSTATUS *Status, ! 2042: BOOLEAN *Retry ! 2043: ) ! 2044: /*++ ! 2045: ! 2046: Routine Description: ! 2047: ! 2048: This routine checks the type of error. If the error indicates CD-ROM the ! 2049: CD-ROM needs to be reinitialized then a Mode sense command is sent to the ! 2050: device. This command disables read-ahead for the device. ! 2051: ! 2052: Arguments: ! 2053: ! 2054: DeviceObject - Supplies a pointer to the device object. ! 2055: ! 2056: Srb - Supplies a pointer to the failing Srb. ! 2057: ! 2058: Status - Not used. ! 2059: ! 2060: Retry - Not used. ! 2061: ! 2062: Return Value: ! 2063: ! 2064: None. ! 2065: ! 2066: --*/ ! 2067: ! 2068: { ! 2069: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; ! 2070: PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer; ! 2071: LARGE_INTEGER largeInt = LiFromUlong(1); ! 2072: PUCHAR modePage; ! 2073: PIO_STACK_LOCATION irpStack; ! 2074: PIRP irp; ! 2075: PSCSI_REQUEST_BLOCK srb; ! 2076: PCOMPLETION_CONTEXT context; ! 2077: PCDB cdb; ! 2078: ULONG alignment; ! 2079: ! 2080: UNREFERENCED_PARAMETER(Status); ! 2081: UNREFERENCED_PARAMETER(Retry); ! 2082: ! 2083: // ! 2084: // Check the status. The initialization command only needs to be sent ! 2085: // if UNIT ATTENTION is returned. ! 2086: // ! 2087: ! 2088: if (!(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID)) { ! 2089: ! 2090: // ! 2091: // The drive does not require reinitialization. ! 2092: // ! 2093: ! 2094: return; ! 2095: } ! 2096: ! 2097: // ! 2098: // Found a bad HITACHI cd-rom. These devices do not work with PIO ! 2099: // adapters when read-ahead is enabled. Read-ahead is disabled by ! 2100: // a mode select command. The mode select page code is zero and the ! 2101: // length is 6 bytes. All of the other bytes should be zero. ! 2102: // ! 2103: ! 2104: ! 2105: if ((senseBuffer->SenseKey & 0xf) == SCSI_SENSE_UNIT_ATTENTION) { ! 2106: ! 2107: DebugPrint((1, "HitachiProcessError: Reinitializing the CD-ROM.\n")); ! 2108: ! 2109: // ! 2110: // Send the special mode select command to disable read-ahead ! 2111: // on the CD-ROM reader. ! 2112: // ! 2113: ! 2114: alignment = DeviceObject->AlignmentRequirement ? ! 2115: DeviceObject->AlignmentRequirement : 1; ! 2116: ! 2117: context = ExAllocatePool( ! 2118: NonPagedPool, ! 2119: sizeof(COMPLETION_CONTEXT) + HITACHI_MODE_DATA_SIZE + alignment ! 2120: ); ! 2121: ! 2122: if (context == NULL) { ! 2123: ! 2124: // ! 2125: // If there is not enough memory to fulfill this request, ! 2126: // simply return. A subsequent retry will fail and another ! 2127: // chance to start the unit. ! 2128: // ! 2129: ! 2130: return; ! 2131: } ! 2132: ! 2133: context->DeviceObject = DeviceObject; ! 2134: srb = &context->Srb; ! 2135: ! 2136: RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE); ! 2137: ! 2138: // ! 2139: // Write length to SRB. ! 2140: // ! 2141: ! 2142: srb->Length = SCSI_REQUEST_BLOCK_SIZE; ! 2143: ! 2144: // ! 2145: // Set up SCSI bus address. ! 2146: // ! 2147: ! 2148: srb->PathId = deviceExtension->PathId; ! 2149: srb->TargetId = deviceExtension->TargetId; ! 2150: srb->Lun = deviceExtension->Lun; ! 2151: ! 2152: srb->Function = SRB_FUNCTION_EXECUTE_SCSI; ! 2153: srb->TimeOutValue = deviceExtension->TimeOutValue; ! 2154: ! 2155: // ! 2156: // Set the transfer length. ! 2157: // ! 2158: ! 2159: srb->DataTransferLength = HITACHI_MODE_DATA_SIZE; ! 2160: srb->SrbFlags = SRB_FLAGS_DATA_OUT | SRB_FLAGS_DISABLE_AUTOSENSE | SRB_FLAGS_DISABLE_SYNCH_TRANSFER; ! 2161: ! 2162: // ! 2163: // The data buffer must be aligned. ! 2164: // ! 2165: ! 2166: srb->DataBuffer = (PVOID) (((ULONG) (context + 1) + (alignment - 1)) & ! 2167: ~(alignment - 1)); ! 2168: ! 2169: ! 2170: // ! 2171: // Build the HITACHI read-ahead mode select CDB. ! 2172: // ! 2173: ! 2174: srb->CdbLength = 6; ! 2175: cdb = (PCDB)srb->Cdb; ! 2176: cdb->MODE_SENSE.LogicalUnitNumber = srb->Lun; ! 2177: cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SELECT; ! 2178: cdb->MODE_SENSE.AllocationLength = HITACHI_MODE_DATA_SIZE; ! 2179: ! 2180: // ! 2181: // Initialize the mode sense data. ! 2182: // ! 2183: ! 2184: modePage = srb->DataBuffer; ! 2185: ! 2186: RtlZeroMemory(modePage, HITACHI_MODE_DATA_SIZE); ! 2187: ! 2188: // ! 2189: // Set the page length field to 6. ! 2190: // ! 2191: ! 2192: modePage[5] = 6; ! 2193: ! 2194: // ! 2195: // Build the asynchronous request to be sent to the port driver. ! 2196: // ! 2197: ! 2198: irp = IoBuildAsynchronousFsdRequest(IRP_MJ_WRITE, ! 2199: DeviceObject, ! 2200: srb->DataBuffer, ! 2201: srb->DataTransferLength, ! 2202: &largeInt, ! 2203: NULL); ! 2204: ! 2205: IoSetCompletionRoutine(irp, ! 2206: (PIO_COMPLETION_ROUTINE)ScsiClassAsynchronousCompletion, ! 2207: context, ! 2208: TRUE, ! 2209: TRUE, ! 2210: TRUE); ! 2211: ! 2212: irpStack = IoGetNextIrpStackLocation(irp); ! 2213: ! 2214: irpStack->MajorFunction = IRP_MJ_SCSI; ! 2215: ! 2216: srb->OriginalRequest = irp; ! 2217: ! 2218: // ! 2219: // Save SRB address in next stack for port driver. ! 2220: // ! 2221: ! 2222: irpStack->Parameters.Scsi.Srb = (PVOID)srb; ! 2223: ! 2224: // ! 2225: // Set up IRP Address. ! 2226: // ! 2227: ! 2228: (VOID)IoCallDriver(deviceExtension->PortDeviceObject, irp); ! 2229: ! 2230: } ! 2231: } ! 2232: ! 2233: BOOLEAN ! 2234: CdRomIsPlayActive( ! 2235: IN PDEVICE_OBJECT DeviceObject ! 2236: ) ! 2237: ! 2238: /*++ ! 2239: ! 2240: Routine Description: ! 2241: ! 2242: This routine determines if the cd is currently playing music. ! 2243: ! 2244: Arguments: ! 2245: ! 2246: DeviceObject - Device object to test. ! 2247: ! 2248: Return Value: ! 2249: ! 2250: TRUE if the device is playing music. ! 2251: ! 2252: --*/ ! 2253: { ! 2254: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; ! 2255: PIRP irp; ! 2256: IO_STATUS_BLOCK ioStatus; ! 2257: KEVENT event; ! 2258: NTSTATUS status; ! 2259: PSUB_Q_CURRENT_POSITION currentBuffer; ! 2260: ! 2261: if (!PLAY_ACTIVE(deviceExtension)) { ! 2262: return(FALSE); ! 2263: } ! 2264: ! 2265: currentBuffer = ExAllocatePool(NonPagedPoolCacheAligned, sizeof(SUB_Q_CURRENT_POSITION)); ! 2266: ! 2267: if (currentBuffer == NULL) { ! 2268: return(FALSE); ! 2269: } ! 2270: ! 2271: ((PCDROM_SUB_Q_DATA_FORMAT) currentBuffer)->Format = IOCTL_CDROM_CURRENT_POSITION; ! 2272: ((PCDROM_SUB_Q_DATA_FORMAT) currentBuffer)->Track = 0; ! 2273: ! 2274: // ! 2275: // Create notification event object to be used to signal the ! 2276: // request completion. ! 2277: // ! 2278: ! 2279: KeInitializeEvent(&event, NotificationEvent, FALSE); ! 2280: ! 2281: // ! 2282: // Build the synchronous request to be sent to the port driver ! 2283: // to perform the request. ! 2284: // ! 2285: ! 2286: irp = IoBuildDeviceIoControlRequest(IOCTL_CDROM_READ_Q_CHANNEL, ! 2287: deviceExtension->DeviceObject, ! 2288: currentBuffer, ! 2289: sizeof(CDROM_SUB_Q_DATA_FORMAT), ! 2290: currentBuffer, ! 2291: sizeof(SUB_Q_CURRENT_POSITION), ! 2292: FALSE, ! 2293: &event, ! 2294: &ioStatus); ! 2295: ! 2296: if (irp == NULL) { ! 2297: ExFreePool(currentBuffer); ! 2298: return FALSE; ! 2299: } ! 2300: ! 2301: // ! 2302: // Pass request to port driver and wait for request to complete. ! 2303: // ! 2304: ! 2305: status = IoCallDriver(deviceExtension->DeviceObject, irp); ! 2306: ! 2307: if (status == STATUS_PENDING) { ! 2308: KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL); ! 2309: status = ioStatus.Status; ! 2310: } ! 2311: ! 2312: if (!NT_SUCCESS(status)) { ! 2313: ExFreePool(currentBuffer); ! 2314: return FALSE; ! 2315: } ! 2316: ! 2317: ExFreePool(currentBuffer); ! 2318: ! 2319: return(PLAY_ACTIVE(deviceExtension)); ! 2320: ! 2321: } ! 2322: ! 2323:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.