ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

ioctl.c
Go to the documentation of this file.
00001 /*--
00002 
00003 Copyright (C) Microsoft Corporation, 1999 - 1999
00004 
00005 Module Name:
00006 
00007     ioctl.c
00008 
00009 Abstract:
00010 
00011     The CDROM class driver tranlates IRPs to SRBs with embedded CDBs
00012     and sends them to its devices through the port driver.
00013 
00014 Environment:
00015 
00016     kernel mode only
00017 
00018 Notes:
00019 
00020     SCSI Tape, CDRom and Disk class drivers share common routines
00021     that can be found in the CLASS directory (..\ntos\dd\class).
00022 
00023 Revision History:
00024 
00025 --*/
00026 
00027 #include "stddef.h"
00028 #include "string.h"
00029 
00030 #include "ntddk.h"
00031 
00032 #include "ntddcdvd.h"
00033 #include "classpnp.h"
00034 
00035 #include "initguid.h"
00036 #include "ntddstor.h"
00037 #include "cdrom.h"
00038 
00039 
00040 #if DBG
00041     PUCHAR READ_DVD_STRUCTURE_FORMAT_STRINGS[DvdMaxDescriptor+1] = {
00042         "Physical",
00043         "Copyright",
00044         "DiskKey",
00045         "BCA",
00046         "Manufacturer",
00047         "Unknown"
00048     };
00049 #endif // DBG
00050 
00051 #define DEFAULT_CDROM_SECTORS_PER_TRACK 32
00052 #define DEFAULT_TRACKS_PER_CYLINDER     64
00053 
00054 
00055 
00056 NTSTATUS
00057 CdRomDeviceControlDispatch(
00058     IN PDEVICE_OBJECT DeviceObject,
00059     IN PIRP Irp
00060     )
00061 /*++
00062 
00063 Routine Description:
00064 
00065     This is the NT device control handler for CDROMs.
00066 
00067 Arguments:
00068 
00069     DeviceObject - for this CDROM
00070 
00071     Irp - IO Request packet
00072 
00073 Return Value:
00074 
00075     NTSTATUS
00076 
00077 --*/
00078 {
00079     PFUNCTIONAL_DEVICE_EXTENSION  fdoExtension = DeviceObject->DeviceExtension;
00080     PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
00081 
00082     PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
00083     PIO_STACK_LOCATION nextStack;
00084     PCDROM_DATA        cdData = (PCDROM_DATA)(commonExtension->DriverData);
00085 
00086     BOOLEAN            use6Byte = TEST_FLAG(cdData->XAFlags, XA_USE_6_BYTE);
00087     SCSI_REQUEST_BLOCK srb;
00088     PCDB cdb = (PCDB)srb.Cdb;
00089     PVOID outputBuffer;
00090     ULONG bytesTransferred = 0;
00091     NTSTATUS status;
00092     NTSTATUS status2;
00093     KIRQL    irql;
00094 
00095     ULONG ioctlCode;
00096     ULONG baseCode;
00097     ULONG functionCode;
00098 
00099 RetryControl:
00100 
00101     //
00102     // Zero the SRB on stack.
00103     //
00104 
00105     RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
00106 
00107     Irp->IoStatus.Information = 0;
00108 
00109     //
00110     // if this is a class driver ioctl then we need to change the base code
00111     // to IOCTL_CDROM_BASE so that the switch statement can handle it.
00112     //
00113     // WARNING - currently the scsi class ioctl function codes are between
00114     // 0x200 & 0x300.  this routine depends on that fact
00115     //
00116 
00117     ioctlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
00118     baseCode = ioctlCode >> 16;
00119     functionCode = (ioctlCode & (~0xffffc003)) >> 2;
00120 
00121     TraceLog((CdromDebugTrace,
00122                 "CdRomDeviceControl: Ioctl Code = %lx, Base Code = %lx,"
00123                 " Function Code = %lx\n",
00124                 ioctlCode,
00125                 baseCode,
00126                 functionCode
00127               ));
00128 
00129     if((functionCode >= 0x200) && (functionCode <= 0x300)) {
00130 
00131         ioctlCode = (ioctlCode & 0x0000ffff) | CTL_CODE(IOCTL_CDROM_BASE, 0, 0, 0);
00132 
00133         TraceLog((CdromDebugTrace,
00134                     "CdRomDeviceControl: Class Code - new ioctl code is %lx\n",
00135                     ioctlCode));
00136 
00137         irpStack->Parameters.DeviceIoControl.IoControlCode = ioctlCode;
00138 
00139     }
00140 
00141     switch (ioctlCode) {
00142 
00143     case IOCTL_STORAGE_GET_MEDIA_TYPES_EX: {
00144 
00145         PGET_MEDIA_TYPES  mediaTypes = Irp->AssociatedIrp.SystemBuffer;
00146         PDEVICE_MEDIA_INFO mediaInfo = &mediaTypes->MediaInfo[0];
00147         ULONG sizeNeeded;
00148 
00149         sizeNeeded = sizeof(GET_MEDIA_TYPES);
00150         
00151         //
00152         // IsMmc is static...
00153         //
00154 
00155         if (cdData->Mmc.IsMmc) {
00156             sizeNeeded += sizeof(DEVICE_MEDIA_INFO) * 1; // return two media types
00157         }
00158 
00159         //
00160         // Ensure that buffer is large enough.
00161         //
00162 
00163         if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
00164             sizeNeeded) {
00165 
00166             //
00167             // Buffer too small.
00168             //
00169 
00170             Irp->IoStatus.Information = sizeNeeded;
00171             status = STATUS_BUFFER_TOO_SMALL;
00172             break;
00173         }
00174         
00175         RtlZeroMemory(Irp->AssociatedIrp.SystemBuffer, sizeNeeded);
00176 
00177         //
00178         // ISSUE-2000/5/11-henrygab - need to update GET_MEDIA_TYPES_EX
00179         //
00180 
00181         mediaTypes->DeviceType = CdRomGetDeviceType(DeviceObject);
00182 
00183         mediaTypes->MediaInfoCount = 1;
00184         mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType = CD_ROM;
00185         mediaInfo->DeviceSpecific.RemovableDiskInfo.NumberMediaSides = 1;
00186         mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics = MEDIA_READ_ONLY;
00187         mediaInfo->DeviceSpecific.RemovableDiskInfo.Cylinders.QuadPart = fdoExtension->DiskGeometry.Cylinders.QuadPart;
00188         mediaInfo->DeviceSpecific.RemovableDiskInfo.TracksPerCylinder = fdoExtension->DiskGeometry.TracksPerCylinder;
00189         mediaInfo->DeviceSpecific.RemovableDiskInfo.SectorsPerTrack = fdoExtension->DiskGeometry.SectorsPerTrack;
00190         mediaInfo->DeviceSpecific.RemovableDiskInfo.BytesPerSector = fdoExtension->DiskGeometry.BytesPerSector;
00191 
00192         if (cdData->Mmc.IsMmc) {
00193             
00194             //
00195             // also report a removable disk
00196             //
00197             mediaTypes->MediaInfoCount += 1;
00198             
00199             mediaInfo++;
00200             mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType = RemovableMedia;
00201             mediaInfo->DeviceSpecific.RemovableDiskInfo.NumberMediaSides = 1;
00202             mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics = MEDIA_READ_WRITE;
00203             mediaInfo->DeviceSpecific.RemovableDiskInfo.Cylinders.QuadPart = fdoExtension->DiskGeometry.Cylinders.QuadPart;
00204             mediaInfo->DeviceSpecific.RemovableDiskInfo.TracksPerCylinder = fdoExtension->DiskGeometry.TracksPerCylinder;
00205             mediaInfo->DeviceSpecific.RemovableDiskInfo.SectorsPerTrack = fdoExtension->DiskGeometry.SectorsPerTrack;
00206             mediaInfo->DeviceSpecific.RemovableDiskInfo.BytesPerSector = fdoExtension->DiskGeometry.BytesPerSector;
00207             mediaInfo--;
00208         
00209         }
00210 
00211         //
00212         // Status will either be success, if media is present, or no media.
00213         // It would be optimal to base from density code and medium type, but not all devices
00214         // have values for these fields.
00215         //
00216 
00217         //
00218         // Send a TUR to determine if media is present.
00219         //
00220 
00221         srb.CdbLength = 6;
00222         cdb = (PCDB)srb.Cdb;
00223         cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
00224 
00225         //
00226         // Set timeout value.
00227         //
00228 
00229         srb.TimeOutValue = fdoExtension->TimeOutValue;
00230 
00231         status = ClassSendSrbSynchronous(DeviceObject,
00232                                          &srb,
00233                                          NULL,
00234                                          0,
00235                                          FALSE);
00236 
00237 
00238         TraceLog((CdromDebugWarning,
00239                    "CdRomDeviceControl: GET_MEDIA_TYPES status of TUR - %lx\n",
00240                    status));
00241 
00242         if (NT_SUCCESS(status)) {
00243 
00244             //
00245             // set the disk's media as current if we can write to it.
00246             //
00247 
00248             if (cdData->Mmc.IsMmc && cdData->Mmc.WriteAllowed) {
00249 
00250                 mediaInfo++;
00251                 SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics,
00252                          MEDIA_CURRENTLY_MOUNTED);
00253                 mediaInfo--;
00254 
00255 
00256             } else {
00257 
00258                 SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics,
00259                          MEDIA_CURRENTLY_MOUNTED);
00260 
00261             }
00262 
00263         }
00264 
00265         Irp->IoStatus.Information = sizeNeeded;
00266         status = STATUS_SUCCESS;
00267         break;
00268     }
00269 
00270 
00271     case IOCTL_CDROM_RAW_READ: {
00272 
00273         LARGE_INTEGER  startingOffset;
00274         ULONGLONG      transferBytes;
00275         ULONGLONG      endOffset;
00276         ULONGLONG      mdlBytes;
00277         ULONG          startingSector;
00278         PRAW_READ_INFO rawReadInfo = (PRAW_READ_INFO)irpStack->Parameters.DeviceIoControl.Type3InputBuffer;
00279 
00280         //
00281         // Ensure that XA reads are supported.
00282         //
00283 
00284         if (TEST_FLAG(cdData->XAFlags, XA_NOT_SUPPORTED)) {
00285             TraceLog((CdromDebugWarning,
00286                         "CdRomDeviceControl: XA Reads not supported. Flags (%x)\n",
00287                         cdData->XAFlags));
00288             status = STATUS_INVALID_DEVICE_REQUEST;
00289             break;
00290         }
00291 
00292         //
00293         // Check that ending sector is on disc and buffers are there and of
00294         // correct size.
00295         //
00296 
00297         if (rawReadInfo == NULL) {
00298             
00299             //
00300             // Called from user space. Save the userbuffer in the 
00301             // Type3InputBuffer so we can reduce the number of code paths.
00302             //
00303 
00304             irpStack->Parameters.DeviceIoControl.Type3InputBuffer =
00305                 Irp->AssociatedIrp.SystemBuffer;
00306 
00307             //
00308             // Called from user space.  Validate the buffers.
00309             //
00310 
00311             rawReadInfo = (PRAW_READ_INFO)irpStack->Parameters.DeviceIoControl.Type3InputBuffer;
00312 
00313             if (rawReadInfo == NULL) {
00314 
00315                 TraceLog((CdromDebugWarning,
00316                             "CdRomDeviceControl: Invalid I/O parameters for "
00317                             "XA Read (No extent info\n"));
00318                 status = STATUS_INVALID_PARAMETER;
00319                 break;
00320 
00321             }
00322 
00323             if (irpStack->Parameters.DeviceIoControl.InputBufferLength !=
00324                 sizeof(RAW_READ_INFO)) {
00325 
00326                 TraceLog((CdromDebugWarning,
00327                             "CdRomDeviceControl: Invalid I/O parameters for "
00328                             "XA Read (Invalid info buffer\n"));
00329                 status = STATUS_INVALID_PARAMETER;
00330                 break;
00331 
00332             }
00333         }
00334 
00335         //
00336         // if they don't request any data, just fail the request
00337         //
00338 
00339         if (rawReadInfo->SectorCount == 0) {
00340 
00341             status = STATUS_INVALID_PARAMETER;
00342             break;
00343 
00344         }
00345 
00346         startingOffset.QuadPart = rawReadInfo->DiskOffset.QuadPart;
00347         startingSector = (ULONG)(rawReadInfo->DiskOffset.QuadPart >>
00348                                  fdoExtension->SectorShift);
00349         transferBytes = (ULONGLONG)rawReadInfo->SectorCount * RAW_SECTOR_SIZE;
00350         
00351         endOffset = (ULONGLONG)rawReadInfo->SectorCount * COOKED_SECTOR_SIZE;
00352         endOffset += startingOffset.QuadPart;
00353 
00354         //
00355         // check for overflows....
00356         //
00357         
00358         if (transferBytes < (ULONGLONG)(rawReadInfo->SectorCount)) {
00359             TraceLog((CdromDebugWarning,
00360                         "CdRomDeviceControl: Invalid I/O parameters for XA "
00361                         "Read (TransferBytes Overflow)\n"));
00362             status = STATUS_INVALID_PARAMETER;
00363             break;
00364         }
00365         if (endOffset < (ULONGLONG)startingOffset.QuadPart) {
00366             TraceLog((CdromDebugWarning,
00367                         "CdRomDeviceControl: Invalid I/O parameters for XA "
00368                         "Read (EndingOffset Overflow)\n"));
00369             status = STATUS_INVALID_PARAMETER;
00370             break;
00371         }
00372         if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
00373             transferBytes) {
00374             TraceLog((CdromDebugWarning,
00375                         "CdRomDeviceControl: Invalid I/O parameters for XA "
00376                         "Read (Bad buffer size)\n"));
00377             status = STATUS_INVALID_PARAMETER;
00378             break;
00379         }
00380         if (endOffset > (ULONGLONG)commonExtension->PartitionLength.QuadPart) {
00381             TraceLog((CdromDebugWarning,
00382                         "CdRomDeviceControl: Invalid I/O parameters for XA "
00383                         "Read (Request Out of Bounds)\n"));
00384             status = STATUS_INVALID_PARAMETER;
00385             break;
00386         }
00387 
00388         //
00389         // cannot validate the MdlAddress, since it is not included in any
00390         // other location per the DDK and file system calls.
00391         //
00392 
00393         //
00394         // validate the mdl describes at least the number of bytes
00395         // requested from us.
00396         //
00397 
00398         mdlBytes = (ULONGLONG)MmGetMdlByteCount(Irp->MdlAddress);
00399         if (mdlBytes < transferBytes) {
00400             TraceLog((CdromDebugWarning,
00401                         "CdRomDeviceControl: Invalid MDL %s, Irp %p\n",
00402                         "size (5)", Irp));
00403             status = STATUS_INVALID_PARAMETER;
00404             break;
00405         }
00406 
00407         //
00408         // HACKHACK - REF #0001
00409         // The retry count will be in this irp's IRP_MN function,
00410         // as the new irp was freed, and we therefore cannot use
00411         // this irp's next stack location for this function.
00412         // This may be a good location to store this info for
00413         // when we remove RAW_READ (mode switching), as we will
00414         // no longer have the nextIrpStackLocation to play with
00415         // when that occurs
00416         //
00417         // once XA_READ is removed, then this hack can also be
00418         // removed.
00419         //
00420         irpStack->MinorFunction = MAXIMUM_RETRIES; // HACKHACK - REF #0001
00421 
00422         IoMarkIrpPending(Irp);
00423         IoStartPacket(DeviceObject, Irp, NULL, NULL);
00424 
00425         return STATUS_PENDING;
00426     }
00427 
00428     case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX:
00429     case IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX: {
00430         TraceLog((CdromDebugTrace,
00431                     "CdRomDeviceControl: Get drive geometryEx\n"));
00432         if ( irpStack->Parameters.DeviceIoControl.OutputBufferLength <
00433              FIELD_OFFSET(DISK_GEOMETRY_EX, Data)) {
00434             status = STATUS_BUFFER_TOO_SMALL;
00435             Irp->IoStatus.Information = FIELD_OFFSET(DISK_GEOMETRY_EX, Data);
00436             break;
00437         }
00438         IoMarkIrpPending(Irp);
00439         IoStartPacket(DeviceObject, Irp, NULL, NULL);
00440         return STATUS_PENDING;
00441     }
00442 
00443     case IOCTL_DISK_GET_DRIVE_GEOMETRY:
00444     case IOCTL_CDROM_GET_DRIVE_GEOMETRY: {
00445 
00446         TraceLog((CdromDebugTrace,
00447                     "CdRomDeviceControl: Get drive geometry\n"));
00448 
00449         if ( irpStack->Parameters.DeviceIoControl.OutputBufferLength <
00450             sizeof( DISK_GEOMETRY ) ) {
00451 
00452             status = STATUS_BUFFER_TOO_SMALL;
00453             Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
00454             break;
00455         }
00456 
00457         IoMarkIrpPending(Irp);
00458         IoStartPacket(DeviceObject, Irp, NULL, NULL);
00459 
00460         return STATUS_PENDING;
00461     }
00462 
00463     case IOCTL_CDROM_READ_TOC_EX: {
00464 
00465         PCDROM_READ_TOC_EX inputBuffer;
00466         
00467         if (CdRomIsPlayActive(DeviceObject)) {
00468             status = STATUS_DEVICE_BUSY;
00469             break;
00470         }
00471 
00472         if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
00473             sizeof(CDROM_READ_TOC_EX)) {
00474             status = STATUS_INFO_LENGTH_MISMATCH;
00475             break;
00476         }
00477 
00478         if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
00479             MINIMUM_CDROM_READ_TOC_EX_SIZE) {
00480             status = STATUS_BUFFER_TOO_SMALL;
00481             Irp->IoStatus.Information = MINIMUM_CDROM_READ_TOC_EX_SIZE;
00482             break;
00483         }
00484 
00485         if (irpStack->Parameters.Read.Length > ((USHORT)-1)) {
00486             status = STATUS_INVALID_PARAMETER;
00487             break;
00488         }
00489 
00490         inputBuffer = Irp->AssociatedIrp.SystemBuffer;
00491 
00492         if ((inputBuffer->Reserved1 != 0) ||
00493             (inputBuffer->Reserved2 != 0) ||
00494             (inputBuffer->Reserved3 != 0)) {
00495             status = STATUS_INVALID_PARAMETER;
00496             break;
00497         }
00498 
00499         //
00500         // NOTE: when adding new formats, ensure that first two bytes
00501         //       specify the amount of additional data available.
00502         //
00503 
00504         if ((inputBuffer->Format == CDROM_READ_TOC_EX_FORMAT_TOC     ) ||
00505             (inputBuffer->Format == CDROM_READ_TOC_EX_FORMAT_FULL_TOC) ||
00506             (inputBuffer->Format == CDROM_READ_TOC_EX_FORMAT_CDTEXT  )) {
00507             
00508             // SessionTrack field is used
00509 
00510         } else
00511         if ((inputBuffer->Format == CDROM_READ_TOC_EX_FORMAT_SESSION) ||
00512             (inputBuffer->Format == CDROM_READ_TOC_EX_FORMAT_PMA)     ||
00513             (inputBuffer->Format == CDROM_READ_TOC_EX_FORMAT_ATIP)) {
00514             
00515             // SessionTrack field is reserved
00516             
00517             if (inputBuffer->SessionTrack != 0) {
00518                 status = STATUS_INVALID_PARAMETER;
00519                 break;
00520             }
00521             
00522         } else {
00523             status = STATUS_INVALID_PARAMETER;
00524             break;
00525         }
00526 
00527         IoMarkIrpPending(Irp);
00528         IoStartPacket(DeviceObject, Irp, NULL, NULL);
00529         return STATUS_PENDING;
00530     }
00531 
00532     case IOCTL_CDROM_GET_LAST_SESSION: {
00533 
00534         //
00535         // If the cd is playing music then reject this request.
00536         //
00537 
00538         if (CdRomIsPlayActive(DeviceObject)) {
00539             status = STATUS_DEVICE_BUSY;
00540             break;
00541         }
00542 
00543         //
00544         // Make sure the caller is requesting enough data to make this worth
00545         // our while.
00546         //
00547 
00548         if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
00549             sizeof(CDROM_TOC_SESSION_DATA)) {
00550 
00551             //
00552             // they didn't request the entire TOC -- use _EX version
00553             // for partial transfers and such.
00554             //
00555 
00556             status = STATUS_BUFFER_TOO_SMALL;
00557             Irp->IoStatus.Information = sizeof(CDROM_TOC_SESSION_DATA);
00558             break;
00559         }
00560 
00561         IoMarkIrpPending(Irp);
00562         IoStartPacket(DeviceObject, Irp, NULL, NULL);
00563 
00564         return STATUS_PENDING;
00565     }
00566 
00567     case IOCTL_CDROM_READ_TOC:  {
00568 
00569         //
00570         // If the cd is playing music then reject this request.
00571         //
00572 
00573         if (CdRomIsPlayActive(DeviceObject)) {
00574             status = STATUS_DEVICE_BUSY;
00575             break;
00576         }
00577 
00578         //
00579         // Make sure the caller is requesting enough data to make this worth
00580         // our while.
00581         //
00582 
00583         if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
00584             sizeof(CDROM_TOC)) {
00585 
00586             //
00587             // they didn't request the entire TOC -- use _EX version
00588             // for partial transfers and such.
00589             //
00590 
00591             status = STATUS_BUFFER_TOO_SMALL;
00592             Irp->IoStatus.Information = sizeof(CDROM_TOC);
00593             break;
00594         }
00595 
00596         IoMarkIrpPending(Irp);
00597         IoStartPacket(DeviceObject, Irp, NULL, NULL);
00598 
00599         return STATUS_PENDING;
00600     }
00601 
00602     case IOCTL_CDROM_PLAY_AUDIO_MSF: {
00603 
00604         //
00605         // Play Audio MSF
00606         //
00607 
00608         TraceLog((CdromDebugTrace,
00609                     "CdRomDeviceControl: Play audio MSF\n"));
00610 
00611         if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
00612             sizeof(CDROM_PLAY_AUDIO_MSF)) {
00613 
00614             //
00615             // Indicate unsuccessful status.
00616             //
00617 
00618             status = STATUS_INFO_LENGTH_MISMATCH;
00619             break;
00620         }
00621 
00622         IoMarkIrpPending(Irp);
00623         IoStartPacket(DeviceObject, Irp, NULL, NULL);
00624 
00625         return STATUS_PENDING;
00626     }
00627 
00628     case IOCTL_CDROM_SEEK_AUDIO_MSF: {
00629 
00630 
00631         //
00632         // Seek Audio MSF
00633         //
00634 
00635         TraceLog((CdromDebugTrace,
00636                     "CdRomDeviceControl: Seek audio MSF\n"));
00637 
00638         if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
00639             sizeof(CDROM_SEEK_AUDIO_MSF)) {
00640 
00641             //
00642             // Indicate unsuccessful status.
00643             //
00644 
00645             status = STATUS_INFO_LENGTH_MISMATCH;
00646             break;
00647         }
00648         
00649         IoMarkIrpPending(Irp);
00650         IoStartPacket(DeviceObject, Irp, NULL, NULL);
00651         return STATUS_PENDING;
00652 
00653     }
00654 
00655     case IOCTL_CDROM_PAUSE_AUDIO: {
00656 
00657         //
00658         // Pause audio
00659         //
00660 
00661         TraceLog((CdromDebugTrace,
00662                     "CdRomDeviceControl: Pause audio\n"));
00663 
00664         IoMarkIrpPending(Irp);
00665         IoStartPacket(DeviceObject, Irp, NULL, NULL);
00666 
00667         return STATUS_PENDING;
00668 
00669         break;
00670     }
00671 
00672     case IOCTL_CDROM_RESUME_AUDIO: {
00673 
00674         //
00675         // Resume audio
00676         //
00677 
00678         TraceLog((CdromDebugTrace,
00679                     "CdRomDeviceControl: Resume audio\n"));
00680 
00681         IoMarkIrpPending(Irp);
00682         IoStartPacket(DeviceObject, Irp, NULL, NULL);
00683 
00684         return STATUS_PENDING;
00685     }
00686 
00687     case IOCTL_CDROM_READ_Q_CHANNEL: {
00688 
00689         PCDROM_SUB_Q_DATA_FORMAT inputBuffer =
00690                          Irp->AssociatedIrp.SystemBuffer;
00691 
00692         if(irpStack->Parameters.DeviceIoControl.InputBufferLength <
00693             sizeof(CDROM_SUB_Q_DATA_FORMAT)) {
00694 
00695             status = STATUS_INFO_LENGTH_MISMATCH;
00696             break;
00697         }
00698 
00699         //
00700         // check for all valid types of request
00701         //
00702 
00703         if (inputBuffer->Format != IOCTL_CDROM_CURRENT_POSITION &&
00704             inputBuffer->Format != IOCTL_CDROM_MEDIA_CATALOG &&
00705             inputBuffer->Format != IOCTL_CDROM_TRACK_ISRC ) {
00706             status = STATUS_INVALID_PARAMETER;
00707             Irp->IoStatus.Information = 0;
00708             break;
00709         }
00710 
00711         IoMarkIrpPending(Irp);
00712         IoStartPacket(DeviceObject, Irp, NULL, NULL);
00713 
00714         return STATUS_PENDING;
00715     }
00716 
00717     case IOCTL_CDROM_GET_CONTROL: {
00718 
00719         TraceLog((CdromDebugTrace,
00720                     "CdRomDeviceControl: Get audio control\n"));
00721 
00722         //
00723         // Verify user buffer is large enough for the data.
00724         //
00725 
00726         if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
00727             sizeof(CDROM_AUDIO_CONTROL)) {
00728 
00729             //
00730             // Indicate unsuccessful status and no data transferred.
00731             //
00732 
00733             status = STATUS_BUFFER_TOO_SMALL;
00734             Irp->IoStatus.Information = sizeof(CDROM_AUDIO_CONTROL);
00735             break;
00736 
00737         }
00738 
00739         IoMarkIrpPending(Irp);
00740         IoStartPacket(DeviceObject, Irp, NULL, NULL);
00741 
00742         return STATUS_PENDING;
00743     }
00744 
00745     case IOCTL_CDROM_GET_VOLUME: {
00746 
00747         TraceLog((CdromDebugTrace,
00748                     "CdRomDeviceControl: Get volume control\n"));
00749 
00750         //
00751         // Verify user buffer is large enough for data.
00752         //
00753 
00754         if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
00755             sizeof(VOLUME_CONTROL)) {
00756 
00757             //
00758             // Indicate unsuccessful status and no data transferred.
00759             //
00760 
00761             status = STATUS_BUFFER_TOO_SMALL;
00762             Irp->IoStatus.Information = sizeof(VOLUME_CONTROL);
00763             break;
00764 
00765         }
00766 
00767         IoMarkIrpPending(Irp);
00768         IoStartPacket(DeviceObject, Irp, NULL, NULL);
00769 
00770         return STATUS_PENDING;
00771     }
00772 
00773     case IOCTL_CDROM_SET_VOLUME: {
00774 
00775         TraceLog((CdromDebugTrace,
00776                     "CdRomDeviceControl: Set volume control\n"));
00777 
00778         if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
00779             sizeof(VOLUME_CONTROL)) {
00780 
00781             //
00782             // Indicate unsuccessful status.
00783             //
00784 
00785             status = STATUS_INFO_LENGTH_MISMATCH;
00786             break;
00787 
00788         }
00789 
00790         IoMarkIrpPending(Irp);
00791         IoStartPacket(DeviceObject, Irp, NULL, NULL);
00792 
00793         return STATUS_PENDING;
00794     }
00795 
00796     case IOCTL_CDROM_STOP_AUDIO: {
00797 
00798         //
00799         // Stop play.
00800         //
00801 
00802         TraceLog((CdromDebugTrace,
00803                     "CdRomDeviceControl: Stop audio\n"));
00804 
00805         IoMarkIrpPending(Irp);
00806         IoStartPacket(DeviceObject, Irp, NULL, NULL);
00807 
00808         return STATUS_PENDING;
00809     }
00810 
00811     case IOCTL_STORAGE_CHECK_VERIFY:
00812     case IOCTL_DISK_CHECK_VERIFY:
00813     case IOCTL_CDROM_CHECK_VERIFY: {
00814 
00815         TraceLog((CdromDebugTrace,
00816                     "CdRomDeviceControl: [%p] Check Verify\n", Irp));
00817 
00818         if((irpStack->Parameters.DeviceIoControl.OutputBufferLength) &&
00819            (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG))) {
00820 
00821            TraceLog((CdromDebugWarning,
00822                        "CdRomDeviceControl: Check Verify: media count "
00823                        "buffer too small\n"));
00824 
00825            status = STATUS_BUFFER_TOO_SMALL;
00826            Irp->IoStatus.Information = sizeof(ULONG);
00827            break;
00828         }
00829 
00830         IoMarkIrpPending(Irp);
00831         IoStartPacket(DeviceObject, Irp, NULL, NULL);
00832 
00833         return STATUS_PENDING;
00834     }
00835 
00836     case IOCTL_DVD_READ_STRUCTURE: {
00837 
00838         TraceLog((CdromDebugTrace,
00839                     "DvdDeviceControl: [%p] IOCTL_DVD_READ_STRUCTURE\n", Irp));
00840 
00841         if (cdData->DvdRpc0Device && cdData->DvdRpc0LicenseFailure) {
00842             TraceLog((CdromDebugWarning,
00843                         "DvdDeviceControl: License Failure\n"));
00844             status = STATUS_COPY_PROTECTION_FAILURE;
00845             break;
00846         }
00847 
00848         if (cdData->DvdRpc0Device && cdData->Rpc0RetryRegistryCallback) {
00849             //
00850             // if currently in-progress, this will just return.
00851             // prevents looping by doing that interlockedExchange()
00852             //
00853             TraceLog((CdromDebugWarning,
00854                         "DvdDeviceControl: PickRegion() from "
00855                         "READ_STRUCTURE\n"));
00856             CdRomPickDvdRegion(DeviceObject);
00857         }
00858 
00859 
00860         if(irpStack->Parameters.DeviceIoControl.InputBufferLength <
00861            sizeof(DVD_READ_STRUCTURE)) {
00862 
00863             TraceLog((CdromDebugWarning,
00864                         "DvdDeviceControl - READ_STRUCTURE: input buffer "
00865                         "length too small (was %d should be %d)\n",
00866                         irpStack->Parameters.DeviceIoControl.InputBufferLength,
00867                         sizeof(DVD_READ_STRUCTURE)));
00868             status = STATUS_INVALID_PARAMETER;
00869             break;
00870         }
00871 
00872         if(irpStack->Parameters.DeviceIoControl.OutputBufferLength <
00873            sizeof(READ_DVD_STRUCTURES_HEADER)) {
00874 
00875             TraceLog((CdromDebugWarning,
00876                         "DvdDeviceControl - READ_STRUCTURE: output buffer "
00877                         "cannot hold header information\n"));
00878             status = STATUS_BUFFER_TOO_SMALL;
00879             Irp->IoStatus.Information = sizeof(READ_DVD_STRUCTURES_HEADER);            
00880             break;
00881         }
00882 
00883         if(irpStack->Parameters.DeviceIoControl.OutputBufferLength >
00884            MAXUSHORT) {
00885 
00886             //
00887             // key length must fit in two bytes
00888             //
00889             TraceLog((CdromDebugWarning,
00890                         "DvdDeviceControl - READ_STRUCTURE: output buffer "
00891                         "too large\n"));
00892             status = STATUS_INVALID_PARAMETER;
00893             break;
00894         }
00895 
00896         IoMarkIrpPending(Irp);
00897         IoStartPacket(DeviceObject, Irp, NULL, NULL);
00898 
00899         return STATUS_PENDING;
00900     }
00901 
00902     case IOCTL_DVD_START_SESSION: {
00903 
00904         TraceLog((CdromDebugTrace,
00905                     "DvdDeviceControl: [%p] IOCTL_DVD_START_SESSION\n", Irp));
00906 
00907         if (cdData->DvdRpc0Device && cdData->DvdRpc0LicenseFailure) {
00908             TraceLog((CdromDebugWarning,
00909                         "DvdDeviceControl: License Failure\n"));
00910             status = STATUS_COPY_PROTECTION_FAILURE;
00911             break;
00912         }
00913 
00914         if(irpStack->Parameters.DeviceIoControl.OutputBufferLength <
00915            sizeof(DVD_SESSION_ID)) {
00916 
00917             TraceLog((CdromDebugWarning,
00918                         "DvdDeviceControl: DVD_START_SESSION - output "
00919                         "buffer too small\n"));
00920             status = STATUS_BUFFER_TOO_SMALL;
00921             Irp->IoStatus.Information = sizeof(DVD_SESSION_ID);
00922             break;
00923         }
00924 
00925         IoMarkIrpPending(Irp);
00926         IoStartPacket(DeviceObject, Irp, NULL, NULL);
00927 
00928         return STATUS_PENDING;
00929     }
00930 
00931     case IOCTL_DVD_SEND_KEY:
00932     case IOCTL_DVD_SEND_KEY2: {
00933 
00934         PDVD_COPY_PROTECT_KEY key = Irp->AssociatedIrp.SystemBuffer;
00935         ULONG keyLength;
00936 
00937         TraceLog((CdromDebugTrace,
00938                     "DvdDeviceControl: [%p] IOCTL_DVD_SEND_KEY\n", Irp));
00939 
00940         if (cdData->DvdRpc0Device && cdData->DvdRpc0LicenseFailure) {
00941             TraceLog((CdromDebugWarning,
00942                         "DvdDeviceControl: License Failure\n"));
00943             status = STATUS_COPY_PROTECTION_FAILURE;
00944             break;
00945         }
00946 
00947         if((irpStack->Parameters.DeviceIoControl.InputBufferLength <
00948             sizeof(DVD_COPY_PROTECT_KEY)) ||
00949            (irpStack->Parameters.DeviceIoControl.InputBufferLength !=
00950             key->KeyLength)) {
00951 
00952             //
00953             // Key is too small to have a header or the key length doesn't
00954             // match the input buffer length.  Key must be invalid
00955             //
00956 
00957             TraceLog((CdromDebugWarning,
00958                         "DvdDeviceControl: [%p] IOCTL_DVD_SEND_KEY - "
00959                         "key is too small or does not match KeyLength\n",
00960                         Irp));
00961             status = STATUS_INVALID_PARAMETER;
00962             break;
00963         }
00964 
00965         //
00966         // allow only certain key type (non-destructive) to go through
00967         // IOCTL_DVD_SEND_KEY (which only requires READ access to the device
00968         //
00969         if (ioctlCode == IOCTL_DVD_SEND_KEY) {
00970 
00971             if ((key->KeyType != DvdChallengeKey) &&
00972                 (key->KeyType != DvdBusKey2) &&
00973                 (key->KeyType != DvdInvalidateAGID)) {
00974 
00975                 status = STATUS_INVALID_PARAMETER;
00976                 break;
00977             }
00978         }
00979 
00980         if (cdData->DvdRpc0Device) {
00981 
00982             if (key->KeyType == DvdSetRpcKey) {
00983 
00984                 PDVD_SET_RPC_KEY rpcKey = (PDVD_SET_RPC_KEY) key->KeyData;
00985 
00986                 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
00987                     DVD_SET_RPC_KEY_LENGTH) {
00988 
00989                     status = STATUS_INVALID_PARAMETER;
00990                     break;
00991                 }
00992 
00993                 //
00994                 // we have a request to set region code
00995                 // on a RPC0 device which doesn't support
00996                 // region coding.
00997                 //
00998                 // we have to fake it.
00999                 //
01000 
01001                 KeWaitForMutexObject(
01002                     &cdData->Rpc0RegionMutex,
01003                     UserRequest,
01004                     KernelMode,
01005                     FALSE,
01006                     NULL
01007                     );
01008 
01009                 if (cdData->DvdRpc0Device && cdData->Rpc0RetryRegistryCallback) {
01010                     //
01011                     // if currently in-progress, this will just return.
01012                     // prevents looping by doing that interlockedExchange()
01013                     //
01014                     TraceLog((CdromDebugWarning,
01015                                 "DvdDeviceControl: PickRegion() from "
01016                                 "SEND_KEY\n"));
01017                     CdRomPickDvdRegion(DeviceObject);
01018                 }
01019 
01020                 if (cdData->Rpc0SystemRegion == rpcKey->PreferredDriveRegionCode) {
01021 
01022                     //
01023                     // nothing to change
01024                     //
01025                     TraceLog((CdromDebugWarning,
01026                                 "DvdDeviceControl (%p) => not changing "
01027                                 "regions -- requesting current region\n",
01028                                 DeviceObject));
01029                     status = STATUS_SUCCESS;
01030 
01031                 } else if (cdData->Rpc0SystemRegionResetCount == 0) {
01032 
01033                     //
01034                     // not allowed to change it again
01035                     //
01036 
01037                     TraceLog((CdromDebugWarning,
01038                                 "DvdDeviceControl (%p) => no more region "
01039                                 "changes are allowed for this device\n",
01040                                 DeviceObject));
01041                     status = STATUS_CSS_RESETS_EXHAUSTED;
01042 
01043                 } else {
01044 
01045                     ULONG i;
01046                     UCHAR mask;
01047                     ULONG bufferLen;
01048                     PDVD_READ_STRUCTURE dvdReadStructure;
01049                     PDVD_COPYRIGHT_DESCRIPTOR dvdCopyRight;
01050                     IO_STATUS_BLOCK ioStatus;
01051                     UCHAR mediaRegionData;
01052 
01053                     mask = ~rpcKey->PreferredDriveRegionCode;
01054 
01055                     if (CountOfSetBitsUChar(mask) != 1) {
01056 
01057                         status = STATUS_INVALID_DEVICE_REQUEST;
01058                         break;
01059                     }
01060 
01061                     //
01062                     // this test will always be TRUE except during initial
01063                     // automatic selection of the first region.
01064                     //
01065 
01066                     if (cdData->Rpc0SystemRegion != 0xff) {
01067 
01068                         //
01069                         // make sure we have a media in the drive with the same
01070                         // region code if the drive is already has a region set
01071                         //
01072 
01073                         TraceLog((CdromDebugTrace,
01074                                     "DvdDeviceControl (%p) => Checking "
01075                                     "media region\n",
01076                                     DeviceObject));
01077 
01078                         bufferLen = max(sizeof(DVD_DESCRIPTOR_HEADER) +
01079                                             sizeof(DVD_COPYRIGHT_DESCRIPTOR),
01080                                         sizeof(DVD_READ_STRUCTURE)
01081                                         );
01082 
01083                         dvdReadStructure = (PDVD_READ_STRUCTURE)
01084                             ExAllocatePoolWithTag(PagedPool,
01085                                                   bufferLen,
01086                                                   DVD_TAG_RPC2_CHECK);
01087 
01088                         if (dvdReadStructure == NULL) {
01089                             status = STATUS_INSUFFICIENT_RESOURCES;
01090                             KeReleaseMutex(&cdData->Rpc0RegionMutex,FALSE);
01091                             break;
01092                         }
01093 
01094                         dvdCopyRight = (PDVD_COPYRIGHT_DESCRIPTOR)
01095                             ((PDVD_DESCRIPTOR_HEADER) dvdReadStructure)->Data;
01096 
01097                         //
01098                         // check to see if we have a DVD device
01099                         //
01100 
01101                         RtlZeroMemory (dvdReadStructure, bufferLen);
01102                         dvdReadStructure->Format = DvdCopyrightDescriptor;
01103 
01104                         //
01105                         // Build a request for READ_KEY
01106                         //
01107                         ClassSendDeviceIoControlSynchronous(
01108                             IOCTL_DVD_READ_STRUCTURE,
01109                             DeviceObject,
01110                             dvdReadStructure,
01111                             sizeof(DVD_READ_STRUCTURE),
01112                             sizeof(DVD_DESCRIPTOR_HEADER) +
01113                                 sizeof(DVD_COPYRIGHT_DESCRIPTOR),
01114                             FALSE,
01115                             &ioStatus);
01116 
01117                         //
01118                         // this is just to prevent bugs from creeping in
01119                         // if status is not set later in development
01120                         //
01121 
01122                         status = ioStatus.Status;
01123 
01124                         //
01125                         // handle errors
01126                         //
01127 
01128                         if (!NT_SUCCESS(status)) {
01129                             KeReleaseMutex(&cdData->Rpc0RegionMutex,FALSE);
01130                             ExFreePool(dvdReadStructure);
01131                             status = STATUS_INVALID_DEVICE_REQUEST;
01132                             break;
01133                         }
01134 
01135                         //
01136                         // save the mediaRegionData before freeing the
01137                         // allocated memory
01138                         //
01139 
01140                         mediaRegionData =
01141                             dvdCopyRight->RegionManagementInformation;
01142                         ExFreePool(dvdReadStructure);
01143 
01144                         TraceLog((CdromDebugWarning,
01145                                     "DvdDeviceControl (%p) => new mask is %x"
01146                                     " MediaRegionData is %x\n", DeviceObject,
01147                                     rpcKey->PreferredDriveRegionCode,
01148                                     mediaRegionData));
01149 
01150                         //
01151                         // the media region must match the requested region
01152                         // for RPC0 drives for initial region selection
01153                         //
01154 
01155                         if (((UCHAR)~(mediaRegionData | rpcKey->PreferredDriveRegionCode)) == 0) {
01156                             KeReleaseMutex(&cdData->Rpc0RegionMutex,FALSE);
01157                             status = STATUS_CSS_REGION_MISMATCH;
01158                             break;
01159                         }
01160 
01161                     }
01162 
01163                     //
01164                     // now try to set the region
01165                     //
01166 
01167                     TraceLog((CdromDebugTrace,
01168                                 "DvdDeviceControl (%p) => Soft-Setting "
01169                                 "region of RPC1 device to %x\n",
01170                                 DeviceObject,
01171                                 rpcKey->PreferredDriveRegionCode
01172                                 ));
01173 
01174                     status = CdRomSetRpc0Settings(DeviceObject,
01175                                                   rpcKey->PreferredDriveRegionCode);
01176 
01177                     if (!NT_SUCCESS(status)) {
01178                         TraceLog((CdromDebugWarning,
01179                                     "DvdDeviceControl (%p) => Could not "
01180                                     "set region code (%x)\n",
01181                                     DeviceObject, status
01182                                     ));
01183                     } else {
01184 
01185                         TraceLog((CdromDebugTrace,
01186                                     "DvdDeviceControl (%p) => New region set "
01187                                     " for RPC1 drive\n", DeviceObject));
01188 
01189                         //
01190                         // if it worked, our extension is already updated.
01191                         // release the mutex
01192                         //
01193 
01194                         DebugPrint ((4, "DvdDeviceControl (%p) => DVD current "
01195                                      "region bitmap  0x%x\n", DeviceObject,
01196                                      cdData->Rpc0SystemRegion));
01197                         DebugPrint ((4, "DvdDeviceControl (%p) => DVD region "
01198                                      " reset Count     0x%x\n", DeviceObject,
01199                                      cdData->Rpc0SystemRegionResetCount));
01200                     }
01201 
01202                 }
01203 
01204                 KeReleaseMutex(&cdData->Rpc0RegionMutex,FALSE);
01205                 break;
01206             } // end of key->KeyType == DvdSetRpcKey
01207         } // end of Rpc0Device hacks
01208 
01209         IoMarkIrpPending(Irp);
01210         IoStartPacket(DeviceObject, Irp, NULL, NULL);
01211         return STATUS_PENDING;
01212         break;
01213     }
01214 
01215     case IOCTL_DVD_READ_KEY: {
01216 
01217         PDVD_COPY_PROTECT_KEY keyParameters = Irp->AssociatedIrp.SystemBuffer;
01218         ULONG keyLength;
01219 
01220         TraceLog((CdromDebugTrace,
01221                     "DvdDeviceControl: [%p] IOCTL_DVD_READ_KEY\n", Irp));
01222 
01223         if (cdData->DvdRpc0Device && cdData->DvdRpc0LicenseFailure) {
01224             TraceLog((CdromDebugWarning,
01225                         "DvdDeviceControl: License Failure\n"));
01226             status = STATUS_COPY_PROTECTION_FAILURE;
01227             break;
01228         }
01229 
01230         if (cdData->DvdRpc0Device && cdData->Rpc0RetryRegistryCallback) {
01231             TraceLog((CdromDebugWarning,
01232                         "DvdDeviceControl: PickRegion() from READ_KEY\n"));
01233             CdRomPickDvdRegion(DeviceObject);
01234         }
01235 
01236 
01237         if(irpStack->Parameters.DeviceIoControl.InputBufferLength <
01238             sizeof(DVD_COPY_PROTECT_KEY)) {
01239 
01240             TraceLog((CdromDebugWarning,
01241                         "DvdDeviceControl: EstablishDriveKey - challenge "
01242                         "key buffer too small\n"));
01243 
01244             status = STATUS_INVALID_PARAMETER;
01245             break;
01246 
01247         }
01248 
01249 
01250         switch(keyParameters->KeyType) {
01251 
01252             case DvdChallengeKey:
01253                 keyLength = DVD_CHALLENGE_KEY_LENGTH;
01254                 break;
01255 
01256             case DvdBusKey1:
01257             case DvdBusKey2:
01258 
01259                 keyLength = DVD_BUS_KEY_LENGTH;
01260                 break;
01261 
01262             case DvdTitleKey:
01263                 keyLength = DVD_TITLE_KEY_LENGTH;
01264                 break;
01265 
01266             case DvdAsf:
01267                 keyLength = DVD_ASF_LENGTH;
01268                 break;
01269 
01270             case DvdDiskKey:
01271                 keyLength = DVD_DISK_KEY_LENGTH;
01272                 break;
01273 
01274             case DvdGetRpcKey:
01275                 keyLength = DVD_RPC_KEY_LENGTH;
01276                 break;
01277 
01278             default:
01279                 keyLength = sizeof(DVD_COPY_PROTECT_KEY);
01280                 break;
01281         }
01282 
01283         if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
01284             keyLength) {
01285 
01286             TraceLog((CdromDebugWarning,
01287                         "DvdDeviceControl: EstablishDriveKey - output "
01288                         "buffer too small\n"));
01289             status = STATUS_BUFFER_TOO_SMALL;
01290             Irp->IoStatus.Information = keyLength;
01291             break;
01292         }
01293 
01294         if (keyParameters->KeyType == DvdGetRpcKey) {
01295 
01296             CdRomPickDvdRegion(DeviceObject);
01297         }
01298 
01299         if ((keyParameters->KeyType == DvdGetRpcKey) &&
01300             (cdData->DvdRpc0Device)) {
01301 
01302             PDVD_RPC_KEY rpcKey;
01303             rpcKey = (PDVD_RPC_KEY)keyParameters->KeyData;
01304             RtlZeroMemory (rpcKey, sizeof (*rpcKey));
01305 
01306             KeWaitForMutexObject(
01307                 &cdData->Rpc0RegionMutex,
01308                 UserRequest,
01309                 KernelMode,
01310                 FALSE,
01311                 NULL
01312                 );
01313 
01314             //
01315             // make up the data
01316             //
01317             rpcKey->UserResetsAvailable = cdData->Rpc0SystemRegionResetCount;
01318             rpcKey->ManufacturerResetsAvailable = 0;
01319             if (cdData->Rpc0SystemRegion == 0xff) {
01320                 rpcKey->TypeCode = 0;
01321             } else {
01322                 rpcKey->TypeCode = 1;
01323             }
01324             rpcKey->RegionMask = (UCHAR) cdData->Rpc0SystemRegion;
01325             rpcKey->RpcScheme = 1;
01326 
01327             KeReleaseMutex(
01328                 &cdData->Rpc0RegionMutex,
01329                 FALSE
01330                 );
01331 
01332             Irp->IoStatus.Information = DVD_RPC_KEY_LENGTH;
01333             status = STATUS_SUCCESS;
01334             break;
01335 
01336         } else if (keyParameters->KeyType == DvdDiskKey) {
01337 
01338             PDVD_COPY_PROTECT_KEY keyHeader;
01339             PDVD_READ_STRUCTURE readStructureRequest;
01340 
01341             //
01342             // Special case - build a request to get the dvd structure
01343             // so we can get the disk key.
01344             //
01345 
01346             //
01347             // save the key header so we can restore the interesting
01348             // parts later
01349             //
01350 
01351             keyHeader = ExAllocatePoolWithTag(NonPagedPool,
01352                                               sizeof(DVD_COPY_PROTECT_KEY),
01353                                               DVD_TAG_READ_KEY);
01354 
01355             if(keyHeader == NULL) {
01356 
01357                 //
01358                 // Can't save the context so return an error
01359                 //
01360 
01361                 TraceLog((CdromDebugWarning,
01362                             "DvdDeviceControl - READ_KEY: unable to "
01363                             "allocate context\n"));
01364                 status = STATUS_INSUFFICIENT_RESOURCES;
01365                 break;
01366             }
01367 
01368             RtlCopyMemory(keyHeader,
01369                           Irp->AssociatedIrp.SystemBuffer,
01370                           sizeof(DVD_COPY_PROTECT_KEY));
01371 
01372             IoCopyCurrentIrpStackLocationToNext(Irp);
01373 
01374             nextStack = IoGetNextIrpStackLocation(Irp);
01375 
01376             nextStack->Parameters.DeviceIoControl.IoControlCode =
01377                 IOCTL_DVD_READ_STRUCTURE;
01378 
01379             readStructureRequest = Irp->AssociatedIrp.SystemBuffer;
01380             readStructureRequest->Format = DvdDiskKeyDescriptor;
01381             readStructureRequest->BlockByteOffset.QuadPart = 0;
01382             readStructureRequest->LayerNumber = 0;
01383             readStructureRequest->SessionId = keyHeader->SessionId;
01384 
01385             nextStack->Parameters.DeviceIoControl.InputBufferLength =
01386                 sizeof(DVD_READ_STRUCTURE);
01387 
01388             nextStack->Parameters.DeviceIoControl.OutputBufferLength =
01389                 sizeof(READ_DVD_STRUCTURES_HEADER) + sizeof(DVD_DISK_KEY_DESCRIPTOR);
01390 
01391             IoSetCompletionRoutine(Irp,
01392                                    CdRomDvdReadDiskKeyCompletion,
01393                                    (PVOID) keyHeader,
01394                                    TRUE,
01395                                    TRUE,
01396                                    TRUE);
01397 
01398             {
01399                 UCHAR uniqueAddress;
01400                 ClassAcquireRemoveLock(DeviceObject, (PIRP)&uniqueAddress);
01401                 ClassReleaseRemoveLock(DeviceObject, Irp);
01402 
01403                 IoMarkIrpPending(Irp);
01404                 IoCallDriver(commonExtension->DeviceObject, Irp);
01405                 status = STATUS_PENDING;
01406 
01407                 ClassReleaseRemoveLock(DeviceObject, (PIRP)&uniqueAddress);
01408             }
01409 
01410             return STATUS_PENDING;
01411 
01412         } else {
01413 
01414             IoMarkIrpPending(Irp);
01415             IoStartPacket(DeviceObject, Irp, NULL, NULL);
01416 
01417         }
01418         return STATUS_PENDING;
01419     }
01420 
01421     case IOCTL_DVD_END_SESSION: {
01422 
01423         PDVD_SESSION_ID sessionId = Irp->AssociatedIrp.SystemBuffer;
01424 
01425         TraceLog((CdromDebugTrace,
01426                     "DvdDeviceControl: [%p] END_SESSION\n", Irp));
01427 
01428         if (cdData->DvdRpc0Device && cdData->DvdRpc0LicenseFailure) {
01429             TraceLog((CdromDebugWarning,
01430                         "DvdDeviceControl: License Failure\n"));
01431             status = STATUS_COPY_PROTECTION_FAILURE;
01432             break;
01433         }
01434 
01435         if(irpStack->Parameters.DeviceIoControl.InputBufferLength <
01436             sizeof(DVD_SESSION_ID)) {
01437 
01438             TraceLog((CdromDebugWarning,
01439                         "DvdDeviceControl: EndSession - input buffer too "
01440                         "small\n"));
01441             status = STATUS_INVALID_PARAMETER;
01442             break;
01443         }
01444 
01445         IoMarkIrpPending(Irp);
01446 
01447         if(*sessionId == DVD_END_ALL_SESSIONS) {
01448 
01449             status = CdRomDvdEndAllSessionsCompletion(DeviceObject, Irp, NULL);
01450 
01451             if(status == STATUS_SUCCESS) {
01452 
01453                 //
01454                 // Just complete the request - it was never issued to the
01455                 // lower device
01456                 //
01457 
01458                 break;
01459 
01460             } else {
01461 
01462                 return STATUS_PENDING;
01463 
01464             }
01465         }
01466 
01467         IoStartPacket(DeviceObject, Irp, NULL, NULL);
01468 
01469         return STATUS_PENDING;
01470     }
01471 
01472     case IOCTL_DVD_GET_REGION: {
01473 
01474         PDVD_COPY_PROTECT_KEY copyProtectKey;
01475         ULONG keyLength;
01476         IO_STATUS_BLOCK ioStatus;
01477         PDVD_DESCRIPTOR_HEADER dvdHeader;
01478         PDVD_COPYRIGHT_DESCRIPTOR copyRightDescriptor;
01479         PDVD_REGION dvdRegion;
01480         PDVD_READ_STRUCTURE readStructure;
01481         PDVD_RPC_KEY rpcKey;
01482 
01483         TraceLog((CdromDebugTrace,
01484                     "DvdDeviceControl: [%p] IOCTL_DVD_GET_REGION\n", Irp));
01485 
01486         if (cdData->DvdRpc0Device && cdData->DvdRpc0LicenseFailure) {
01487             TraceLog((CdromDebugWarning,
01488                         "DvdDeviceControl: License Failure\n"));
01489             status = STATUS_COPY_PROTECTION_FAILURE;
01490             break;
01491         }
01492 
01493         if(irpStack->Parameters.DeviceIoControl.OutputBufferLength <
01494             sizeof(DVD_REGION)) {
01495 
01496             TraceLog((CdromDebugWarning,
01497                         "DvdDeviceControl: output buffer DVD_REGION too small\n"));
01498             status = STATUS_INVALID_PARAMETER;
01499             break;
01500         }
01501 
01502         //
01503         // figure out how much data buffer we need
01504         //
01505 
01506         keyLength = max(sizeof(DVD_DESCRIPTOR_HEADER) +
01507                             sizeof(DVD_COPYRIGHT_DESCRIPTOR),
01508                         sizeof(DVD_READ_STRUCTURE)
01509                         );
01510         keyLength = max(keyLength,
01511                         DVD_RPC_KEY_LENGTH
01512                         );
01513 
01514         //
01515         // round the size to nearest ULONGLONG -- why?
01516         //
01517 
01518         keyLength += sizeof(ULONGLONG) - (keyLength & (sizeof(ULONGLONG) - 1));
01519 
01520         readStructure = ExAllocatePoolWithTag(NonPagedPool,
01521                                               keyLength,
01522                                               DVD_TAG_READ_KEY);
01523         if (readStructure == NULL) {
01524             status = STATUS_INSUFFICIENT_RESOURCES;
01525             break;
01526         }
01527 
01528         RtlZeroMemory (readStructure, keyLength);
01529         readStructure->Format = DvdCopyrightDescriptor;
01530 
01531         //
01532         // Build a request for READ_STRUCTURE
01533         //
01534 
01535         ClassSendDeviceIoControlSynchronous(
01536             IOCTL_DVD_READ_STRUCTURE,
01537             DeviceObject,
01538             readStructure,
01539             keyLength,
01540             sizeof(DVD_DESCRIPTOR_HEADER) +
01541                 sizeof(DVD_COPYRIGHT_DESCRIPTOR),
01542             FALSE,
01543             &ioStatus);
01544 
01545         status = ioStatus.Status;
01546 
01547         if (!NT_SUCCESS(status)) {
01548             TraceLog((CdromDebugWarning,
01549                         "CdRomDvdGetRegion => read structure failed %x\n",
01550                         status));
01551             ExFreePool(readStructure);
01552             break;
01553         }
01554 
01555         //
01556         // we got the copyright descriptor, so now get the region if possible
01557         //
01558 
01559         dvdHeader = (PDVD_DESCRIPTOR_HEADER) readStructure;
01560         copyRightDescriptor = (PDVD_COPYRIGHT_DESCRIPTOR) dvdHeader->Data;
01561 
01562         //
01563         // the original irp's systembuffer has a copy of the info that
01564         // should be passed down in the request
01565         //
01566 
01567         dvdRegion = Irp->AssociatedIrp.SystemBuffer;
01568 
01569         dvdRegion->CopySystem = copyRightDescriptor->CopyrightProtectionType;
01570         dvdRegion->RegionData = copyRightDescriptor->RegionManagementInformation;
01571 
01572         //
01573         // now reuse the buffer to request the copy protection info
01574         //
01575 
01576         copyProtectKey = (PDVD_COPY_PROTECT_KEY) readStructure;
01577         RtlZeroMemory (copyProtectKey, DVD_RPC_KEY_LENGTH);
01578         copyProtectKey->KeyLength = DVD_RPC_KEY_LENGTH;
01579         copyProtectKey->KeyType = DvdGetRpcKey;
01580 
01581         //
01582         // send a request for READ_KEY
01583         //
01584 
01585         ClassSendDeviceIoControlSynchronous(
01586             IOCTL_DVD_READ_KEY,
01587             DeviceObject,
01588             copyProtectKey,
01589             DVD_RPC_KEY_LENGTH,
01590             DVD_RPC_KEY_LENGTH,
01591             FALSE,
01592             &ioStatus);
01593         status = ioStatus.Status;
01594 
01595         if (!NT_SUCCESS(status)) {
01596             TraceLog((CdromDebugWarning,
01597                         "CdRomDvdGetRegion => read key failed %x\n",
01598                         status));
01599             ExFreePool(readStructure);
01600             break;
01601         }
01602 
01603         //
01604         // the request succeeded.  if a supported scheme is returned,
01605         // then return the information to the caller
01606         //
01607 
01608         rpcKey = (PDVD_RPC_KEY) copyProtectKey->KeyData;
01609 
01610         if (rpcKey->RpcScheme == 1) {
01611 
01612             if (rpcKey->TypeCode) {
01613 
01614                 dvdRegion->SystemRegion = ~rpcKey->RegionMask;
01615                 dvdRegion->ResetCount = rpcKey->UserResetsAvailable;
01616 
01617             } else {
01618 
01619                 //
01620                 // the drive has not been set for any region
01621                 //
01622 
01623                 dvdRegion->SystemRegion = 0;
01624                 dvdRegion->ResetCount = rpcKey->UserResetsAvailable;
01625             }
01626             Irp->IoStatus.Information = sizeof(DVD_REGION);
01627 
01628         } else {
01629 
01630             TraceLog((CdromDebugWarning,
01631                         "CdRomDvdGetRegion => rpcKey->RpcScheme != 1\n"));
01632             status = STATUS_INVALID_DEVICE_REQUEST;
01633         }
01634 
01635         ExFreePool(readStructure);
01636         break;
01637     }
01638 
01639 
01640     case IOCTL_STORAGE_SET_READ_AHEAD: {
01641 
01642         if(irpStack->Parameters.DeviceIoControl.InputBufferLength <
01643            sizeof(STORAGE_SET_READ_AHEAD)) {
01644 
01645             TraceLog((CdromDebugWarning,
01646                         "DvdDeviceControl: SetReadAhead buffer too small\n"));
01647             status = STATUS_INVALID_PARAMETER;
01648             break;
01649         }
01650 
01651         IoMarkIrpPending(Irp);
01652         IoStartPacket(DeviceObject, Irp, NULL, NULL);
01653 
01654         return STATUS_PENDING;
01655     }
01656 
01657     case IOCTL_DISK_IS_WRITABLE: {
01658 
01659         IoMarkIrpPending(Irp);
01660         IoStartPacket(DeviceObject, Irp, NULL, NULL);
01661 
01662         return STATUS_PENDING;
01663 
01664     }
01665 
01666     case IOCTL_DISK_GET_DRIVE_LAYOUT: {
01667 
01668         ULONG size;
01669 
01670         //
01671         // we always fake zero or one partitions, and one partition
01672         // structure is included in DRIVE_LAYOUT_INFORMATION
01673         //
01674         
01675         size = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION, PartitionEntry[1]);
01676 
01677 
01678         TraceLog((CdromDebugTrace,
01679                     "CdRomDeviceControl: Get drive layout\n"));
01680         if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < size) {            
01681             status = STATUS_BUFFER_TOO_SMALL;
01682             Irp->IoStatus.Information = size;
01683             break;
01684         }
01685         
01686         IoMarkIrpPending(Irp);
01687         IoStartPacket(DeviceObject, Irp, NULL, NULL);
01688         return STATUS_PENDING;
01689 
01690 
01691     }
01692     case IOCTL_DISK_GET_DRIVE_LAYOUT_EX: {
01693         
01694         ULONG size;
01695 
01696         //
01697         // we always fake zero or one partitions, and one partition
01698         // structure is included in DRIVE_LAYOUT_INFORMATION_EX
01699         //
01700 
01701         size = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[1]);
01702 
01703         TraceLog((CdromDebugTrace,
01704                     "CdRomDeviceControl: Get drive layout ex\n"));
01705         if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < size) {            
01706             status = STATUS_BUFFER_TOO_SMALL;
01707             Irp->IoStatus.Information = size;
01708             break;
01709         }
01710 
01711         IoMarkIrpPending(Irp);
01712         IoStartPacket(DeviceObject, Irp, NULL, NULL);
01713         return STATUS_PENDING;    
01714     
01715     }
01716 
01717     
01718     case IOCTL_DISK_GET_PARTITION_INFO: {
01719 
01720         //
01721         // Check that the buffer is large enough.
01722         //
01723 
01724         if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
01725             sizeof(PARTITION_INFORMATION)) {
01726 
01727             status = STATUS_BUFFER_TOO_SMALL;
01728             Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION);
01729             break;
01730         }
01731         
01732         IoMarkIrpPending(Irp);
01733         IoStartPacket(DeviceObject, Irp, NULL, NULL);
01734         return STATUS_PENDING;
01735     
01736     }
01737     case IOCTL_DISK_GET_PARTITION_INFO_EX: {
01738 
01739         if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
01740             sizeof(PARTITION_INFORMATION_EX)) {
01741 
01742             status = STATUS_BUFFER_TOO_SMALL;
01743             Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION_EX);
01744             break;
01745         }
01746 
01747         IoMarkIrpPending(Irp);
01748         IoStartPacket(DeviceObject, Irp, NULL, NULL);
01749         return STATUS_PENDING;
01750     }
01751 
01752     case IOCTL_DISK_VERIFY: {
01753 
01754         TraceLog((CdromDebugTrace,
01755                     "IOCTL_DISK_VERIFY to device %p through irp %p\n",
01756                     DeviceObject, Irp));
01757 
01758         //
01759         // Validate buffer length.
01760         //
01761 
01762         if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
01763             sizeof(VERIFY_INFORMATION)) {
01764 
01765             status = STATUS_INFO_LENGTH_MISMATCH;
01766             break;
01767         }
01768         IoMarkIrpPending(Irp);
01769         IoStartPacket(DeviceObject, Irp, NULL, NULL);
01770         return STATUS_PENDING;
01771     }
01772 
01773     case IOCTL_DISK_GET_LENGTH_INFO: {
01774         
01775         if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
01776             sizeof(GET_LENGTH_INFORMATION)) {
01777             status = STATUS_BUFFER_TOO_SMALL;
01778             Irp->IoStatus.Information = sizeof(GET_LENGTH_INFORMATION);
01779             break;
01780         }
01781         IoMarkIrpPending(Irp);
01782         IoStartPacket(DeviceObject, Irp, NULL, NULL);
01783         return STATUS_PENDING;
01784     }
01785 
01786     case IOCTL_CDROM_GET_CONFIGURATION: {
01787 
01788         PGET_CONFIGURATION_IOCTL_INPUT inputBuffer;
01789 
01790         TraceLog((CdromDebugTrace,
01791                     "IOCTL_CDROM_GET_CONFIGURATION to via irp %p\n", Irp));
01792 
01793         //
01794         // Validate buffer length.
01795         //
01796 
01797         if (irpStack->Parameters.DeviceIoControl.InputBufferLength !=
01798             sizeof(GET_CONFIGURATION_IOCTL_INPUT)) {
01799             status = STATUS_INFO_LENGTH_MISMATCH;
01800             break;
01801         }
01802         if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
01803             sizeof(GET_CONFIGURATION_HEADER)) {
01804             status = STATUS_BUFFER_TOO_SMALL;
01805             Irp->IoStatus.Information = sizeof(GET_CONFIGURATION_HEADER);
01806             break;
01807         }
01808         if (irpStack->Parameters.DeviceIoControl.OutputBufferLength > 0xffff) {
01809             // output buffer is too large
01810             status = STATUS_INVALID_BUFFER_SIZE;
01811             break;
01812         }
01813 
01814         //
01815         // also verify the arguments are reasonable.
01816         //
01817 
01818         inputBuffer = Irp->AssociatedIrp.SystemBuffer;
01819         if (inputBuffer->Feature > 0xffff) {
01820             status = STATUS_INVALID_PARAMETER;
01821             break;
01822         }
01823         if ((inputBuffer->RequestType != SCSI_GET_CONFIGURATION_REQUEST_TYPE_ONE) &&
01824             (inputBuffer->RequestType != SCSI_GET_CONFIGURATION_REQUEST_TYPE_CURRENT) &&
01825             (inputBuffer->RequestType != SCSI_GET_CONFIGURATION_REQUEST_TYPE_ALL)) {
01826             status = STATUS_INVALID_PARAMETER;
01827             break;
01828         }
01829         if (inputBuffer->Reserved[0] || inputBuffer->Reserved[1]) {
01830             status = STATUS_INVALID_PARAMETER;
01831             break;
01832         }
01833 
01834         IoMarkIrpPending(Irp);
01835         IoStartPacket(DeviceObject, Irp, NULL, NULL);
01836         return STATUS_PENDING;
01837 
01838     }
01839 
01840     default: {
01841 
01842         BOOLEAN synchronize = (KeGetCurrentIrql() == PASSIVE_LEVEL);
01843         PKEVENT deviceControlEvent;
01844 
01845         //
01846         // If the ioctl has come in at passive level then we will synchronize
01847         // with our start-io routine when sending the ioctl.  If the ioctl
01848         // has come in at a higher interrupt level and it was not handled
01849         // above then it's unlikely to be a request for the class DLL - however
01850         // we'll still use it's common code to forward the request through.
01851         //
01852 
01853         if (synchronize) {
01854 
01855             deviceControlEvent = ExAllocatePoolWithTag(NonPagedPool,
01856                                                        sizeof(KEVENT),
01857                                                        CDROM_TAG_DC_EVENT);
01858 
01859             if (deviceControlEvent == NULL) {
01860 
01861                 //
01862                 // must complete this irp unsuccessful here
01863                 //
01864                 status = STATUS_INSUFFICIENT_RESOURCES;
01865                 break;
01866 
01867             } else {
01868 
01869                 PIO_STACK_LOCATION currentStack;
01870 
01871                 KeInitializeEvent(deviceControlEvent, NotificationEvent, FALSE);
01872 
01873                 currentStack = IoGetCurrentIrpStackLocation(Irp);
01874                 nextStack = IoGetNextIrpStackLocation(Irp);
01875 
01876                 //
01877                 // Copy the stack down a notch
01878                 //
01879 
01880                 IoCopyCurrentIrpStackLocationToNext(Irp);
01881 
01882                 IoSetCompletionRoutine(
01883                     Irp,
01884                     CdRomClassIoctlCompletion,
01885                     deviceControlEvent,
01886                     TRUE,
01887                     TRUE,
01888                     TRUE
01889                     );
01890 
01891                 IoSetNextIrpStackLocation(Irp);
01892 
01893                 Irp->IoStatus.Status = STATUS_SUCCESS;
01894                 Irp->IoStatus.Information = 0;
01895 
01896                 //
01897                 // Override volume verifies on this stack location so that we
01898                 // will be forced through the synchronization.  Once this
01899                 // location goes away we get the old value back
01900                 //
01901 
01902                 SET_FLAG(nextStack->Flags, SL_OVERRIDE_VERIFY_VOLUME);
01903 
01904                 IoStartPacket(DeviceObject, Irp, NULL, NULL);
01905 
01906                 //
01907                 // Wait for CdRomClassIoctlCompletion to set the event. This
01908                 // ensures serialization remains intact for these unhandled device
01909                 // controls.
01910                 //
01911 
01912                 KeWaitForSingleObject(
01913                     deviceControlEvent,
01914                     Executive,
01915                     KernelMode,
01916                     FALSE,
01917                     NULL);
01918 
01919                 ExFreePool(deviceControlEvent);
01920 
01921                 TraceLog((CdromDebugTrace,
01922                             "CdRomDeviceControl: irp %p synchronized\n", Irp));
01923 
01924                 status = Irp->IoStatus.Status;
01925             }
01926 
01927         } else {
01928             status = STATUS_SUCCESS;
01929         }
01930 
01931         //
01932         // If an error occured then propagate that back up - we are no longer
01933         // guaranteed synchronization and the upper layers will have to
01934         // retry.
01935         //
01936         // If no error occured, call down to the class driver directly
01937         // then start up the next request.
01938         //
01939 
01940         if (NT_SUCCESS(status)) {
01941 
01942             UCHAR uniqueAddress;
01943 
01944             //
01945             // The class device control routine will release the remove
01946             // lock for this Irp.  We need to make sure we have one
01947             // available so that it's safe to call IoStartNextPacket
01948             //
01949 
01950             if(synchronize) {
01951 
01952                 ClassAcquireRemoveLock(DeviceObject, (PIRP)&uniqueAddress);
01953 
01954             }
01955 
01956             status = ClassDeviceControl(DeviceObject, Irp);
01957 
01958             if(synchronize) {
01959                 KeRaiseIrql(DISPATCH_LEVEL, &irql);
01960                 IoStartNextPacket(DeviceObject, FALSE);
01961                 KeLowerIrql(irql);
01962                 ClassReleaseRemoveLock(DeviceObject, (PIRP)&uniqueAddress);
01963             }
01964             return status;
01965 
01966         }
01967 
01968         //
01969         // an error occurred (either STATUS_INSUFFICIENT_RESOURCES from
01970         // attempting to synchronize or  StartIo() error'd this one
01971         // out), so we need to finish the irp, which is
01972         // done at the end of this routine.
01973         //
01974         break;
01975 
01976     } // end default case
01977 
01978     } // end switch()
01979 
01980     if (status == STATUS_VERIFY_REQUIRED) {
01981 
01982         //
01983         // If the status is verified required and this request
01984         // should bypass verify required then retry the request.
01985         //
01986 
01987         if (irpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME) {
01988 
01989             status = STATUS_IO_DEVICE_ERROR;
01990             goto RetryControl;
01991 
01992         }
01993     }
01994 
01995     if (IoIsErrorUserInduced(status)) {
01996 
01997         if (Irp->Tail.Overlay.Thread) {
01998             IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
01999         }
02000 
02001     }
02002 
02003     //
02004     // Update IRP with completion status.
02005     //
02006 
02007     Irp->IoStatus.Status = status;
02008 
02009     //
02010     // Complete the request.
02011     //
02012 
02013     ClassReleaseRemoveLock(DeviceObject, Irp);
02014     ClassCompleteRequest(DeviceObject, Irp, IO_DISK_INCREMENT);
02015     TraceLog((CdromDebugTrace,
02016                 "CdRomDeviceControl: Status is %lx\n", status));
02017     return status;
02018 
02019 } // end CdRomDeviceControl()
02020 
02021 
02022 NTSTATUS
02023 CdRomClassIoctlCompletion(
02024     IN PDEVICE_OBJECT DeviceObject,
02025     IN PIRP Irp,
02026     IN PVOID Context
02027     )
02028 /*++
02029 
02030 Routine Description:
02031 
02032     This routine signals the event used by CdRomDeviceControl to synchronize
02033     class driver (and lower level driver) ioctls with cdrom's startio routine.
02034     The irp completion is short-circuited so that CdRomDeviceControlDispatch
02035     can reissue it once it wakes up.
02036 
02037 Arguments:
02038 
02039     DeviceObject - the device object
02040     Irp - the request we are synchronizing
02041     Context - a PKEVENT that we need to signal
02042 
02043 Return Value:
02044 
02045     NTSTATUS
02046 
02047 --*/
02048 {
02049     PKEVENT syncEvent = (PKEVENT) Context;
02050 
02051     TraceLog((CdromDebugTrace,
02052                 "CdRomClassIoctlCompletion: setting event for irp %p\n", Irp));
02053 
02054     //
02055     // We released the lock when we completed this request.  Reacquire it.
02056     //
02057 
02058     ClassAcquireRemoveLock(DeviceObject, Irp);
02059 
02060     KeSetEvent(syncEvent, IO_DISK_INCREMENT, FALSE);
02061 
02062     return STATUS_MORE_PROCESSING_REQUIRED;
02063 }
02064 
02065 
02066 NTSTATUS
02067 CdRomDeviceControlCompletion(
02068     IN PDEVICE_OBJECT DeviceObject,
02069     IN PIRP Irp,
02070     IN PVOID Context
02071     )
02072 {
02073     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
02074     PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
02075 
02076     PCDROM_DATA         cdData = (PCDROM_DATA)(commonExtension->DriverData);
02077     BOOLEAN             use6Byte = TEST_FLAG(cdData->XAFlags, XA_USE_6_BYTE);
02078 
02079     PIO_STACK_LOCATION  irpStack        = IoGetCurrentIrpStackLocation(Irp);
02080     PIO_STACK_LOCATION  realIrpStack;
02081     PIO_STACK_LOCATION  realIrpNextStack;
02082 
02083     PSCSI_REQUEST_BLOCK srb     = Context;
02084 
02085     PIRP                realIrp = NULL;
02086 
02087     NTSTATUS            status;
02088     BOOLEAN             retry;
02089     ULONG retryCount;
02090 
02091     //
02092     // Extract the 'real' irp from the irpstack.
02093     //
02094 
02095     realIrp = (PIRP) irpStack->Parameters.Others.Argument2;
02096     realIrpStack = IoGetCurrentIrpStackLocation(realIrp);
02097     realIrpNextStack = IoGetNextIrpStackLocation(realIrp);
02098 
02099     //
02100     // check that we've really got the correct irp
02101     //
02102 
02103     ASSERT(realIrpNextStack->Parameters.Others.Argument3 == Irp);
02104 
02105     //
02106     // Check SRB status for success of completing request.
02107     //
02108 
02109     if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
02110 
02111         ULONG retryInterval;
02112 
02113         TraceLog((CdromDebugTrace,
02114                     "CdRomDeviceControlCompletion: Irp %p, Srb %p Real Irp %p Status %lx\n",
02115                     Irp,
02116                     srb,
02117                     realIrp,
02118                     srb->SrbStatus));
02119 
02120         //
02121         // Release the queue if it is frozen.
02122         //
02123 
02124         if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
02125             TraceLog((CdromDebugTrace,
02126                         "CdRomDeviceControlCompletion: Releasing Queue\n"));
02127             ClassReleaseQueue(DeviceObject);
02128         }
02129 
02130 
02131         retry = ClassInterpretSenseInfo(DeviceObject,
02132                                         srb,
02133                                         irpStack->MajorFunction,
02134                                         irpStack->Parameters.DeviceIoControl.IoControlCode,
02135                                         MAXIMUM_RETRIES - ((ULONG)(ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1),
02136                                         &status,
02137                                         &retryInterval);
02138 
02139         TraceLog((CdromDebugTrace,
02140                     "CdRomDeviceControlCompletion: IRP will %sbe retried\n",
02141                     (retry ? "" : "not ")));
02142 
02143         //
02144         // Some of the Device Controls need special cases on non-Success status's.
02145         //
02146 
02147         if (realIrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) {
02148             if ((realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_GET_LAST_SESSION) ||
02149                 (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_READ_TOC)         ||
02150                 (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_READ_TOC_EX)      ||
02151                 (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_GET_CONTROL)      ||
02152                 (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_GET_VOLUME)) {
02153 
02154                 if (status == STATUS_DATA_OVERRUN) {
02155                     status = STATUS_SUCCESS;
02156                     retry = FALSE;
02157                 }
02158             }
02159 
02160             if (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_READ_Q_CHANNEL) {
02161                 PLAY_ACTIVE(fdoExtension) = FALSE;
02162             }
02163         }
02164 
02165         //
02166         // If the status is verified required and the this request
02167         // should bypass verify required then retry the request.
02168         //
02169 
02170         if (realIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME &&
02171             status == STATUS_VERIFY_REQUIRED) {
02172 
02173             // note: status gets overwritten here
02174             status = STATUS_IO_DEVICE_ERROR;
02175             retry = TRUE;
02176 
02177             if (((realIrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) ||
02178                  (realIrpStack->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL)
02179                 ) &&
02180                 ((realIrpStack->Parameters.DeviceIoControl.IoControlCode ==
02181                   IOCTL_CDROM_CHECK_VERIFY) ||
02182                  (realIrpStack->Parameters.DeviceIoControl.IoControlCode ==
02183                   IOCTL_STORAGE_CHECK_VERIFY) ||
02184                  (realIrpStack->Parameters.DeviceIoControl.IoControlCode ==
02185                   IOCTL_STORAGE_CHECK_VERIFY2) ||
02186                  (realIrpStack->Parameters.DeviceIoControl.IoControlCode ==
02187                   IOCTL_DISK_CHECK_VERIFY)
02188                 )
02189                ) {
02190 
02191                 //
02192                 // Update the geometry information, as the media could have
02193                 // changed. The completion routine for this will complete
02194                 // the real irp and start the next packet.
02195                 //
02196 
02197                 if (srb) {
02198                     if (srb->SenseInfoBuffer) {
02199                         ExFreePool(srb->SenseInfoBuffer);
02200                     }
02201                     if (srb->DataBuffer) {
02202                         ExFreePool(srb->DataBuffer);
02203                     }
02204                     ExFreePool(srb);
02205                     srb = NULL;
02206                 }
02207 
02208                 if (Irp->MdlAddress) {
02209                     IoFreeMdl(Irp->MdlAddress);
02210                     Irp->MdlAddress = NULL;
02211                 }
02212 
02213                 IoFreeIrp(Irp);
02214                 Irp = NULL;
02215 
02216                 status = CdRomUpdateCapacity(fdoExtension, realIrp, NULL);
02217                 TraceLog((CdromDebugTrace,
02218                             "CdRomDeviceControlCompletion: [%p] "
02219                             "CdRomUpdateCapacity completed with status %lx\n",
02220                             realIrp, status));
02221                 
02222                 //
02223                 // needed to update the capacity.
02224                 // the irp's already handed off to CdRomUpdateCapacity().
02225                 // we've already free'd the current irp.
02226                 // nothing left to do in this code path.
02227                 //
02228                 
02229                 return STATUS_MORE_PROCESSING_REQUIRED;
02230 
02231             } // end of ioctls to update capacity
02232 
02233         }
02234 
02235         //
02236         // get current retry count
02237         //
02238         retryCount = PtrToUlong(realIrpNextStack->Parameters.Others.Argument1);
02239 
02240         if (retry && retryCount) {
02241 
02242             //
02243             // update retry count
02244             //
02245             realIrpNextStack->Parameters.Others.Argument1 = UlongToPtr(retryCount-1);
02246 
02247             if (((ULONG)(ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1)) {
02248 
02249                 //
02250                 // Retry request.
02251                 //
02252 
02253                 TraceLog((CdromDebugWarning,
02254                             "Retry request %p - Calling StartIo\n", Irp));
02255 
02256 
02257                 ExFreePool(srb->SenseInfoBuffer);
02258                 if (srb->DataBuffer) {
02259                     ExFreePool(srb->DataBuffer);
02260                 }
02261                 ExFreePool(srb);
02262                 if (Irp->MdlAddress) {
02263                     IoFreeMdl(Irp->MdlAddress);
02264                 }
02265 
02266                 realIrpNextStack->Parameters.Others.Argument3 = (PVOID)-1;
02267                 IoFreeIrp(Irp);
02268 
02269                 CdRomRetryRequest(fdoExtension, realIrp, retryInterval, FALSE);
02270                 return STATUS_MORE_PROCESSING_REQUIRED;
02271             }
02272 
02273             //
02274             // Exhausted retries. Fall through and complete the request with
02275             // the appropriate status.
02276             //
02277 
02278         }
02279     } else {
02280 
02281         //
02282         // Set status for successful request.
02283         //
02284 
02285         status = STATUS_SUCCESS;
02286 
02287     }
02288 
02289 
02290     if (NT_SUCCESS(status)) {
02291         
02292         BOOLEAN b = FALSE;
02293 
02294 
02295         switch (realIrpStack->Parameters.DeviceIoControl.IoControlCode) {
02296 
02297         case IOCTL_CDROM_GET_CONFIGURATION: {
02298             RtlMoveMemory(realIrp->AssociatedIrp.SystemBuffer,
02299                           srb->DataBuffer,
02300                           srb->DataTransferLength);
02301             realIrp->IoStatus.Information = srb->DataTransferLength;
02302             break;
02303         }
02304 
02305         case IOCTL_DISK_GET_LENGTH_INFO: {
02306             
02307             PGET_LENGTH_INFORMATION lengthInfo;
02308             
02309             CdRomInterpretReadCapacity(DeviceObject,
02310                                        (PREAD_CAPACITY_DATA)srb->DataBuffer);
02311 
02312             lengthInfo = (PGET_LENGTH_INFORMATION)realIrp->AssociatedIrp.SystemBuffer;
02313             lengthInfo->Length = commonExtension->PartitionLength;
02314             realIrp->IoStatus.Information = sizeof(GET_LENGTH_INFORMATION);
02315             status = STATUS_SUCCESS;
02316             break;
02317         }
02318 
02319         case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX:
02320         case IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX: {
02321             
02322             PDISK_GEOMETRY_EX geometryEx;
02323             
02324             CdRomInterpretReadCapacity(DeviceObject,
02325                                        (PREAD_CAPACITY_DATA)srb->DataBuffer);
02326 
02327             geometryEx = (PDISK_GEOMETRY_EX)(realIrp->AssociatedIrp.SystemBuffer);
02328             geometryEx->DiskSize = commonExtension->PartitionLength;
02329             geometryEx->Geometry = fdoExtension->DiskGeometry;
02330             realIrp->IoStatus.Information =
02331                 FIELD_OFFSET(DISK_GEOMETRY_EX, Data);
02332             break;
02333         }
02334 
02335         case IOCTL_DISK_GET_DRIVE_GEOMETRY:
02336         case IOCTL_CDROM_GET_DRIVE_GEOMETRY: {
02337 
02338             PDISK_GEOMETRY geometry;
02339             
02340             CdRomInterpretReadCapacity(DeviceObject,
02341                                        (PREAD_CAPACITY_DATA)srb->DataBuffer);
02342 
02343             geometry = (PDISK_GEOMETRY)(realIrp->AssociatedIrp.SystemBuffer);
02344             *geometry = fdoExtension->DiskGeometry;
02345             realIrp->IoStatus.Information = sizeof(DISK_GEOMETRY);
02346             break;
02347         }
02348 
02349         case IOCTL_DISK_VERIFY: {
02350             //
02351             // nothing to do but return the status...
02352             //
02353             break;
02354         }
02355 
02356         case IOCTL_DISK_CHECK_VERIFY:
02357         case IOCTL_STORAGE_CHECK_VERIFY:
02358         case IOCTL_CDROM_CHECK_VERIFY: {
02359 
02360             if((realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_CHECK_VERIFY) &&
02361                (realIrpStack->Parameters.DeviceIoControl.OutputBufferLength)) {
02362 
02363                 *((PULONG)realIrp->AssociatedIrp.SystemBuffer) =
02364                     commonExtension->PartitionZeroExtension->MediaChangeCount;
02365 
02366                 realIrp->IoStatus.Information = sizeof(ULONG);
02367             } else {
02368                 realIrp->IoStatus.Information = 0;
02369             }
02370 
02371             TraceLog((CdromDebugTrace,
02372                         "CdRomDeviceControlCompletion: [%p] completing "
02373                         "CHECK_VERIFY buddy irp %p\n", realIrp, Irp));
02374             break;
02375         }
02376 
02377         case IOCTL_CDROM_READ_TOC_EX: {
02378 
02379             if (srb->DataTransferLength < MINIMUM_CDROM_READ_TOC_EX_SIZE) {
02380                 status = STATUS_INVALID_DEVICE_REQUEST;
02381                 break;
02382             }
02383 
02384             //
02385             // Copy the returned info into the user buffer.
02386             //
02387 
02388             RtlMoveMemory(realIrp->AssociatedIrp.SystemBuffer,
02389                           srb->DataBuffer,
02390                           srb->DataTransferLength);
02391 
02392             //
02393             // update information field.
02394             //
02395 
02396             realIrp->IoStatus.Information = srb->DataTransferLength;
02397             break;
02398         }
02399 
02400 
02401         case IOCTL_CDROM_GET_LAST_SESSION:
02402         case IOCTL_CDROM_READ_TOC: {
02403 
02404             //
02405             // Copy the returned info into the user buffer.
02406             //
02407 
02408             RtlMoveMemory(realIrp->AssociatedIrp.SystemBuffer,
02409                           srb->DataBuffer,
02410                           srb->DataTransferLength);
02411 
02412             //
02413             // update information field.
02414             //
02415 
02416             realIrp->IoStatus.Information = srb->DataTransferLength;
02417             break;
02418         }
02419 
02420         case IOCTL_DVD_READ_STRUCTURE: {
02421 
02422             DVD_STRUCTURE_FORMAT format = ((PDVD_READ_STRUCTURE) realIrp->AssociatedIrp.SystemBuffer)->Format;
02423 
02424             PDVD_DESCRIPTOR_HEADER header = realIrp->AssociatedIrp.SystemBuffer;
02425 
02426             FOUR_BYTE fourByte;
02427             PTWO_BYTE twoByte;
02428             UCHAR tmp;
02429 
02430             TraceLog((CdromDebugTrace,
02431                         "DvdDeviceControlCompletion - IOCTL_DVD_READ_STRUCTURE: completing irp %p (buddy %p)\n",
02432                         Irp,
02433                         realIrp));
02434 
02435             TraceLog((CdromDebugTrace,
02436                         "DvdDCCompletion - READ_STRUCTURE: descriptor format of %d\n", format));
02437 
02438             RtlMoveMemory(header,
02439                           srb->DataBuffer,
02440                           srb->DataTransferLength);
02441 
02442             //
02443             // Cook the data.  There are a number of fields that really
02444             // should be byte-swapped for the caller.
02445             //
02446 
02447             TraceLog((CdromDebugInfo,
02448                       "DvdDCCompletion - READ_STRUCTURE:\n"
02449                       "\tHeader at %p\n"
02450                       "\tDvdDCCompletion - READ_STRUCTURE: data at %p\n"
02451                       "\tDataBuffer was at %p\n"
02452                       "\tDataTransferLength was %lx\n",
02453                       header,
02454                       header->Data,
02455                       srb->DataBuffer,
02456                       srb->DataTransferLength));
02457 
02458             //
02459             // First the fields in the header
02460             //
02461 
02462             TraceLog((CdromDebugInfo, "READ_STRUCTURE: header->Length %lx -> ",
02463                            header->Length));
02464             REVERSE_SHORT(&header->Length);
02465             TraceLog((CdromDebugInfo, "%lx\n", header->Length));
02466 
02467             //
02468             // Now the fields in the descriptor
02469             //
02470 
02471             if(format == DvdPhysicalDescriptor) {
02472 
02473                 PDVD_LAYER_DESCRIPTOR layer = (PDVD_LAYER_DESCRIPTOR) &(header->Data[0]);
02474 
02475                 TraceLog((CdromDebugInfo, "READ_STRUCTURE: StartingDataSector %lx -> ",
02476                                layer->StartingDataSector));
02477                 REVERSE_LONG(&(layer->StartingDataSector));
02478                 TraceLog((CdromDebugInfo, "%lx\n", layer->StartingDataSector));
02479 
02480                 TraceLog((CdromDebugInfo, "READ_STRUCTURE: EndDataSector %lx -> ",
02481                                layer->EndDataSector));
02482                 REVERSE_LONG(&(layer->EndDataSector));
02483                 TraceLog((CdromDebugInfo, "%lx\n", layer->EndDataSector));
02484 
02485                 TraceLog((CdromDebugInfo, "READ_STRUCTURE: EndLayerZeroSector %lx -> ",
02486                                layer->EndLayerZeroSector));
02487                 REVERSE_LONG(&(layer->EndLayerZeroSector));
02488                 TraceLog((CdromDebugInfo, "%lx\n", layer->EndLayerZeroSector));
02489             }
02490 
02491             TraceLog((CdromDebugTrace, "Status is %lx\n", Irp->IoStatus.Status));
02492             TraceLog((CdromDebugTrace, "DvdDeviceControlCompletion - "
02493                         "IOCTL_DVD_READ_STRUCTURE: data transfer length of %d\n",
02494                         srb->DataTransferLength));
02495 
02496             realIrp->IoStatus.Information = srb->DataTransferLength;
02497             break;
02498         }
02499 
02500         case IOCTL_DVD_READ_KEY: {
02501 
02502             PDVD_COPY_PROTECT_KEY copyProtectKey = realIrp->AssociatedIrp.SystemBuffer;
02503 
02504             PCDVD_KEY_HEADER keyHeader = srb->DataBuffer;
02505             ULONG dataLength;
02506 
02507             ULONG transferLength =
02508                 srb->DataTransferLength -
02509                 FIELD_OFFSET(CDVD_KEY_HEADER, Data);
02510 
02511             //
02512             // Adjust the data length to ignore the two reserved bytes in the
02513             // header.
02514             //
02515 
02516             dataLength = (keyHeader->DataLength[0] << 8) +
02517                          keyHeader->DataLength[1];
02518             dataLength -= 2;
02519 
02520             //
02521             // take the minimum of the transferred length and the
02522             // length as specified in the header.
02523             //
02524 
02525             if(dataLength < transferLength) {
02526                 transferLength = dataLength;
02527             }
02528 
02529             TraceLog((CdromDebugTrace,
02530                         "DvdDeviceControlCompletion: [%p] - READ_KEY with "
02531                         "transfer length of (%d or %d) bytes\n",
02532                         Irp,
02533                         dataLength,
02534                         srb->DataTransferLength - 2));
02535 
02536             //
02537             // Copy the key data into the return buffer
02538             //
02539             if(copyProtectKey->KeyType == DvdTitleKey) {
02540 
02541                 RtlMoveMemory(copyProtectKey->KeyData,
02542                               keyHeader->Data + 1,
02543                               transferLength - 1);
02544                 copyProtectKey->KeyData[transferLength - 1] = 0;
02545 
02546                 //
02547                 // If this is a title key then we need to copy the CGMS flags
02548                 // as well.
02549                 //
02550                 copyProtectKey->KeyFlags = *(keyHeader->Data);
02551 
02552             } else {
02553 
02554                 RtlMoveMemory(copyProtectKey->KeyData,
02555                               keyHeader->Data,
02556                               transferLength);
02557             }
02558 
02559             copyProtectKey->KeyLength = sizeof(DVD_COPY_PROTECT_KEY);
02560             copyProtectKey->KeyLength += transferLength;
02561 
02562             realIrp->IoStatus.Information = copyProtectKey->KeyLength;
02563             break;
02564         }
02565 
02566         case IOCTL_DVD_START_SESSION: {
02567 
02568             PDVD_SESSION_ID sessionId = realIrp->AssociatedIrp.SystemBuffer;
02569 
02570             PCDVD_KEY_HEADER keyHeader = srb->DataBuffer;
02571             PCDVD_REPORT_AGID_DATA keyData = (PCDVD_REPORT_AGID_DATA) keyHeader->Data;
02572 
02573             *sessionId = keyData->AGID;
02574 
02575             realIrp->IoStatus.Information = sizeof(DVD_SESSION_ID);
02576 
02577             break;
02578         }
02579 
02580         case IOCTL_DVD_END_SESSION:
02581         case IOCTL_DVD_SEND_KEY:
02582         case IOCTL_DVD_SEND_KEY2:
02583 
02584             //
02585             // nothing to return
02586             //
02587             realIrp->IoStatus.Information = 0;
02588             break;
02589 
02590         case IOCTL_CDROM_PLAY_AUDIO_MSF:
02591 
02592             PLAY_ACTIVE(fdoExtension) = TRUE;
02593 
02594             break;
02595 
02596         case IOCTL_CDROM_READ_Q_CHANNEL: {
02597 
02598             PSUB_Q_CHANNEL_DATA userChannelData = realIrp->AssociatedIrp.SystemBuffer;
02599             PCDROM_SUB_Q_DATA_FORMAT inputBuffer = realIrp->AssociatedIrp.SystemBuffer;
02600             PSUB_Q_CHANNEL_DATA subQPtr = srb->DataBuffer;
02601 
02602 #if DBG
02603             switch( inputBuffer->Format ) {
02604 
02605             case IOCTL_CDROM_CURRENT_POSITION:
02606                 TraceLog((CdromDebugTrace,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr->CurrentPosition.Header.AudioStatus ));
02607                 TraceLog((CdromDebugTrace,"CdRomDeviceControlCompletion: ADR = 0x%x\n", subQPtr->CurrentPosition.ADR ));
02608                 TraceLog((CdromDebugTrace,"CdRomDeviceControlCompletion: Control = 0x%x\n", subQPtr->CurrentPosition.Control ));
02609                 TraceLog((CdromDebugTrace,"CdRomDeviceControlCompletion: Track = %u\n", subQPtr->CurrentPosition.TrackNumber ));
02610                 TraceLog((CdromDebugTrace,"CdRomDeviceControlCompletion: Index = %u\n", subQPtr->CurrentPosition.IndexNumber ));
02611                 TraceLog((CdromDebugTrace,"CdRomDeviceControlCompletion: Absolute Address = %x\n", *((PULONG)subQPtr->CurrentPosition.AbsoluteAddress) ));
02612                 TraceLog((CdromDebugTrace,"CdRomDeviceControlCompletion: Relative Address = %x\n", *((PULONG)subQPtr->CurrentPosition.TrackRelativeAddress) ));
02613                 break;
02614 
02615             case IOCTL_CDROM_MEDIA_CATALOG:
02616                 TraceLog((CdromDebugTrace,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr->MediaCatalog.Header.AudioStatus ));
02617                 TraceLog((CdromDebugTrace,"CdRomDeviceControlCompletion: Mcval is %u\n", subQPtr->MediaCatalog.Mcval ));
02618                 break;
02619 
02620             case IOCTL_CDROM_TRACK_ISRC:
02621                 TraceLog((CdromDebugTrace,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr->TrackIsrc.Header.AudioStatus ));
02622                 TraceLog((CdromDebugTrace,"CdRomDeviceControlCompletion: Tcval is %u\n", subQPtr->TrackIsrc.Tcval ));
02623                 break;
02624 
02625             }
02626 #endif
02627 
02628             //
02629             // Update the play active status.
02630             //
02631 
02632             if (subQPtr->CurrentPosition.Header.AudioStatus == AUDIO_STATUS_IN_PROGRESS) {
02633 
02634                 PLAY_ACTIVE(fdoExtension) = TRUE;
02635 
02636             } else {
02637 
02638                 PLAY_ACTIVE(fdoExtension) = FALSE;
02639 
02640             }
02641 
02642             //
02643             // Check if output buffer is large enough to contain
02644             // the data.
02645             //
02646 
02647             if (realIrpStack->Parameters.DeviceIoControl.OutputBufferLength <
02648                 srb->DataTransferLength) {
02649 
02650                 srb->DataTransferLength =
02651                     realIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
02652             }
02653 
02654             //
02655             // Copy our buffer into users.
02656             //
02657 
02658             RtlMoveMemory(userChannelData,
02659                           subQPtr,
02660                           srb->DataTransferLength);
02661 
02662             realIrp->IoStatus.Information = srb->DataTransferLength;
02663             break;
02664         }
02665 
02666         case IOCTL_CDROM_PAUSE_AUDIO:
02667 
02668             PLAY_ACTIVE(fdoExtension) = FALSE;
02669             realIrp->IoStatus.Information = 0;
02670             break;
02671 
02672         case IOCTL_CDROM_RESUME_AUDIO:
02673 
02674             realIrp->IoStatus.Information = 0;
02675             break;
02676 
02677         case IOCTL_CDROM_SEEK_AUDIO_MSF:
02678 
02679             realIrp->IoStatus.Information = 0;
02680             break;
02681 
02682         case IOCTL_CDROM_STOP_AUDIO:
02683 
02684             PLAY_ACTIVE(fdoExtension) = FALSE;
02685             realIrp->IoStatus.Information = 0;
02686             break;
02687 
02688         case IOCTL_CDROM_GET_CONTROL: {
02689 
02690             PCDROM_AUDIO_CONTROL audioControl = srb->DataBuffer;
02691             PAUDIO_OUTPUT        audioOutput;
02692             ULONG                bytesTransferred;
02693 
02694             audioOutput = ClassFindModePage((PCHAR)audioControl,
02695                                             srb->DataTransferLength,
02696                                             CDROM_AUDIO_CONTROL_PAGE,
02697                                             use6Byte);
02698             //
02699             // Verify the page is as big as expected.
02700             //
02701 
02702             bytesTransferred = (ULONG)((PCHAR) audioOutput - (PCHAR) audioControl) +
02703                                sizeof(AUDIO_OUTPUT);
02704 
02705             if (audioOutput != NULL &&
02706                 srb->DataTransferLength >= bytesTransferred) {
02707 
02708                 audioControl->LbaFormat = audioOutput->LbaFormat;
02709 
02710                 audioControl->LogicalBlocksPerSecond =
02711                     (audioOutput->LogicalBlocksPerSecond[0] << (UCHAR)8) |
02712                     audioOutput->LogicalBlocksPerSecond[1];
02713 
02714                 realIrp->IoStatus.Information = sizeof(CDROM_AUDIO_CONTROL);
02715 
02716             } else {
02717                 realIrp->IoStatus.Information = 0;
02718                 status = STATUS_INVALID_DEVICE_REQUEST;
02719             }
02720             break;
02721         }
02722 
02723         case IOCTL_CDROM_GET_VOLUME: {
02724 
02725             PAUDIO_OUTPUT audioOutput;
02726             PVOLUME_CONTROL volumeControl = srb->DataBuffer;
02727             ULONG i;
02728             ULONG bytesTransferred;
02729 
02730             audioOutput = ClassFindModePage((PCHAR)volumeControl,
02731                                                  srb->DataTransferLength,
02732                                                  CDROM_AUDIO_CONTROL_PAGE,
02733                                                  use6Byte);
02734 
02735             //
02736             // Verify the page is as big as expected.
02737             //
02738 
02739             bytesTransferred = (ULONG)((PCHAR) audioOutput - (PCHAR) volumeControl) +
02740                                sizeof(AUDIO_OUTPUT);
02741 
02742             if (audioOutput != NULL &&
02743                 srb->DataTransferLength >= bytesTransferred) {
02744 
02745                 for (i=0; i<4; i++) {
02746                     volumeControl->PortVolume[i] =
02747                         audioOutput->PortOutput[i].Volume;
02748                 }
02749 
02750                 //
02751                 // Set bytes transferred in IRP.
02752                 //
02753 
02754                 realIrp->IoStatus.Information = sizeof(VOLUME_CONTROL);
02755 
02756             } else {
02757                 realIrp->IoStatus.Information = 0;
02758                 status = STATUS_INVALID_DEVICE_REQUEST;
02759             }
02760 
02761             break;
02762         }
02763 
02764         case IOCTL_CDROM_SET_VOLUME:
02765 
02766             realIrp->IoStatus.Information = 0;
02767             break;
02768 
02769         default:
02770 
02771             ASSERT(FALSE);
02772             realIrp->IoStatus.Information = 0;
02773             status = STATUS_INVALID_DEVICE_REQUEST;
02774 
02775         } // end switch()
02776     }
02777 
02778     //
02779     // Deallocate srb and sense buffer.
02780     //
02781 
02782     if (srb) {
02783         if (srb->DataBuffer) {
02784             ExFreePool(srb->DataBuffer);
02785         }
02786         if (srb->SenseInfoBuffer) {
02787             ExFreePool(srb->SenseInfoBuffer);
02788         }
02789         ExFreePool(srb);
02790     }
02791 
02792     if (realIrp->PendingReturned) {
02793         IoMarkIrpPending(realIrp);
02794     }
02795 
02796     if (Irp->MdlAddress) {
02797         IoFreeMdl(Irp->MdlAddress);
02798     }
02799 
02800     IoFreeIrp(Irp);
02801 
02802     //
02803     // Set status in completing IRP.
02804     //
02805 
02806     realIrp->IoStatus.Status = status;
02807 
02808     //
02809     // Set the hard error if necessary.
02810     //
02811 
02812     if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
02813 
02814         //
02815         // Store DeviceObject for filesystem, and clear
02816         // in IoStatus.Information field.
02817         //
02818 
02819         TraceLog((CdromDebugWarning,
02820                     "CdRomDeviceCompletion - Setting Hard Error on realIrp %p\n",
02821                     realIrp));
02822         if (realIrp->Tail.Overlay.Thread) {
02823             IoSetHardErrorOrVerifyDevice(realIrp, DeviceObject);
02824         }
02825 
02826         realIrp->IoStatus.Information = 0;
02827     }
02828     
02829     //
02830     // note: must complete the realIrp, as the completed irp (above)
02831     //       was self-allocated.
02832     //
02833 
02834     CdRomCompleteIrpAndStartNextPacketSafely(DeviceObject, realIrp);
02835     return STATUS_MORE_PROCESSING_REQUIRED;
02836 }
02837 
02838 
02839 NTSTATUS
02840 CdRomSetVolumeIntermediateCompletion(
02841     IN PDEVICE_OBJECT DeviceObject,
02842     IN PIRP Irp,
02843     IN PVOID Context
02844     )
02845 {
02846     PFUNCTIONAL_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
02847     PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
02848 
02849     PIO_STACK_LOCATION  irpStack = IoGetCurrentIrpStackLocation(Irp);
02850     PCDROM_DATA         cdData = (PCDROM_DATA)(commonExtension->DriverData);
02851     BOOLEAN             use6Byte = TEST_FLAG(cdData->XAFlags, XA_USE_6_BYTE);
02852     PIO_STACK_LOCATION  realIrpStack;
02853     PIO_STACK_LOCATION  realIrpNextStack;
02854     PSCSI_REQUEST_BLOCK srb     = Context;
02855     PIRP                realIrp = NULL;
02856     NTSTATUS            status;
02857     BOOLEAN             retry;
02858     ULONG retryCount;
02859 
02860     //
02861     // Extract the 'real' irp from the irpstack.
02862     //
02863 
02864     realIrp = (PIRP) irpStack->Parameters.Others.Argument2;
02865     realIrpStack = IoGetCurrentIrpStackLocation(realIrp);
02866     realIrpNextStack = IoGetNextIrpStackLocation(realIrp);
02867 
02868     //
02869     // Check SRB status for success of completing request.
02870     //
02871 
02872     if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
02873 
02874         ULONG retryInterval;
02875 
02876         TraceLog((CdromDebugTrace,
02877                     "CdRomSetVolumeIntermediateCompletion: Irp %p, Srb %p, Real Irp %p\n",
02878                     Irp,
02879                     srb,
02880                     realIrp));
02881 
02882         //
02883         // Release the queue if it is frozen.
02884         //
02885 
02886         if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
02887             ClassReleaseQueue(DeviceObject);
02888         }
02889 
02890 
02891         retry = ClassInterpretSenseInfo(DeviceObject,
02892                                             srb,
02893                                             irpStack->MajorFunction,
02894                                             irpStack->Parameters.DeviceIoControl.IoControlCode,
02895                                             MAXIMUM_RETRIES - ((ULONG)(ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1),
02896                                             &status,
02897                                             &retryInterval);
02898 
02899         if (status == STATUS_DATA_OVERRUN) {
02900             status = STATUS_SUCCESS;
02901             retry = FALSE;
02902         }
02903 
02904         //
02905         // If the status is verified required and the this request
02906         // should bypass verify required then retry the request.
02907         //
02908 
02909         if (realIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME &&
02910             status == STATUS_VERIFY_REQUIRED) {
02911 
02912             status = STATUS_IO_DEVICE_ERROR;
02913             retry = TRUE;
02914         }
02915 
02916         //
02917         // get current retry count
02918         //
02919         retryCount = PtrToUlong(realIrpNextStack->Parameters.Others.Argument1);
02920 
02921         if (retry && retryCount) {
02922 
02923             //
02924             // update retry count
02925             //
02926             realIrpNextStack->Parameters.Others.Argument1 = UlongToPtr(retryCount-1);
02927 
02928 
02929             if (((ULONG)(ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1)) {
02930 
02931                 //
02932                 // Retry request.
02933                 //
02934 
02935                 TraceLog((CdromDebugWarning,
02936                             "Retry request %p - Calling StartIo\n", Irp));
02937 
02938 
02939                 ExFreePool(srb->SenseInfoBuffer);
02940                 ExFreePool(srb->DataBuffer);
02941                 ExFreePool(srb);
02942                 if (Irp->MdlAddress) {
02943                     IoFreeMdl(Irp->MdlAddress);
02944                 }
02945 
02946                 IoFreeIrp(Irp);
02947 
02948                 CdRomRetryRequest(deviceExtension,
02949                                   realIrp,
02950                                   retryInterval,
02951                                   FALSE);
02952 
02953                 return STATUS_MORE_PROCESSING_REQUIRED;
02954 
02955             }
02956 
02957             //
02958             // Exhausted retries. Fall through and complete the request with the appropriate status.
02959             //
02960 
02961         }
02962     } else {
02963 
02964         //
02965         // Set status for successful request.
02966         //
02967 
02968         status = STATUS_SUCCESS;
02969     
02970     }
02971 
02972     if (NT_SUCCESS(status)) {
02973 
02974         PAUDIO_OUTPUT   audioInput = NULL;
02975         PAUDIO_OUTPUT   audioOutput;
02976         PVOLUME_CONTROL volumeControl = realIrp->AssociatedIrp.SystemBuffer;
02977         ULONG           i,bytesTransferred,headerLength;
02978         PVOID           dataBuffer;
02979         PCDB            cdb;
02980 
02981         audioInput = ClassFindModePage((PCHAR)srb->DataBuffer,
02982                                              srb->DataTransferLength,
02983                                              CDROM_AUDIO_CONTROL_PAGE,
02984                                              use6Byte);
02985 
02986         //
02987         // Check to make sure the mode sense data is valid before we go on
02988         //
02989 
02990         if(audioInput == NULL) {
02991 
02992             TraceLog((CdromDebugWarning,
02993                         "Mode Sense Page %d not found\n",
02994                         CDROM_AUDIO_CONTROL_PAGE));
02995 
02996             realIrp->IoStatus.Information = 0;
02997             realIrp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
02998             goto SafeExit;
02999         }
03000 
03001         if (use6Byte) {
03002             headerLength = sizeof(MODE_PARAMETER_HEADER);
03003         } else {
03004             headerLength = sizeof(MODE_PARAMETER_HEADER10);
03005         }
03006 
03007         bytesTransferred = sizeof(AUDIO_OUTPUT) + headerLength;
03008 
03009         //
03010         // Allocate a new buffer for the mode select.
03011         //
03012 
03013         dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
03014                                     bytesTransferred,
03015                                     CDROM_TAG_VOLUME_INT);
03016 
03017         if (!dataBuffer) {
03018             realIrp->IoStatus.Information = 0;
03019             realIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
03020             goto SafeExit;
03021         }
03022 
03023         RtlZeroMemory(dataBuffer, bytesTransferred);
03024 
03025         //
03026         // Rebuild the data buffer to include the user requested values.
03027         //
03028 
03029         audioOutput = (PAUDIO_OUTPUT) ((PCHAR) dataBuffer + headerLength);
03030 
03031         for (i=0; i<4; i++) {
03032             audioOutput->PortOutput[i].Volume =
03033                 volumeControl->PortVolume[i];
03034             audioOutput->PortOutput[i].ChannelSelection =
03035                 audioInput->PortOutput[i].ChannelSelection;
03036         }
03037 
03038         audioOutput->CodePage = CDROM_AUDIO_CONTROL_PAGE;
03039         audioOutput->ParameterLength = sizeof(AUDIO_OUTPUT) - 2;
03040         audioOutput->Immediate = MODE_SELECT_IMMEDIATE;
03041 
03042         //
03043         // Free the old data buffer, mdl.
03044         //
03045 
03046         IoFreeMdl(Irp->MdlAddress);
03047         Irp->MdlAddress = NULL;
03048         ExFreePool(srb->DataBuffer);
03049 
03050         //
03051         // set the data buffer to new allocation, so it can be
03052         // freed in the exit path
03053         //
03054         
03055         srb->DataBuffer = dataBuffer;
03056 
03057         //
03058         // rebuild the srb.
03059         //
03060 
03061         cdb = (PCDB)srb->Cdb;
03062         RtlZeroMemory(cdb, CDB12GENERIC_LENGTH);
03063 
03064         srb->SrbStatus = srb->ScsiStatus = 0;
03065         srb->SrbFlags = deviceExtension->SrbFlags;
03066         SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
03067         SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_OUT);
03068         srb->DataTransferLength = bytesTransferred;
03069 
03070         if (use6Byte) {
03071 
03072             cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
03073             cdb->MODE_SELECT.ParameterListLength = (UCHAR) bytesTransferred;
03074             cdb->MODE_SELECT.PFBit = 1;
03075             srb->CdbLength = 6;
03076         } else {
03077 
03078             cdb->MODE_SELECT10.OperationCode = SCSIOP_MODE_SELECT10;
03079             cdb->MODE_SELECT10.ParameterListLength[0] = (UCHAR) (bytesTransferred >> 8);
03080             cdb->MODE_SELECT10.ParameterListLength[1] = (UCHAR) (bytesTransferred & 0xFF);
03081             cdb->MODE_SELECT10.PFBit = 1;
03082             srb->CdbLength = 10;
03083         }
03084 
03085         //
03086         // Prepare the MDL
03087         //
03088 
03089         Irp->MdlAddress = IoAllocateMdl(dataBuffer,
03090                                         bytesTransferred,
03091                                         FALSE,
03092                                         FALSE,
03093                                         (PIRP) NULL);
03094 
03095         if (!Irp->MdlAddress) {
03096             realIrp->IoStatus.Information = 0;
03097             realIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
03098             goto SafeExit;
03099         }
03100 
03101         MmBuildMdlForNonPagedPool(Irp->MdlAddress);
03102 
03103         irpStack = IoGetNextIrpStackLocation(Irp);
03104         irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
03105         irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
03106         irpStack->Parameters.Scsi.Srb = srb;
03107 
03108         //
03109         // reset the irp completion.
03110         //
03111 
03112         IoSetCompletionRoutine(Irp,
03113                                CdRomDeviceControlCompletion,
03114                                srb,
03115                                TRUE,
03116                                TRUE,
03117                                TRUE);
03118         //
03119         // Call the port driver.
03120         //
03121 
03122         IoCallDriver(commonExtension->LowerDeviceObject, Irp);
03123 
03124         return STATUS_MORE_PROCESSING_REQUIRED;
03125     }
03126 
03127 SafeExit:
03128 
03129     //
03130     // Deallocate srb and sense buffer.
03131     //
03132 
03133     if (srb) {
03134         if (srb->DataBuffer) {
03135             ExFreePool(srb->DataBuffer);
03136         }
03137         if (srb->SenseInfoBuffer) {
03138             ExFreePool(srb->SenseInfoBuffer);
03139         }
03140         ExFreePool(srb);
03141     }
03142 
03143     if (Irp->PendingReturned) {
03144       IoMarkIrpPending(Irp);
03145     }
03146 
03147     if (realIrp->PendingReturned) {
03148         IoMarkIrpPending(realIrp);
03149     }
03150 
03151     if (Irp->MdlAddress) {
03152         IoFreeMdl(Irp->MdlAddress);
03153     }
03154 
03155     IoFreeIrp(Irp);
03156 
03157     //
03158     // Set status in completing IRP.
03159     //
03160 
03161     realIrp->IoStatus.Status = status;
03162 
03163     //
03164     // Set the hard error if necessary.
03165     //
03166 
03167     if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
03168 
03169         //
03170         // Store DeviceObject for filesystem, and clear
03171         // in IoStatus.Information field.
03172         //
03173 
03174         if (realIrp->Tail.Overlay.Thread) {
03175             IoSetHardErrorOrVerifyDevice(realIrp, DeviceObject);
03176         }
03177         realIrp->IoStatus.Information = 0;
03178     }
03179 
03180     CdRomCompleteIrpAndStartNextPacketSafely(DeviceObject, realIrp);
03181     return STATUS_MORE_PROCESSING_REQUIRED;
03182 }
03183 
03184 NTSTATUS
03185 CdRomDvdEndAllSessionsCompletion(
03186     IN PDEVICE_OBJECT DeviceObject,
03187     IN PIRP Irp,
03188     IN PVOID Context
03189     )
03190 
03191 /*++
03192 
03193 Routine Description:
03194 
03195     This routine will setup the next stack location to issue an end session
03196     to the device.  It will increment the session id in the system buffer
03197     and issue an END_SESSION for that AGID if the AGID is valid.
03198 
03199     When the new AGID is > 3 this routine will complete the request.
03200 
03201 Arguments:
03202 
03203     DeviceObject - the device object for this drive
03204 
03205     Irp - the request
03206 
03207     Context - done
03208 
03209 Return Value:
03210 
03211     STATUS_MORE_PROCESSING_REQUIRED if there is another AGID to clear
03212     status otherwise.
03213 
03214 --*/
03215 
03216 {
03217     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
03218 
03219     PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
03220 
03221     PDVD_SESSION_ID sessionId = Irp->AssociatedIrp.SystemBuffer;
03222 
03223     NTSTATUS status;
03224 
03225     if(++(*sessionId) > MAX_COPY_PROTECT_AGID) {
03226 
03227         //
03228         // We're done here - just return success and let the io system
03229         // continue to complete it.
03230         //
03231 
03232         return STATUS_SUCCESS;
03233 
03234     }
03235 
03236     IoCopyCurrentIrpStackLocationToNext(Irp);
03237 
03238     IoSetCompletionRoutine(Irp,
03239                            CdRomDvdEndAllSessionsCompletion,
03240                            NULL,
03241                            TRUE,
03242                            FALSE,
03243                            FALSE);
03244 
03245     IoMarkIrpPending(Irp);
03246 
03247     IoCallDriver(fdoExtension->CommonExtension.DeviceObject, Irp);
03248 
03249     //
03250     // At this point we have to assume the irp may have already been
03251     // completed.  Ignore the returned status and return.
03252     //
03253 
03254     return STATUS_MORE_PROCESSING_REQUIRED;
03255 }
03256 
03257 NTSTATUS
03258 CdRomDvdReadDiskKeyCompletion(
03259     IN PDEVICE_OBJECT DeviceObject,
03260     IN PIRP Irp,
03261     IN PVOID Context
03262     )
03263 
03264 /*++
03265 
03266 Routine Description:
03267 
03268     This routine handles the completion of a request to obtain the disk
03269     key from the dvd media.  It will transform the raw 2K of key data into
03270     a DVD_COPY_PROTECT_KEY structure and copy back the saved key parameters
03271     from the context pointer before returning.
03272 
03273 Arguments:
03274 
03275     DeviceObject -
03276 
03277     Irp -
03278 
03279     Context - a DVD_COPY_PROTECT_KEY pointer which contains the key
03280               parameters handed down by the caller.
03281 
03282 Return Value:
03283 
03284     STATUS_SUCCESS;
03285 
03286 --*/
03287 
03288 {
03289     PDVD_COPY_PROTECT_KEY savedKey = Context;
03290 
03291     PREAD_DVD_STRUCTURES_HEADER rawKey = Irp->AssociatedIrp.SystemBuffer;
03292     PDVD_COPY_PROTECT_KEY outputKey = Irp->AssociatedIrp.SystemBuffer;
03293 
03294     if (NT_SUCCESS(Irp->IoStatus.Status)) {
03295 
03296         //
03297         // Shift the data down to its new position.
03298         //
03299 
03300         RtlMoveMemory(outputKey->KeyData,
03301                       rawKey->Data,
03302                       sizeof(DVD_DISK_KEY_DESCRIPTOR));
03303 
03304         RtlCopyMemory(outputKey,
03305                       savedKey,
03306                       sizeof(DVD_COPY_PROTECT_KEY));
03307 
03308         outputKey->KeyLength = DVD_DISK_KEY_LENGTH;
03309 
03310         Irp->IoStatus.Information = DVD_DISK_KEY_LENGTH;
03311 
03312     } else {
03313 
03314         TraceLog((CdromDebugWarning,
03315                     "DiskKey Failed with status %x, %p (%x) bytes\n",
03316                     Irp->IoStatus.Status,
03317                     (PVOID)Irp->IoStatus.Information,
03318                     ((rawKey->Length[0] << 16) | rawKey->Length[1])
03319                     ));
03320 
03321     }
03322 
03323     //
03324     // release the context block
03325     //
03326 
03327     ExFreePool(Context);
03328 
03329     return STATUS_SUCCESS;
03330 }
03331 
03332 NTSTATUS
03333 CdRomXACompletion(
03334     IN PDEVICE_OBJECT DeviceObject,
03335     IN PIRP Irp,
03336     IN PVOID Context
03337     )
03338 
03339 /*++
03340 
03341 Routine Description:
03342 
03343     This routine executes when the port driver has completed a request.
03344     It looks at the SRB status in the completing SRB and if not success
03345     it checks for valid request sense buffer information. If valid, the
03346     info is used to update status with more precise message of type of
03347     error. This routine deallocates the SRB.
03348 
03349 Arguments:
03350 
03351     DeviceObject - Supplies the device object which represents the logical
03352         unit.
03353 
03354     Irp - Supplies the Irp which has completed.
03355 
03356     Context - Supplies a pointer to the SRB.
03357 
03358 Return Value:
03359 
03360     NT status
03361 
03362 --*/
03363 
03364 {
03365     PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
03366     PSCSI_REQUEST_BLOCK srb = Context;
03367     PFUNCTIONAL_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
03368     NTSTATUS status;
03369     BOOLEAN retry;
03370 
03371     //
03372     // Check SRB status for success of completing request.
03373     //
03374 
03375     if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
03376 
03377         ULONG retryInterval;
03378 
03379         TraceLog((CdromDebugTrace, "CdromXAComplete: IRP %p  SRB %p  Status %x\n",
03380                     Irp, srb, srb->SrbStatus));
03381 
03382         //
03383         // Release the queue if it is frozen.
03384         //
03385 
03386         if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
03387             ClassReleaseQueue(DeviceObject);
03388         }
03389 
03390         retry = ClassInterpretSenseInfo(
03391             DeviceObject,
03392             srb,
03393             irpStack->MajorFunction,
03394             irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL ? irpStack->Parameters.DeviceIoControl.IoControlCode : 0,
03395             MAXIMUM_RETRIES - irpStack->MinorFunction, // HACKHACK - REF #0001
03396             &status,
03397             &retryInterval);
03398 
03399         //
03400         // If the status is verified required and the this request
03401         // should bypass verify required then retry the request.
03402         //
03403 
03404         if (irpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME &&
03405             status == STATUS_VERIFY_REQUIRED) {
03406 
03407             status = STATUS_IO_DEVICE_ERROR;
03408             retry = TRUE;
03409         }
03410 
03411         if (retry) {
03412 
03413             if (irpStack->MinorFunction != 0) { // HACKHACK - REF #0001
03414 
03415                 irpStack->MinorFunction--;      // HACKHACK - REF #0001
03416 
03417                 //
03418                 // Retry request.
03419                 //
03420 
03421                 TraceLog((CdromDebugWarning,
03422                             "CdRomXACompletion: Retry request %p (%x) - "
03423                             "Calling StartIo\n", Irp, irpStack->MinorFunction));
03424 
03425 
03426                 ExFreePool(srb->SenseInfoBuffer);
03427                 ExFreePool(srb);
03428 
03429                 //
03430                 // Call StartIo directly since IoStartNextPacket hasn't been called,
03431                 // the serialisation is still intact.
03432                 //
03433 
03434                 CdRomRetryRequest(deviceExtension,
03435                                   Irp,
03436                                   retryInterval,
03437                                   FALSE);
03438 
03439                 return STATUS_MORE_PROCESSING_REQUIRED;
03440 
03441             }
03442 
03443             //
03444             // Exhausted retries, fall through and complete the request
03445             // with the appropriate status
03446             //
03447 
03448             TraceLog((CdromDebugWarning,
03449                         "CdRomXACompletion: Retries exhausted for irp %p\n",
03450                         Irp));
03451 
03452         }
03453 
03454     } else {
03455 
03456         //
03457         // Set status for successful request.
03458         //
03459 
03460         status = STATUS_SUCCESS;
03461 
03462     } // end if (SRB_STATUS(srb->SrbStatus) ...
03463 
03464     //
03465     // Return SRB to nonpaged pool.
03466     //
03467 
03468     ExFreePool(srb->SenseInfoBuffer);
03469     ExFreePool(srb);
03470 
03471     //
03472     // Set status in completing IRP.
03473     //
03474 
03475     Irp->IoStatus.Status = status;    
03476 
03477     //
03478     // Set the hard error if necessary.
03479     //
03480 
03481     if (!NT_SUCCESS(status) &&
03482         IoIsErrorUserInduced(status) &&
03483         Irp->Tail.Overlay.Thread != NULL ) {
03484 
03485         //
03486         // Store DeviceObject for filesystem, and clear
03487         // in IoStatus.Information field.
03488         //
03489 
03490         IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
03491         Irp->IoStatus.Information = 0;
03492     }
03493 
03494     //
03495     // If pending has be returned for this irp then mark the current stack as
03496     // pending.
03497     //
03498 
03499     if (Irp->PendingReturned) {
03500       IoMarkIrpPending(Irp);
03501     }
03502     
03503     {
03504         KIRQL oldIrql = KeRaiseIrqlToDpcLevel();
03505         IoStartNextPacket(DeviceObject, FALSE);
03506         KeLowerIrql(oldIrql);
03507     }
03508     ClassReleaseRemoveLock(DeviceObject, Irp);
03509     
03510     return status;
03511 }
03512 
03513 
03514 VOID
03515 CdRomDeviceControlDvdReadStructure(
03516     IN PDEVICE_OBJECT Fdo,
03517     IN PIRP OriginalIrp,
03518     IN PIRP NewIrp,
03519     IN PSCSI_REQUEST_BLOCK Srb
03520     )
03521 {
03522     PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(OriginalIrp);
03523     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
03524     PCDB cdb = (PCDB)Srb->Cdb;
03525     PVOID dataBuffer;
03526 
03527     PDVD_READ_STRUCTURE request;
03528     USHORT dataLength;
03529     ULONG blockNumber;
03530     PFOUR_BYTE fourByte;
03531 
03532     dataLength =
03533         (USHORT)currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
03534 
03535     request = OriginalIrp->AssociatedIrp.SystemBuffer;
03536     blockNumber =
03537         (ULONG)(request->BlockByteOffset.QuadPart >> fdoExtension->SectorShift);
03538     fourByte = (PFOUR_BYTE) &blockNumber;
03539 
03540     Srb->CdbLength = 12;
03541     Srb->TimeOutValue = fdoExtension->TimeOutValue;
03542     Srb->SrbFlags = fdoExtension->SrbFlags;
03543     SET_FLAG(Srb->SrbFlags, SRB_FLAGS_DATA_IN);
03544 
03545     cdb->READ_DVD_STRUCTURE.OperationCode = SCSIOP_READ_DVD_STRUCTURE;
03546     cdb->READ_DVD_STRUCTURE.RMDBlockNumber[0] = fourByte->Byte3;
03547     cdb->READ_DVD_STRUCTURE.RMDBlockNumber[1] = fourByte->Byte2;
03548     cdb->READ_DVD_STRUCTURE.RMDBlockNumber[2] = fourByte->Byte1;
03549     cdb->READ_DVD_STRUCTURE.RMDBlockNumber[3] = fourByte->Byte0;
03550     cdb->READ_DVD_STRUCTURE.LayerNumber   = request->LayerNumber;
03551     cdb->READ_DVD_STRUCTURE.Format        = (UCHAR)request->Format;
03552 
03553 #if DBG
03554     {
03555         if ((UCHAR)request->Format > DvdMaxDescriptor) {
03556             TraceLog((CdromDebugWarning,
03557                         "READ_DVD_STRUCTURE format %x = %s (%x bytes)\n",
03558                         (UCHAR)request->Format,
03559                         READ_DVD_STRUCTURE_FORMAT_STRINGS[DvdMaxDescriptor],
03560                         dataLength
03561                         ));
03562         } else {
03563             TraceLog((CdromDebugWarning,
03564                         "READ_DVD_STRUCTURE format %x = %s (%x bytes)\n",
03565                         (UCHAR)request->Format,
03566                         READ_DVD_STRUCTURE_FORMAT_STRINGS[(UCHAR)request->Format],
03567                         dataLength
03568                         ));
03569         }
03570     }
03571 #endif // DBG
03572 
03573     if (request->Format == DvdDiskKeyDescriptor) {
03574 
03575         cdb->READ_DVD_STRUCTURE.AGID = (UCHAR) request->SessionId;
03576 
03577     }
03578 
03579     cdb->READ_DVD_STRUCTURE.AllocationLength[0] = (UCHAR)(dataLength >> 8);
03580     cdb->READ_DVD_STRUCTURE.AllocationLength[1] = (UCHAR)(dataLength & 0xff);
03581     Srb->DataTransferLength = dataLength;
03582 
03583 
03584 
03585     dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
03586                                        dataLength,
03587                                        DVD_TAG_READ_STRUCTURE);
03588 
03589     if (!dataBuffer) {
03590         ExFreePool(Srb->SenseInfoBuffer);
03591         ExFreePool(Srb);
03592         IoFreeIrp(NewIrp);
03593         OriginalIrp->IoStatus.Information = 0;
03594         OriginalIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
03595 
03596         BAIL_OUT(OriginalIrp);
03597         CdRomCompleteIrpAndStartNextPacketSafely(Fdo, OriginalIrp);
03598         return;
03599     }
03600     RtlZeroMemory(dataBuffer, dataLength);
03601 
03602     NewIrp->MdlAddress = IoAllocateMdl(dataBuffer,
03603                                        currentIrpStack->Parameters.Read.Length,
03604                                        FALSE,
03605                                        FALSE,
03606                                        (PIRP) NULL);
03607 
03608     if (NewIrp->MdlAddress == NULL) {
03609         ExFreePool(dataBuffer);
03610         ExFreePool(Srb->SenseInfoBuffer);
03611         ExFreePool(Srb);
03612         IoFreeIrp(NewIrp);
03613         OriginalIrp->IoStatus.Information = 0;
03614         OriginalIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
03615 
03616         BAIL_OUT(OriginalIrp);
03617         CdRomCompleteIrpAndStartNextPacketSafely(Fdo, OriginalIrp);
03618         return;
03619     }
03620 
03621     //
03622     // Prepare the MDL
03623     //
03624 
03625     MmBuildMdlForNonPagedPool(NewIrp->MdlAddress);
03626 
03627     Srb->DataBuffer = dataBuffer;
03628 
03629     IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, NewIrp);
03630 
03631     return;
03632 }
03633 
03634 
03635 VOID
03636 CdRomDeviceControlDvdEndSession(
03637     IN PDEVICE_OBJECT Fdo,
03638     IN PIRP OriginalIrp,
03639     IN PIRP NewIrp,
03640     IN PSCSI_REQUEST_BLOCK Srb
03641     )
03642 {
03643     PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(OriginalIrp);
03644     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
03645     PCDB cdb = (PCDB)Srb->Cdb;
03646 
03647     PDVD_SESSION_ID sessionId = OriginalIrp->AssociatedIrp.SystemBuffer;
03648 
03649     Srb->CdbLength = 12;
03650     Srb->TimeOutValue = fdoExtension->TimeOutValue;
03651     Srb->SrbFlags = fdoExtension->SrbFlags;
03652     SET_FLAG(Srb->SrbFlags, SRB_FLAGS_NO_DATA_TRANSFER);
03653 
03654     cdb->SEND_KEY.OperationCode = SCSIOP_SEND_KEY;
03655     cdb->SEND_KEY.AGID = (UCHAR) (*sessionId);
03656     cdb->SEND_KEY.KeyFormat = DVD_INVALIDATE_AGID;
03657 
03658     IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, NewIrp);
03659     return;
03660 
03661 }
03662 
03663 
03664 VOID
03665 CdRomDeviceControlDvdStartSessionReadKey(
03666     IN PDEVICE_OBJECT Fdo,
03667     IN PIRP OriginalIrp,
03668     IN PIRP NewIrp,
03669     IN PSCSI_REQUEST_BLOCK Srb
03670     )
03671 {
03672     PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(OriginalIrp);
03673     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
03674     PCDB cdb = (PCDB)Srb->Cdb;
03675     NTSTATUS status;
03676 
03677     PDVD_COPY_PROTECT_KEY keyParameters;
03678     PCDVD_KEY_HEADER keyBuffer = NULL;
03679 
03680     ULONG keyLength;
03681 
03682     ULONG allocationLength;
03683     PFOUR_BYTE fourByte;
03684 
03685     //
03686     // Both of these use REPORT_KEY commands.
03687     // Determine the size of the input buffer
03688     //
03689 
03690     if(currentIrpStack->Parameters.DeviceIoControl.IoControlCode ==
03691        IOCTL_DVD_READ_KEY) {
03692 
03693         keyParameters = OriginalIrp->AssociatedIrp.SystemBuffer;
03694 
03695         keyLength = sizeof(CDVD_KEY_HEADER) +
03696                     (currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength -
03697                      sizeof(DVD_COPY_PROTECT_KEY));
03698     } else {
03699 
03700         keyParameters = NULL;
03701         keyLength = sizeof(CDVD_KEY_HEADER) +
03702                     sizeof(CDVD_REPORT_AGID_DATA);
03703     }
03704 
03705     TRY {
03706 
03707         keyBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
03708                                           keyLength,
03709                                           DVD_TAG_READ_KEY);
03710 
03711         if(keyBuffer == NULL) {
03712 
03713             TraceLog((CdromDebugWarning,
03714                         "IOCTL_DVD_READ_KEY - couldn't allocate "
03715                         "%d byte buffer for key\n",
03716                         keyLength));
03717             status = STATUS_INSUFFICIENT_RESOURCES;
03718             LEAVE;
03719         }
03720 
03721 
03722         NewIrp->MdlAddress = IoAllocateMdl(keyBuffer,
03723                                            keyLength,
03724                                            FALSE,
03725                                            FALSE,
03726                                            (PIRP) NULL);
03727 
03728         if(NewIrp->MdlAddress == NULL) {
03729 
03730             TraceLog((CdromDebugWarning,
03731                         "IOCTL_DVD_READ_KEY - couldn't create mdl\n"));
03732             status = STATUS_INSUFFICIENT_RESOURCES;
03733             LEAVE;
03734         }
03735 
03736         MmBuildMdlForNonPagedPool(NewIrp->MdlAddress);
03737 
03738         Srb->DataBuffer = keyBuffer;
03739         Srb->CdbLength = 12;
03740 
03741         cdb->REPORT_KEY.OperationCode = SCSIOP_REPORT_KEY;
03742 
03743         allocationLength = keyLength;
03744         fourByte = (PFOUR_BYTE) &allocationLength;
03745         cdb->REPORT_KEY.AllocationLength[0] = fourByte->Byte1;
03746         cdb->REPORT_KEY.AllocationLength[1] = fourByte->Byte0;
03747 
03748         Srb->DataTransferLength = keyLength;
03749 
03750         //
03751         // set the specific parameters....
03752         //
03753 
03754         if(currentIrpStack->Parameters.DeviceIoControl.IoControlCode ==
03755            IOCTL_DVD_READ_KEY) {
03756 
03757             if(keyParameters->KeyType == DvdTitleKey) {
03758 
03759                 ULONG logicalBlockAddress;
03760 
03761                 logicalBlockAddress = (ULONG)
03762                     (keyParameters->Parameters.TitleOffset.QuadPart >>
03763                      fdoExtension->SectorShift);
03764 
03765                 fourByte = (PFOUR_BYTE) &(logicalBlockAddress);
03766 
03767                 cdb->REPORT_KEY.LogicalBlockAddress[0] = fourByte->Byte3;
03768                 cdb->REPORT_KEY.LogicalBlockAddress[1] = fourByte->Byte2;
03769                 cdb->REPORT_KEY.LogicalBlockAddress[2] = fourByte->Byte1;
03770                 cdb->REPORT_KEY.LogicalBlockAddress[3] = fourByte->Byte0;
03771             }
03772 
03773             cdb->REPORT_KEY.KeyFormat = (UCHAR)keyParameters->KeyType;
03774             cdb->REPORT_KEY.AGID = (UCHAR) keyParameters->SessionId;
03775             TraceLog((CdromDebugWarning,
03776                         "CdRomDvdReadKey => sending irp %p for irp %p (%s)\n",
03777                         NewIrp, OriginalIrp, "READ_KEY"));
03778 
03779         } else {
03780 
03781             cdb->REPORT_KEY.KeyFormat = DVD_REPORT_AGID;
03782             cdb->REPORT_KEY.AGID = 0;
03783             TraceLog((CdromDebugWarning,
03784                         "CdRomDvdReadKey => sending irp %p for irp %p (%s)\n",
03785                         NewIrp, OriginalIrp, "START_SESSION"));
03786         }
03787 
03788         Srb->TimeOutValue = fdoExtension->TimeOutValue;
03789         Srb->SrbFlags = fdoExtension->SrbFlags;
03790         SET_FLAG(Srb->SrbFlags, SRB_FLAGS_DATA_IN);
03791 
03792         IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, NewIrp);
03793 
03794         status = STATUS_SUCCESS;
03795 
03796     } FINALLY {
03797 
03798         if (!NT_SUCCESS(status)) {
03799 
03800             //
03801             // An error occured during setup - free resources and
03802             // complete this request.
03803             //
03804             if (NewIrp->MdlAddress != NULL) {
03805                 IoFreeMdl(NewIrp->MdlAddress);
03806             }
03807 
03808             if (keyBuffer != NULL) {
03809                 ExFreePool(keyBuffer);
03810             }
03811             ExFreePool(Srb->SenseInfoBuffer);
03812             ExFreePool(Srb);
03813             IoFreeIrp(NewIrp);
03814 
03815             OriginalIrp->IoStatus.Information = 0;
03816             OriginalIrp->IoStatus.Status = status;
03817 
03818             BAIL_OUT(OriginalIrp);
03819             CdRomCompleteIrpAndStartNextPacketSafely(Fdo, OriginalIrp);
03820 
03821         } // end !NT_SUCCESS
03822     }
03823     return;
03824 }
03825 
03826 
03827 VOID
03828 CdRomDeviceControlDvdSendKey(
03829     IN PDEVICE_OBJECT Fdo,
03830     IN PIRP OriginalIrp,
03831     IN PIRP NewIrp,
03832     IN PSCSI_REQUEST_BLOCK Srb
03833     )
03834 {
03835     PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(OriginalIrp);
03836     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
03837     PCDB cdb = (PCDB)Srb->Cdb;
03838 
03839     PDVD_COPY_PROTECT_KEY key;
03840     PCDVD_KEY_HEADER keyBuffer = NULL;
03841 
03842     NTSTATUS status;
03843     ULONG keyLength;
03844     PFOUR_BYTE fourByte;
03845 
03846     key = OriginalIrp->AssociatedIrp.SystemBuffer;
03847     keyLength = (key->KeyLength - sizeof(DVD_COPY_PROTECT_KEY)) +
03848                 sizeof(CDVD_KEY_HEADER);
03849 
03850     TRY {
03851 
03852         keyBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
03853                                           keyLength,
03854                                           DVD_TAG_SEND_KEY);
03855 
03856         if(keyBuffer == NULL) {
03857 
03858             TraceLog((CdromDebugWarning,
03859                         "IOCTL_DVD_SEND_KEY - couldn't allocate "
03860                         "%d byte buffer for key\n",
03861                         keyLength));
03862             status = STATUS_INSUFFICIENT_RESOURCES;
03863             LEAVE;
03864         }
03865 
03866         RtlZeroMemory(keyBuffer, keyLength);
03867 
03868         //
03869         // keylength is decremented here by two because the
03870         // datalength does not include the header, which is two
03871         // bytes.  keylength is immediately incremented later
03872         // by the same amount.
03873         //
03874 
03875         keyLength -= 2;
03876         fourByte = (PFOUR_BYTE) &keyLength;
03877         keyBuffer->DataLength[0] = fourByte->Byte1;
03878         keyBuffer->DataLength[1] = fourByte->Byte0;
03879         keyLength += 2;
03880 
03881         //
03882         // copy the user's buffer to our own allocated buffer
03883         //
03884 
03885         RtlMoveMemory(keyBuffer->Data,
03886                       key->KeyData,
03887                       key->KeyLength - sizeof(DVD_COPY_PROTECT_KEY));
03888 
03889 
03890         NewIrp->MdlAddress = IoAllocateMdl(keyBuffer,
03891                                            keyLength,
03892                                            FALSE,
03893                                            FALSE,
03894                                            (PIRP) NULL);
03895 
03896         if(NewIrp->MdlAddress == NULL) {
03897             TraceLog((CdromDebugWarning,
03898                         "IOCTL_DVD_SEND_KEY - couldn't create mdl\n"));
03899             status = STATUS_INSUFFICIENT_RESOURCES;
03900             LEAVE;
03901         }
03902 
03903 
03904         MmBuildMdlForNonPagedPool(NewIrp->MdlAddress);
03905 
03906         Srb->CdbLength = 12;
03907         Srb->DataBuffer = keyBuffer;
03908         Srb->DataTransferLength = keyLength;
03909 
03910         Srb->TimeOutValue = fdoExtension->TimeOutValue;
03911         Srb->SrbFlags = fdoExtension->SrbFlags;
03912         SET_FLAG(Srb->SrbFlags, SRB_FLAGS_DATA_OUT);
03913 
03914         cdb->REPORT_KEY.OperationCode = SCSIOP_SEND_KEY;
03915 
03916         fourByte = (PFOUR_BYTE) &keyLength;
03917 
03918         cdb->SEND_KEY.ParameterListLength[0] = fourByte->Byte1;
03919         cdb->SEND_KEY.ParameterListLength[1] = fourByte->Byte0;
03920         cdb->SEND_KEY.KeyFormat = (UCHAR)key->KeyType;
03921         cdb->SEND_KEY.AGID = (UCHAR) key->SessionId;
03922 
03923         if (key->KeyType == DvdSetRpcKey) {
03924             TraceLog((CdromDebugWarning,
03925                         "IOCTL_DVD_SEND_KEY - Setting RPC2 drive region\n"));
03926         } else {
03927             TraceLog((CdromDebugWarning,
03928                         "IOCTL_DVD_SEND_KEY - key type %x\n", key->KeyType));
03929         }
03930 
03931         IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, NewIrp);
03932 
03933         status = STATUS_SUCCESS;
03934 
03935     } FINALLY {
03936 
03937         if (!NT_SUCCESS(status)) {
03938 
03939             //
03940             // An error occured during setup - free resources and
03941             // complete this request.
03942             //
03943 
03944             if (NewIrp->MdlAddress != NULL) {
03945                 IoFreeMdl(NewIrp->MdlAddress);
03946             }
03947 
03948             if (keyBuffer != NULL) {
03949                 ExFreePool(keyBuffer);
03950             }
03951 
03952             ExFreePool(Srb->SenseInfoBuffer);
03953             ExFreePool(Srb);
03954             IoFreeIrp(NewIrp);
03955 
03956             OriginalIrp->IoStatus.Information = 0;
03957             OriginalIrp->IoStatus.Status = status;
03958 
03959             BAIL_OUT(OriginalIrp);
03960             CdRomCompleteIrpAndStartNextPacketSafely(Fdo, OriginalIrp);
03961 
03962         }
03963     }
03964 
03965     return;
03966 }
03967 
03968 
03969 VOID
03970 CdRomInterpretReadCapacity(
03971     IN PDEVICE_OBJECT Fdo,
03972     IN PREAD_CAPACITY_DATA ReadCapacityBuffer
03973     )
03974 {
03975     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
03976     PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
03977     ULONG               lastSector;
03978     ULONG               bps;
03979     ULONG               lastBit;
03980     ULONG               tmp;
03981 
03982     ASSERT(ReadCapacityBuffer);
03983     ASSERT(commonExtension->IsFdo);
03984     
03985     TraceLog((CdromDebugError,
03986                 "CdRomInterpretReadCapacity: Entering\n"));
03987 
03988     //
03989     // Swizzle bytes from Read Capacity and translate into
03990     // the necessary geometry information in the device extension.
03991     //
03992 
03993     tmp = ReadCapacityBuffer->BytesPerBlock;
03994     ((PFOUR_BYTE)&bps)->Byte0 = ((PFOUR_BYTE)&tmp)->Byte3;
03995     ((PFOUR_BYTE)&bps)->Byte1 = ((PFOUR_BYTE)&tmp)->Byte2;
03996     ((PFOUR_BYTE)&bps)->Byte2 = ((PFOUR_BYTE)&tmp)->Byte1;
03997     ((PFOUR_BYTE)&bps)->Byte3 = ((PFOUR_BYTE)&tmp)->Byte0;
03998 
03999     //
04000     // Insure that bps is a power of 2.
04001     // This corrects a problem with the HP 4020i CDR where it
04002     // returns an incorrect number for bytes per sector.
04003     //
04004 
04005     if (!bps) {
04006         bps = 2048;
04007     } else {
04008         lastBit = (ULONG) -1;
04009         while (bps) {
04010             lastBit++;
04011             bps = bps >> 1;
04012         }
04013         bps = 1 << lastBit;
04014     }
04015 
04016     fdoExtension->DiskGeometry.BytesPerSector = bps;
04017 
04018     TraceLog((CdromDebugTrace, "CdRomInterpretReadCapacity: Calculated bps %#x\n",
04019                 fdoExtension->DiskGeometry.BytesPerSector));
04020 
04021     //
04022     // Copy last sector in reverse byte order.
04023     //
04024 
04025     tmp = ReadCapacityBuffer->LogicalBlockAddress;
04026     ((PFOUR_BYTE)&lastSector)->Byte0 = ((PFOUR_BYTE)&tmp)->Byte3;
04027     ((PFOUR_BYTE)&lastSector)->Byte1 = ((PFOUR_BYTE)&tmp)->Byte2;
04028     ((PFOUR_BYTE)&lastSector)->Byte2 = ((PFOUR_BYTE)&tmp)->Byte1;
04029     ((PFOUR_BYTE)&lastSector)->Byte3 = ((PFOUR_BYTE)&tmp)->Byte0;
04030 
04031     //
04032     // Calculate sector to byte shift.
04033     //
04034 
04035     WHICH_BIT(bps, fdoExtension->SectorShift);
04036 
04037     TraceLog((CdromDebugTrace,"CdRomInterpretReadCapacity: Sector size is %d\n",
04038         fdoExtension->DiskGeometry.BytesPerSector));
04039 
04040     TraceLog((CdromDebugTrace,"CdRomInterpretReadCapacity: Number of Sectors is %d\n",
04041         lastSector + 1));
04042 
04043     //
04044     // Calculate media capacity in bytes.
04045     //
04046 
04047     commonExtension->PartitionLength.QuadPart = (LONGLONG)(lastSector + 1);
04048 
04049     //
04050     // we've defaulted to 32/64 forever.  don't want to change this now...
04051     //
04052 
04053     fdoExtension->DiskGeometry.TracksPerCylinder = 0x40;
04054     fdoExtension->DiskGeometry.SectorsPerTrack = 0x20;
04055 
04056     //
04057     // Calculate number of cylinders.
04058     //
04059 
04060     fdoExtension->DiskGeometry.Cylinders.QuadPart = (LONGLONG)((lastSector + 1) / (32 * 64));
04061 
04062     commonExtension->PartitionLength.QuadPart =
04063         (commonExtension->PartitionLength.QuadPart << fdoExtension->SectorShift);
04064 
04065 
04066     ASSERT(TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA));
04067     
04068     //
04069     // This device supports removable media.
04070     //
04071 
04072     fdoExtension->DiskGeometry.MediaType = RemovableMedia;
04073 
04074     return;
04075 }
04076 
04077 

Generated on Sun May 27 2012 04:27:10 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.