Annotation of ntddk/src/scsi/scsicdrm/cdrom.c, revision 1.1

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: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.