Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygencdrom.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Storage Stack 00003 * LICENSE: DDK - see license.txt in the root dir 00004 * FILE: drivers/storage/cdrom/cdrom.c 00005 * PURPOSE: CDROM driver 00006 * PROGRAMMERS: Based on a source code sample from Microsoft NT4 DDK 00007 */ 00008 00009 #include "precomp.h" 00010 00011 //#define NDEBUG 00012 #include <debug.h> 00013 00014 #define CDB12GENERIC_LENGTH 12 00015 00016 typedef struct _XA_CONTEXT { 00017 00018 // 00019 // Pointer to the device object. 00020 // 00021 00022 PDEVICE_OBJECT DeviceObject; 00023 00024 // 00025 // Pointer to the original request when 00026 // a mode select must be sent. 00027 // 00028 00029 PIRP OriginalRequest; 00030 00031 // 00032 // Pointer to the mode select srb. 00033 // 00034 00035 PSCSI_REQUEST_BLOCK Srb; 00036 } XA_CONTEXT, *PXA_CONTEXT; 00037 00038 typedef struct _ERROR_RECOVERY_DATA { 00039 MODE_PARAMETER_HEADER Header; 00040 MODE_PARAMETER_BLOCK BlockDescriptor; 00041 MODE_READ_RECOVERY_PAGE ReadRecoveryPage; 00042 } ERROR_RECOVERY_DATA, *PERROR_RECOVERY_DATA; 00043 00044 typedef struct _ERROR_RECOVERY_DATA10 { 00045 MODE_PARAMETER_HEADER10 Header10; 00046 MODE_PARAMETER_BLOCK BlockDescriptor10; 00047 MODE_READ_RECOVERY_PAGE ReadRecoveryPage10; 00048 } ERROR_RECOVERY_DATA10, *PERROR_RECOVERY_DATA10; 00049 00050 // 00051 // CdRom specific addition to device extension. 00052 // 00053 00054 typedef struct _CDROM_DATA { 00055 00056 // 00057 // Indicates whether an audio play operation 00058 // is currently being performed. 00059 // 00060 00061 BOOLEAN PlayActive; 00062 00063 // 00064 // Indicates whether the blocksize used for user data 00065 // is 2048 or 2352. 00066 // 00067 00068 BOOLEAN RawAccess; 00069 00070 // 00071 // Indicates whether 6 or 10 byte mode sense/select 00072 // should be used. 00073 // 00074 00075 USHORT XAFlags; 00076 00077 // 00078 // Storage for the error recovery page. This is used 00079 // as an easy method to switch block sizes. 00080 // 00081 00082 union { 00083 ERROR_RECOVERY_DATA u1; 00084 ERROR_RECOVERY_DATA10 u2; 00085 }; 00086 00087 00088 // 00089 // Pointer to the original irp for the raw read. 00090 // 00091 00092 PIRP SavedReadIrp; 00093 00094 // 00095 // Used to protect accesses to the RawAccess flag. 00096 // 00097 00098 KSPIN_LOCK FormSpinLock; 00099 00100 // 00101 // Even if media change support is requested, there are some devices 00102 // that are not supported. This flag will indicate that such a device 00103 // is present when it is FALSE. 00104 // 00105 00106 BOOLEAN MediaChangeSupported; 00107 00108 // 00109 // The media change event is being supported. The media change timer 00110 // should be running whenever this is true. 00111 // 00112 00113 BOOLEAN MediaChange; 00114 00115 // 00116 // The timer value to support media change events. This is a countdown 00117 // value used to determine when to poll the device for a media change. 00118 // The max value for the timer is 255 seconds. 00119 // 00120 00121 UCHAR MediaChangeCountDown; 00122 00123 #if DBG 00124 // 00125 // Second timer to keep track of how long the media change IRP has been 00126 // in use. If this value exceeds the timeout (#defined) then we should 00127 // print out a message to the user and set the MediaChangeIrpLost flag 00128 // 00129 00130 SHORT MediaChangeIrpTimeInUse; 00131 00132 // 00133 // Set by CdRomTickHandler when we determine that the media change irp has 00134 // been lost 00135 // 00136 00137 BOOLEAN MediaChangeIrpLost; 00138 #endif 00139 00140 UCHAR PadReserve; // use this for new flags. 00141 00142 // 00143 // An IRP is allocated and kept for the duration that media change 00144 // detection is in effect. If this is NULL and MediaChange is TRUE, 00145 // the detection is in progress. This should always be NULL when 00146 // MediaChange is FALSE. 00147 // 00148 00149 PIRP MediaChangeIrp; 00150 00151 // 00152 // The timer work list is a collection of IRPS that are prepared for 00153 // submission, but need to allow some time to pass before they are 00154 // run. 00155 // 00156 00157 LIST_ENTRY TimerIrpList; 00158 KSPIN_LOCK TimerIrpSpinLock; 00159 00160 } CDROM_DATA, *PCDROM_DATA; 00161 00162 #define DEVICE_EXTENSION_SIZE sizeof(DEVICE_EXTENSION) + sizeof(CDROM_DATA) 00163 #define SCSI_CDROM_TIMEOUT 10 00164 #define SCSI_CHANGER_BONUS_TIMEOUT 10 00165 #define HITACHI_MODE_DATA_SIZE 12 00166 #define MODE_DATA_SIZE 64 00167 #define RAW_SECTOR_SIZE 2352 00168 #define COOKED_SECTOR_SIZE 2048 00169 #define MEDIA_CHANGE_DEFAULT_TIME 4 00170 #define CDROM_SRB_LIST_SIZE 4 00171 00172 00173 #if DBG 00174 00175 // 00176 // Used to detect the loss of the autorun irp. The driver prints out a message 00177 // (debug level 0) if this timeout ever occurs 00178 // 00179 #define MEDIA_CHANGE_TIMEOUT_TIME 300 00180 00181 #endif 00182 00183 #define PLAY_ACTIVE(DeviceExtension) (((PCDROM_DATA)(DeviceExtension + 1))->PlayActive) 00184 00185 #define MSF_TO_LBA(Minutes,Seconds,Frames) \ 00186 (ULONG)((60 * 75 * (Minutes)) + (75 * (Seconds)) + ((Frames) - 150)) 00187 00188 #define LBA_TO_MSF(Lba,Minutes,Seconds,Frames) \ 00189 { \ 00190 (Minutes) = (UCHAR)(Lba / (60 * 75)); \ 00191 (Seconds) = (UCHAR)((Lba % (60 * 75)) / 75); \ 00192 (Frames) = (UCHAR)((Lba % (60 * 75)) % 75); \ 00193 } 00194 00195 #define DEC_TO_BCD(x) (((x / 10) << 4) + (x % 10)) 00196 00197 // 00198 // Define flags for XA, CDDA, and Mode Select/Sense 00199 // 00200 00201 #define XA_USE_6_BYTE 0x01 00202 #define XA_USE_10_BYTE 0x02 00203 #define XA_USE_READ_CD 0x04 00204 #define XA_NOT_SUPPORTED 0x08 00205 00206 #define PLEXTOR_CDDA 0x10 00207 #define NEC_CDDA 0x20 00208 00209 // 00210 // Sector types for READ_CD 00211 // 00212 00213 #define ANY_SECTOR 0 00214 #define CD_DA_SECTOR 1 00215 #define YELLOW_MODE1_SECTOR 2 00216 #define YELLOW_MODE2_SECTOR 3 00217 #define FORM2_MODE1_SECTOR 4 00218 #define FORM2_MODE2_SECTOR 5 00219 00220 00221 #ifdef POOL_TAGGING 00222 #ifdef ExAllocatePool 00223 #undef ExAllocatePool 00224 #endif 00225 #define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'CscS') 00226 #endif 00227 00228 NTSTATUS 00229 NTAPI 00230 DriverEntry( 00231 IN PDRIVER_OBJECT DriverObject, 00232 IN PUNICODE_STRING RegistryPath 00233 ); 00234 00235 BOOLEAN 00236 NTAPI 00237 ScsiCdRomFindDevices( 00238 IN PDRIVER_OBJECT DriverObject, 00239 IN PUNICODE_STRING RegistryPath, 00240 IN PCLASS_INIT_DATA InitializationData, 00241 IN PDEVICE_OBJECT PortDeviceObject, 00242 IN ULONG PortNumber 00243 ); 00244 00245 NTSTATUS 00246 NTAPI 00247 ScsiCdRomOpenClose( 00248 IN PDEVICE_OBJECT DeviceObject, 00249 IN PIRP Irp 00250 ); 00251 00252 NTSTATUS 00253 NTAPI 00254 ScsiCdRomReadVerification( 00255 IN PDEVICE_OBJECT DeviceObject, 00256 IN PIRP Irp 00257 ); 00258 00259 NTSTATUS 00260 NTAPI 00261 ScsiCdRomSwitchMode( 00262 IN PDEVICE_OBJECT DeviceObject, 00263 IN ULONG SectorSize, 00264 IN PIRP OriginalRequest 00265 ); 00266 00267 NTSTATUS 00268 NTAPI 00269 CdRomDeviceControl( 00270 IN PDEVICE_OBJECT DeviceObject, 00271 IN PIRP Irp 00272 ); 00273 00274 IO_COMPLETION_ROUTINE CdRomDeviceControlCompletion; 00275 NTSTATUS 00276 NTAPI 00277 CdRomDeviceControlCompletion( 00278 IN PDEVICE_OBJECT DeviceObject, 00279 IN PIRP Irp, 00280 IN PVOID Context 00281 ); 00282 00283 IO_COMPLETION_ROUTINE CdRomSetVolumeIntermediateCompletion; 00284 NTSTATUS 00285 NTAPI 00286 CdRomSetVolumeIntermediateCompletion( 00287 IN PDEVICE_OBJECT DeviceObject, 00288 IN PIRP Irp, 00289 IN PVOID Context 00290 ); 00291 00292 IO_COMPLETION_ROUTINE CdRomSwitchModeCompletion; 00293 NTSTATUS 00294 NTAPI 00295 CdRomSwitchModeCompletion( 00296 IN PDEVICE_OBJECT DeviceObject, 00297 IN PIRP Irp, 00298 IN PVOID Context 00299 ); 00300 00301 IO_COMPLETION_ROUTINE CdRomXACompletion; 00302 NTSTATUS 00303 NTAPI 00304 CdRomXACompletion( 00305 IN PDEVICE_OBJECT DeviceObject, 00306 IN PIRP Irp, 00307 IN PVOID Context 00308 ); 00309 00310 IO_COMPLETION_ROUTINE CdRomClassIoctlCompletion; 00311 NTSTATUS 00312 NTAPI 00313 CdRomClassIoctlCompletion( 00314 IN PDEVICE_OBJECT DeviceObject, 00315 IN PIRP Irp, 00316 IN PVOID Context 00317 ); 00318 00319 VOID 00320 NTAPI 00321 ScsiCdRomStartIo( 00322 IN PDEVICE_OBJECT DeviceObject, 00323 IN PIRP Irp 00324 ); 00325 00326 VOID 00327 NTAPI 00328 CdRomTickHandler( 00329 IN PDEVICE_OBJECT DeviceObject, 00330 IN PVOID Context 00331 ); 00332 00333 BOOLEAN 00334 NTAPI 00335 CdRomCheckRegistryForMediaChangeValue( 00336 IN PUNICODE_STRING RegistryPath, 00337 IN ULONG DeviceNumber 00338 ); 00339 00340 NTSTATUS 00341 NTAPI 00342 CdRomUpdateCapacity( 00343 IN PDEVICE_EXTENSION DeviceExtension, 00344 IN PIRP IrpToComplete, 00345 IN OPTIONAL PKEVENT IoctlEvent 00346 ); 00347 00348 NTSTATUS 00349 NTAPI 00350 CreateCdRomDeviceObject( 00351 IN PDRIVER_OBJECT DriverObject, 00352 IN PDEVICE_OBJECT PortDeviceObject, 00353 IN ULONG PortNumber, 00354 IN PULONG DeviceCount, 00355 PIO_SCSI_CAPABILITIES PortCapabilities, 00356 IN PSCSI_INQUIRY_DATA LunInfo, 00357 IN PCLASS_INIT_DATA InitializationData, 00358 IN PUNICODE_STRING RegistryPath 00359 ); 00360 00361 VOID 00362 NTAPI 00363 ScanForSpecial( 00364 PDEVICE_OBJECT DeviceObject, 00365 PINQUIRYDATA InquiryData, 00366 PIO_SCSI_CAPABILITIES PortCapabilities 00367 ); 00368 00369 BOOLEAN 00370 NTAPI 00371 CdRomIsPlayActive( 00372 IN PDEVICE_OBJECT DeviceObject 00373 ); 00374 00375 VOID 00376 NTAPI 00377 HitachProcessError( 00378 PDEVICE_OBJECT DeviceObject, 00379 PSCSI_REQUEST_BLOCK Srb, 00380 NTSTATUS *Status, 00381 BOOLEAN *Retry 00382 ); 00383 00384 IO_COMPLETION_ROUTINE ToshibaProcessErrorCompletion; 00385 VOID 00386 NTAPI 00387 ToshibaProcessError( 00388 PDEVICE_OBJECT DeviceObject, 00389 PSCSI_REQUEST_BLOCK Srb, 00390 NTSTATUS *Status, 00391 BOOLEAN *Retry 00392 ); 00393 00394 BOOLEAN 00395 NTAPI 00396 IsThisAnAtapiChanger( 00397 IN PDEVICE_OBJECT DeviceObject, 00398 OUT PULONG DiscsPresent 00399 ); 00400 00401 BOOLEAN 00402 NTAPI 00403 IsThisASanyo( 00404 IN PDEVICE_OBJECT DeviceObject, 00405 IN UCHAR PathId, 00406 IN UCHAR TargetId 00407 ); 00408 00409 BOOLEAN 00410 NTAPI 00411 IsThisAMultiLunDevice( 00412 IN PDEVICE_OBJECT DeviceObject, 00413 IN PDEVICE_OBJECT PortDeviceObject 00414 ); 00415 00416 VOID 00417 NTAPI 00418 CdRomCreateNamedEvent( 00419 IN PDEVICE_EXTENSION DeviceExtension, 00420 IN ULONG DeviceNumber 00421 ); 00422 00423 #ifdef _PPC_ 00424 NTSTATUS 00425 FindScsiAdapter ( 00426 IN HANDLE KeyHandle, 00427 IN UNICODE_STRING ScsiUnicodeString[], 00428 OUT PUCHAR IntermediateController 00429 ); 00430 #endif 00431 00432 #ifdef ALLOC_PRAGMA 00433 #pragma alloc_text(PAGE, DriverEntry) 00434 #pragma alloc_text(PAGE, ScsiCdRomFindDevices) 00435 #pragma alloc_text(PAGE, CreateCdRomDeviceObject) 00436 #pragma alloc_text(PAGE, ScanForSpecial) 00437 //#pragma alloc_text(PAGE, CdRomDeviceControl) 00438 #pragma alloc_text(PAGE, HitachProcessError) 00439 #pragma alloc_text(PAGE, CdRomIsPlayActive) 00440 #pragma alloc_text(PAGE, ScsiCdRomReadVerification) 00441 #pragma alloc_text(INIT, CdRomCheckRegistryForMediaChangeValue) 00442 #pragma alloc_text(INIT, IsThisAnAtapiChanger) 00443 #pragma alloc_text(INIT, IsThisASanyo) 00444 #pragma alloc_text(INIT, IsThisAMultiLunDevice) 00445 #pragma alloc_text(INIT, CdRomCreateNamedEvent) 00446 #ifdef _PPC_ 00447 #pragma alloc_text(PAGE, FindScsiAdapter) 00448 #endif 00449 #endif 00450 00451 ULONG NoLoad = 0; 00452 00453 NTSTATUS 00454 NTAPI 00455 DriverEntry( 00456 IN PDRIVER_OBJECT DriverObject, 00457 IN PUNICODE_STRING RegistryPath 00458 ) 00459 00460 /*++ 00461 00462 Routine Description: 00463 00464 This routine initializes the cdrom class driver. 00465 00466 Arguments: 00467 00468 DriverObject - Pointer to driver object created by system. 00469 00470 RegistryPath - Pointer to the name of the services node for this driver. 00471 00472 Return Value: 00473 00474 The function value is the final status from the initialization operation. 00475 00476 --*/ 00477 00478 { 00479 CLASS_INIT_DATA InitializationData; 00480 00481 if(NoLoad) { 00482 return STATUS_NO_SUCH_DEVICE; 00483 } 00484 00485 // 00486 // Zero InitData 00487 // 00488 00489 RtlZeroMemory (&InitializationData, sizeof(CLASS_INIT_DATA)); 00490 00491 // 00492 // Set sizes 00493 // 00494 00495 InitializationData.InitializationDataSize = sizeof(CLASS_INIT_DATA); 00496 InitializationData.DeviceExtensionSize = DEVICE_EXTENSION_SIZE; 00497 00498 InitializationData.DeviceType = FILE_DEVICE_CD_ROM; 00499 InitializationData.DeviceCharacteristics = FILE_REMOVABLE_MEDIA | FILE_READ_ONLY_DEVICE; 00500 00501 // 00502 // Set entry points 00503 // 00504 00505 InitializationData.ClassReadWriteVerification = ScsiCdRomReadVerification; 00506 InitializationData.ClassDeviceControl = CdRomDeviceControl; 00507 InitializationData.ClassFindDevices = ScsiCdRomFindDevices; 00508 InitializationData.ClassShutdownFlush = NULL; 00509 InitializationData.ClassCreateClose = NULL; 00510 InitializationData.ClassStartIo = ScsiCdRomStartIo; 00511 00512 // 00513 // Call the class init routine 00514 // 00515 00516 return ScsiClassInitialize( DriverObject, RegistryPath, &InitializationData); 00517 00518 } // end DriverEntry() 00519 00520 BOOLEAN 00521 NTAPI 00522 ScsiCdRomFindDevices( 00523 IN PDRIVER_OBJECT DriverObject, 00524 IN PUNICODE_STRING RegistryPath, 00525 IN PCLASS_INIT_DATA InitializationData, 00526 IN PDEVICE_OBJECT PortDeviceObject, 00527 IN ULONG PortNumber 00528 ) 00529 00530 /*++ 00531 00532 Routine Description: 00533 00534 Connect to SCSI port driver. Get adapter capabilities and 00535 SCSI bus configuration information. Search inquiry data 00536 for CDROM devices to process. 00537 00538 Arguments: 00539 00540 DriverObject - CDROM class driver object. 00541 PortDeviceObject - SCSI port driver device object. 00542 PortNumber - The system ordinal for this scsi adapter. 00543 00544 Return Value: 00545 00546 TRUE if CDROM device present on this SCSI adapter. 00547 00548 --*/ 00549 00550 { 00551 PIO_SCSI_CAPABILITIES portCapabilities; 00552 PULONG cdRomCount; 00553 PCHAR buffer; 00554 PSCSI_INQUIRY_DATA lunInfo; 00555 PSCSI_ADAPTER_BUS_INFO adapterInfo; 00556 PINQUIRYDATA inquiryData; 00557 ULONG scsiBus; 00558 NTSTATUS status; 00559 BOOLEAN foundDevice = FALSE; 00560 00561 // 00562 // Call port driver to get adapter capabilities. 00563 // 00564 00565 status = ScsiClassGetCapabilities(PortDeviceObject, &portCapabilities); 00566 00567 if (!NT_SUCCESS(status)) { 00568 DebugPrint((1,"FindScsiDevices: ScsiClassGetCapabilities failed\n")); 00569 return foundDevice; 00570 } 00571 00572 // 00573 // Call port driver to get inquiry information to find cdroms. 00574 // 00575 00576 status = ScsiClassGetInquiryData(PortDeviceObject, (PSCSI_ADAPTER_BUS_INFO *) &buffer); 00577 00578 if (!NT_SUCCESS(status)) { 00579 DebugPrint((1,"FindScsiDevices: ScsiClassGetInquiryData failed\n")); 00580 return foundDevice; 00581 } 00582 00583 // 00584 // Get the address of the count of the number of cdroms already initialized. 00585 // 00586 00587 cdRomCount = &IoGetConfigurationInformation()->CdRomCount; 00588 adapterInfo = (PVOID) buffer; 00589 00590 // 00591 // For each SCSI bus this adapter supports ... 00592 // 00593 00594 for (scsiBus=0; scsiBus < adapterInfo->NumberOfBuses; scsiBus++) { 00595 00596 // 00597 // Get the SCSI bus scan data for this bus. 00598 // 00599 00600 lunInfo = (PVOID) (buffer + adapterInfo->BusData[scsiBus].InquiryDataOffset); 00601 00602 // 00603 // Search list for unclaimed disk devices. 00604 // 00605 00606 while (adapterInfo->BusData[scsiBus].InquiryDataOffset) { 00607 00608 inquiryData = (PVOID)lunInfo->InquiryData; 00609 00610 if ((inquiryData->DeviceType == READ_ONLY_DIRECT_ACCESS_DEVICE) && 00611 (inquiryData->DeviceTypeQualifier == 0) && 00612 (!lunInfo->DeviceClaimed)) { 00613 00614 DebugPrint((1,"FindScsiDevices: Vendor string is %.24s\n", 00615 inquiryData->VendorId)); 00616 00617 // 00618 // Create device objects for cdrom 00619 // 00620 00621 status = CreateCdRomDeviceObject(DriverObject, 00622 PortDeviceObject, 00623 PortNumber, 00624 cdRomCount, 00625 portCapabilities, 00626 lunInfo, 00627 InitializationData, 00628 RegistryPath); 00629 00630 if (NT_SUCCESS(status)) { 00631 00632 // 00633 // Increment system cdrom device count. 00634 // 00635 00636 (*cdRomCount)++; 00637 00638 // 00639 // Indicate that a cdrom device was found. 00640 // 00641 00642 foundDevice = TRUE; 00643 } 00644 } 00645 00646 // 00647 // Get next LunInfo. 00648 // 00649 00650 if (lunInfo->NextInquiryDataOffset == 0) { 00651 break; 00652 } 00653 00654 lunInfo = (PVOID) (buffer + lunInfo->NextInquiryDataOffset); 00655 } 00656 } 00657 00658 ExFreePool(buffer); 00659 00660 00661 return foundDevice; 00662 00663 } // end FindScsiCdRoms() 00664 00665 VOID 00666 NTAPI 00667 CdRomCreateNamedEvent( 00668 IN PDEVICE_EXTENSION DeviceExtension, 00669 IN ULONG DeviceNumber 00670 ) 00671 00672 /*++ 00673 00674 Routine Description: 00675 00676 Create the named synchronization event for notification of media change 00677 events to the system. The event is reset before this function returns. 00678 00679 Arguments: 00680 00681 DeviceExtension - the device extension pointer for storage of the event pointer. 00682 00683 Return Value: 00684 00685 None. 00686 00687 --*/ 00688 00689 { 00690 UNICODE_STRING unicodeString; 00691 OBJECT_ATTRIBUTES objectAttributes; 00692 CCHAR eventNameBuffer[MAXIMUM_FILENAME_LENGTH]; 00693 STRING eventNameString; 00694 HANDLE handle; 00695 NTSTATUS status; 00696 00697 00698 sprintf(eventNameBuffer,"\\Device\\MediaChangeEvent%ld", 00699 DeviceNumber); 00700 00701 RtlInitString(&eventNameString, 00702 eventNameBuffer); 00703 00704 status = RtlAnsiStringToUnicodeString(&unicodeString, 00705 &eventNameString, 00706 TRUE); 00707 00708 if (!NT_SUCCESS(status)) { 00709 return; 00710 } 00711 00712 InitializeObjectAttributes(&objectAttributes, 00713 &unicodeString, 00714 OBJ_PERMANENT | OBJ_CASE_INSENSITIVE | OBJ_OPENIF, 00715 NULL, 00716 NULL); 00717 00718 DeviceExtension->MediaChangeEvent = IoCreateSynchronizationEvent(&unicodeString, 00719 &handle); 00720 DeviceExtension->MediaChangeEventHandle = handle; 00721 00722 KeClearEvent(DeviceExtension->MediaChangeEvent); 00723 00724 RtlFreeUnicodeString(&unicodeString); 00725 } 00726 00727 NTSTATUS 00728 NTAPI 00729 CreateCdRomDeviceObject( 00730 IN PDRIVER_OBJECT DriverObject, 00731 IN PDEVICE_OBJECT PortDeviceObject, 00732 IN ULONG PortNumber, 00733 IN PULONG DeviceCount, 00734 IN PIO_SCSI_CAPABILITIES PortCapabilities, 00735 IN PSCSI_INQUIRY_DATA LunInfo, 00736 IN PCLASS_INIT_DATA InitializationData, 00737 IN PUNICODE_STRING RegistryPath 00738 ) 00739 00740 /*++ 00741 00742 Routine Description: 00743 00744 This routine creates an object for the device and then calls the 00745 SCSI port driver for media capacity and sector size. 00746 00747 Arguments: 00748 00749 DriverObject - Pointer to driver object created by system. 00750 PortDeviceObject - to connect to SCSI port driver. 00751 DeviceCount - Number of previously installed CDROMs. 00752 PortCapabilities - Pointer to structure returned by SCSI port 00753 driver describing adapter capabilites (and limitations). 00754 LunInfo - Pointer to configuration information for this device. 00755 00756 Return Value: 00757 00758 NTSTATUS 00759 00760 --*/ 00761 { 00762 CHAR ntNameBuffer[64]; 00763 NTSTATUS status; 00764 BOOLEAN changerDevice; 00765 SCSI_REQUEST_BLOCK srb; 00766 ULONG length; 00767 PCDROM_DATA cddata; 00768 PCDB cdb; 00769 PVOID senseData = NULL; 00770 PDEVICE_OBJECT deviceObject = NULL; 00771 PDEVICE_EXTENSION deviceExtension = NULL; 00772 PUCHAR buffer; 00773 ULONG bps; 00774 ULONG lastBit; 00775 ULONG timeOut; 00776 BOOLEAN srbListInitialized = FALSE; 00777 00778 // 00779 // Claim the device. Note that any errors after this 00780 // will goto the generic handler, where the device will 00781 // be released. 00782 // 00783 00784 status = ScsiClassClaimDevice(PortDeviceObject, 00785 LunInfo, 00786 FALSE, 00787 &PortDeviceObject); 00788 00789 if (!NT_SUCCESS(status)) { 00790 return(status); 00791 } 00792 00793 // 00794 // Create device object for this device. 00795 // 00796 00797 sprintf(ntNameBuffer, 00798 "\\Device\\CdRom%lu", 00799 *DeviceCount); 00800 00801 status = ScsiClassCreateDeviceObject(DriverObject, 00802 ntNameBuffer, 00803 NULL, 00804 &deviceObject, 00805 InitializationData); 00806 00807 if (!NT_SUCCESS(status)) { 00808 DebugPrint((1,"CreateCdRomDeviceObjects: Can not create device %s\n", 00809 ntNameBuffer)); 00810 00811 goto CreateCdRomDeviceObjectExit; 00812 } 00813 00814 // 00815 // Indicate that IRPs should include MDLs. 00816 // 00817 00818 deviceObject->Flags |= DO_DIRECT_IO; 00819 00820 // 00821 // Set up required stack size in device object. 00822 // 00823 00824 deviceObject->StackSize = PortDeviceObject->StackSize + 2; 00825 00826 deviceExtension = deviceObject->DeviceExtension; 00827 00828 // 00829 // Allocate spinlock for split request completion. 00830 // 00831 00832 KeInitializeSpinLock(&deviceExtension->SplitRequestSpinLock); 00833 00834 // 00835 // This is the physical device. 00836 // 00837 00838 deviceExtension->PhysicalDevice = deviceObject; 00839 00840 // 00841 // Initialize lock count to zero. The lock count is used to 00842 // disable the ejection mechanism when media is mounted. 00843 // 00844 00845 deviceExtension->LockCount = 0; 00846 00847 // 00848 // Save system cdrom number 00849 // 00850 00851 deviceExtension->DeviceNumber = *DeviceCount; 00852 00853 // 00854 // Copy port device object to device extension. 00855 // 00856 00857 deviceExtension->PortDeviceObject = PortDeviceObject; 00858 00859 // 00860 // Set the alignment requirements for the device based on the 00861 // host adapter requirements 00862 // 00863 00864 if (PortDeviceObject->AlignmentRequirement > deviceObject->AlignmentRequirement) { 00865 deviceObject->AlignmentRequirement = PortDeviceObject->AlignmentRequirement; 00866 } 00867 00868 // 00869 // Save address of port driver capabilities. 00870 // 00871 00872 deviceExtension->PortCapabilities = PortCapabilities; 00873 00874 // 00875 // Clear SRB flags. 00876 // 00877 00878 deviceExtension->SrbFlags = 0; 00879 deviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER; 00880 00881 // 00882 // Allocate request sense buffer. 00883 // 00884 00885 senseData = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE); 00886 00887 if (senseData == NULL) { 00888 00889 // 00890 // The buffer cannot be allocated. 00891 // 00892 00893 status = STATUS_INSUFFICIENT_RESOURCES; 00894 goto CreateCdRomDeviceObjectExit; 00895 } 00896 00897 // 00898 // Set the sense data pointer in the device extension. 00899 // 00900 00901 deviceExtension->SenseData = senseData; 00902 00903 // 00904 // CDROMs are not partitionable so starting offset is 0. 00905 // 00906 00907 deviceExtension->StartingOffset.LowPart = 0; 00908 deviceExtension->StartingOffset.HighPart = 0; 00909 00910 // 00911 // Path/TargetId/LUN describes a device location on the SCSI bus. 00912 // This information comes from the LunInfo buffer. 00913 // 00914 00915 deviceExtension->PortNumber = (UCHAR)PortNumber; 00916 deviceExtension->PathId = LunInfo->PathId; 00917 deviceExtension->TargetId = LunInfo->TargetId; 00918 deviceExtension->Lun = LunInfo->Lun; 00919 00920 // 00921 // Set timeout value in seconds. 00922 // 00923 00924 timeOut = ScsiClassQueryTimeOutRegistryValue(RegistryPath); 00925 if (timeOut) { 00926 deviceExtension->TimeOutValue = timeOut; 00927 } else { 00928 deviceExtension->TimeOutValue = SCSI_CDROM_TIMEOUT; 00929 } 00930 00931 // 00932 // Build the lookaside list for srb's for the physical disk. Should only 00933 // need a couple. 00934 // 00935 00936 ScsiClassInitializeSrbLookasideList(deviceExtension, 00937 CDROM_SRB_LIST_SIZE); 00938 00939 srbListInitialized = TRUE; 00940 00941 // 00942 // Back pointer to device object. 00943 // 00944 00945 deviceExtension->DeviceObject = deviceObject; 00946 00947 // 00948 // Allocate buffer for drive geometry. 00949 // 00950 00951 deviceExtension->DiskGeometry = 00952 ExAllocatePool(NonPagedPool, sizeof(DISK_GEOMETRY_EX)); 00953 00954 if (deviceExtension->DiskGeometry == NULL) { 00955 00956 status = STATUS_INSUFFICIENT_RESOURCES; 00957 goto CreateCdRomDeviceObjectExit; 00958 } 00959 00960 // 00961 // Set up media change support defaults. 00962 // 00963 00964 cddata = (PCDROM_DATA)(deviceExtension + 1); 00965 00966 KeInitializeSpinLock(&cddata->FormSpinLock); 00967 KeInitializeSpinLock(&cddata->TimerIrpSpinLock); 00968 InitializeListHead(&cddata->TimerIrpList); 00969 00970 cddata->MediaChangeCountDown = MEDIA_CHANGE_DEFAULT_TIME; 00971 cddata->MediaChangeSupported = FALSE; 00972 cddata->MediaChange = FALSE; 00973 00974 // 00975 // Assume that there is initially no media in the device 00976 // only notify upper layers if there is something there 00977 // 00978 00979 deviceExtension->MediaChangeNoMedia = TRUE; 00980 cddata->MediaChangeIrp = NULL; 00981 #if DBG 00982 cddata->MediaChangeIrpTimeInUse = 0; 00983 cddata->MediaChangeIrpLost = FALSE; 00984 #endif 00985 00986 // 00987 // Scan for Scsi controllers that require special processing. 00988 // 00989 00990 ScanForSpecial(deviceObject, 00991 (PINQUIRYDATA) LunInfo->InquiryData, 00992 PortCapabilities); 00993 00994 // 00995 // Do READ CAPACITY. This SCSI command 00996 // returns the last sector address on the device 00997 // and the bytes per sector. 00998 // These are used to calculate the drive capacity 00999 // in bytes. 01000 // 01001 01002 status = ScsiClassReadDriveCapacity(deviceObject); 01003 bps = deviceExtension->DiskGeometry->Geometry.BytesPerSector; 01004 01005 if (!NT_SUCCESS(status) || !bps) { 01006 01007 DebugPrint((1, 01008 "CreateCdRomDeviceObjects: Can't read capacity for device %s\n", 01009 ntNameBuffer)); 01010 01011 // 01012 // Set disk geometry to default values (per ISO 9660). 01013 // 01014 01015 bps = 2048; 01016 deviceExtension->SectorShift = 11; 01017 deviceExtension->PartitionLength.QuadPart = (LONGLONG)(0x7fffffff); 01018 } else { 01019 01020 // 01021 // Insure that bytes per sector is a power of 2 01022 // This corrects a problem with the HP 4020i CDR where it 01023 // returns an incorrect number for bytes per sector. 01024 // 01025 01026 lastBit = (ULONG) -1; 01027 while (bps) { 01028 lastBit++; 01029 bps = bps >> 1; 01030 } 01031 01032 bps = 1 << lastBit; 01033 } 01034 deviceExtension->DiskGeometry->Geometry.BytesPerSector = bps; 01035 DebugPrint((2, "CreateCdRomDeviceObject: Calc'd bps = %x\n", bps)); 01036 01037 // 01038 // Check to see if this is some sort of changer device 01039 // 01040 01041 changerDevice = FALSE; 01042 01043 // 01044 // Search for devices that have special requirements for media 01045 // change support. 01046 // 01047 01048 if (deviceExtension->Lun > 0) { 01049 changerDevice = TRUE; 01050 } 01051 01052 if (!changerDevice) { 01053 changerDevice = IsThisASanyo(deviceObject, deviceExtension->PathId, 01054 deviceExtension->TargetId); 01055 } 01056 01057 if (!changerDevice) { 01058 ULONG tmp; 01059 changerDevice = IsThisAnAtapiChanger(deviceObject, &tmp); 01060 } 01061 01062 if (!changerDevice) { 01063 changerDevice = IsThisAMultiLunDevice(deviceObject, PortDeviceObject); 01064 } 01065 01066 // 01067 // If it is a changer device, increment the timeout to take platter-swapping 01068 // time into account 01069 // 01070 01071 if(changerDevice) { 01072 deviceExtension->TimeOutValue += SCSI_CHANGER_BONUS_TIMEOUT; 01073 } 01074 01075 // 01076 // Create the media change named event. If this succeeds then continue 01077 // initializing the media change support data items. 01078 // 01079 01080 CdRomCreateNamedEvent(deviceExtension,*DeviceCount); 01081 if (deviceExtension->MediaChangeEvent) { 01082 01083 // 01084 // If this is not a changer, get an IRP for the timer request 01085 // and initialize the timer. 01086 // 01087 01088 if (!changerDevice) { 01089 01090 // 01091 // Not a changer device - continue with media change initialization. 01092 // Determine if the user actually wants media change events. 01093 // 01094 01095 if (CdRomCheckRegistryForMediaChangeValue(RegistryPath, *DeviceCount)) { 01096 PIO_STACK_LOCATION irpStack; 01097 PSCSI_REQUEST_BLOCK srb; 01098 PIRP irp; 01099 01100 // 01101 // User wants it - preallocate IRP and SRB. 01102 // 01103 01104 irp = IoAllocateIrp((CCHAR)(deviceObject->StackSize+1), 01105 FALSE); 01106 if (irp) { 01107 PVOID buffer; 01108 01109 srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK)); 01110 buffer = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE); 01111 01112 if (srb && buffer) { 01113 PCDB cdb; 01114 01115 // 01116 // All resources have been allocated set up the IRP. 01117 // 01118 01119 IoSetNextIrpStackLocation(irp); 01120 irpStack = IoGetCurrentIrpStackLocation(irp); 01121 irpStack->DeviceObject = deviceObject; 01122 irpStack = IoGetNextIrpStackLocation(irp); 01123 cddata->MediaChangeIrp = irp; 01124 irpStack->Parameters.Scsi.Srb = srb; 01125 01126 // 01127 // Initialize the SRB 01128 // 01129 01130 RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK)); 01131 01132 srb->CdbLength = 6; 01133 srb->TimeOutValue = deviceExtension->TimeOutValue * 2; 01134 srb->QueueTag = SP_UNTAGGED; 01135 srb->QueueAction = SRB_SIMPLE_TAG_REQUEST; 01136 srb->Length = SCSI_REQUEST_BLOCK_SIZE; 01137 srb->PathId = deviceExtension->PathId; 01138 srb->TargetId = deviceExtension->TargetId; 01139 srb->Lun = deviceExtension->Lun; 01140 srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 01141 01142 // 01143 // Initialize and set up the sense information buffer 01144 // 01145 01146 RtlZeroMemory(buffer, SENSE_BUFFER_SIZE); 01147 srb->SenseInfoBuffer = buffer; 01148 srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE; 01149 01150 // 01151 // Initialize the CDB 01152 // 01153 01154 cdb = (PCDB)&srb->Cdb[0]; 01155 cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY; 01156 cdb->CDB6GENERIC.LogicalUnitNumber = deviceExtension->Lun; 01157 01158 // 01159 // It is ok to support media change events on this device. 01160 // 01161 01162 cddata->MediaChangeSupported = TRUE; 01163 cddata->MediaChange = TRUE; 01164 01165 } else { 01166 01167 if (srb) { 01168 ExFreePool(srb); 01169 } 01170 if (buffer) { 01171 ExFreePool(buffer); 01172 } 01173 IoFreeIrp(irp); 01174 } 01175 } 01176 } else { 01177 deviceExtension->MediaChangeEvent = NULL; 01178 } 01179 } else { 01180 deviceExtension->MediaChangeEvent = NULL; 01181 } 01182 } 01183 01184 // 01185 // Assume use of 6-byte mode sense/select for now. 01186 // 01187 01188 cddata->XAFlags |= XA_USE_6_BYTE; 01189 01190 // 01191 // Build and issue mode sense with Read error recovery page. This will be used to change 01192 // block size in case of any raw reads (Mode 2, Form 2). 01193 // 01194 01195 length = (sizeof(MODE_READ_RECOVERY_PAGE) + MODE_BLOCK_DESC_LENGTH + MODE_HEADER_LENGTH); 01196 01197 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK)); 01198 01199 srb.CdbLength = 6; 01200 cdb = (PCDB)srb.Cdb; 01201 01202 // 01203 // Set timeout value from device extension. 01204 // 01205 01206 srb.TimeOutValue = deviceExtension->TimeOutValue; 01207 01208 // 01209 // Build the MODE SENSE CDB. The data returned will be kept in the device extension 01210 // and used to set block size. 01211 // 01212 01213 cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE; 01214 cdb->MODE_SENSE.PageCode = 0x1; 01215 cdb->MODE_SENSE.AllocationLength = (UCHAR)length; 01216 01217 buffer = ExAllocatePool(NonPagedPoolCacheAligned, (sizeof(MODE_READ_RECOVERY_PAGE) + MODE_BLOCK_DESC_LENGTH + MODE_HEADER_LENGTH10)); 01218 if (!buffer) { 01219 status = STATUS_INSUFFICIENT_RESOURCES; 01220 goto CreateCdRomDeviceObjectExit; 01221 } 01222 01223 status = ScsiClassSendSrbSynchronous(deviceObject, 01224 &srb, 01225 buffer, 01226 length, 01227 FALSE); 01228 if (!NT_SUCCESS(status)) { 01229 01230 // 01231 // May be Atapi, try 10-byte. 01232 // 01233 01234 length = (sizeof(MODE_READ_RECOVERY_PAGE) + MODE_BLOCK_DESC_LENGTH + MODE_HEADER_LENGTH10); 01235 01236 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK)); 01237 01238 // 01239 // Build the MODE SENSE CDB. 01240 // 01241 01242 srb.CdbLength = 10; 01243 cdb = (PCDB)srb.Cdb; 01244 01245 // 01246 // Set timeout value from device extension. 01247 // 01248 01249 srb.TimeOutValue = deviceExtension->TimeOutValue; 01250 01251 cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10; 01252 cdb->MODE_SENSE10.PageCode = 0x1; 01253 01254 cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(length >> 8); 01255 cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(length & 0xFF); 01256 01257 status = ScsiClassSendSrbSynchronous(deviceObject, 01258 &srb, 01259 buffer, 01260 length, 01261 FALSE); 01262 if (status == STATUS_DATA_OVERRUN) { 01263 01264 // 01265 // Build and issue the ReadCd command to ensure that this device supports it. 01266 // 01267 01268 RtlZeroMemory(cdb, 12); 01269 01270 cdb->READ_CD.OperationCode = SCSIOP_READ_CD; 01271 01272 status = ScsiClassSendSrbSynchronous(deviceObject, 01273 &srb, 01274 NULL, 01275 0, 01276 FALSE); 01277 01278 // 01279 // If the command wasn't rejected then support the READ_CD. 01280 // 01281 01282 if (NT_SUCCESS(status) || (status == STATUS_NO_MEDIA_IN_DEVICE)) { 01283 01284 // 01285 // Using Read CD precludes issueing a mode select to 01286 // set the user data size. So, no buffer copy is 01287 // necessary. 01288 // 01289 01290 cddata->XAFlags &= ~XA_USE_6_BYTE; 01291 cddata->XAFlags = XA_USE_READ_CD | XA_USE_10_BYTE; 01292 } else { 01293 01294 RtlCopyMemory(&cddata->u1.Header, buffer, sizeof(ERROR_RECOVERY_DATA10)); 01295 cddata->u1.Header.ModeDataLength = 0; 01296 01297 cddata->XAFlags &= ~XA_USE_6_BYTE; 01298 cddata->XAFlags |= XA_USE_10_BYTE; 01299 } 01300 01301 } else if (NT_SUCCESS(status)) { 01302 01303 RtlCopyMemory(&cddata->u1.Header, buffer, sizeof(ERROR_RECOVERY_DATA10)); 01304 cddata->u1.Header.ModeDataLength = 0; 01305 01306 cddata->XAFlags &= ~XA_USE_6_BYTE; 01307 cddata->XAFlags |= XA_USE_10_BYTE; 01308 01309 } else { 01310 cddata->XAFlags |= XA_NOT_SUPPORTED; 01311 } 01312 } else { 01313 RtlCopyMemory(&cddata->u1.Header, buffer, sizeof(ERROR_RECOVERY_DATA)); 01314 cddata->u1.Header.ModeDataLength = 0; 01315 } 01316 01317 ExFreePool(buffer); 01318 01319 // 01320 // Start the timer now regardless of if Autorun is enabled. 01321 // The timer must run forever since IoStopTimer faults. 01322 // 01323 01324 IoInitializeTimer(deviceObject, CdRomTickHandler, NULL); 01325 IoStartTimer(deviceObject); 01326 01327 return(STATUS_SUCCESS); 01328 01329 CreateCdRomDeviceObjectExit: 01330 01331 // 01332 // Release the device since an error occured. 01333 // 01334 01335 ScsiClassClaimDevice(PortDeviceObject, 01336 LunInfo, 01337 TRUE, 01338 NULL); 01339 01340 if (senseData != NULL) { 01341 ExFreePool(senseData); 01342 } 01343 01344 if (deviceExtension->DiskGeometry != NULL) { 01345 ExFreePool(deviceExtension->DiskGeometry); 01346 } 01347 01348 if (deviceObject != NULL) { 01349 if (srbListInitialized) { 01350 ExDeleteNPagedLookasideList(&deviceExtension->SrbLookasideListHead); 01351 } 01352 IoDeleteDevice(deviceObject); 01353 } 01354 01355 01356 return status; 01357 01358 } // end CreateCdRomDeviceObject() 01359 01360 VOID 01361 NTAPI 01362 ScsiCdRomStartIo( 01363 IN PDEVICE_OBJECT DeviceObject, 01364 IN PIRP Irp 01365 ) 01366 { 01367 01368 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 01369 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp); 01370 PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp); 01371 PIO_STACK_LOCATION irpStack; 01372 PIRP irp2 = NULL; 01373 ULONG transferPages; 01374 ULONG transferByteCount = currentIrpStack->Parameters.Read.Length; 01375 ULONG maximumTransferLength = deviceExtension->PortCapabilities->MaximumTransferLength; 01376 PCDROM_DATA cdData; 01377 PSCSI_REQUEST_BLOCK srb = NULL; 01378 PCDB cdb; 01379 PUCHAR senseBuffer = NULL; 01380 PVOID dataBuffer; 01381 NTSTATUS status; 01382 BOOLEAN use6Byte; 01383 01384 // 01385 // Mark IRP with status pending. 01386 // 01387 01388 IoMarkIrpPending(Irp); 01389 01390 // 01391 // If the flag is set in the device object, force a verify. 01392 // 01393 01394 if (DeviceObject->Flags & DO_VERIFY_VOLUME) { 01395 DebugPrint((2, "ScsiCdRomStartIo: [%lx] Volume needs verified\n", Irp)); 01396 if (!(currentIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME)) { 01397 01398 if (Irp->Tail.Overlay.Thread) { 01399 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject); 01400 } 01401 01402 Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED; 01403 01404 DebugPrint((2, "ScsiCdRomStartIo: [%lx] Calling UpdateCapcity - " 01405 "ioctl event = %lx\n", 01406 Irp, 01407 nextIrpStack->Parameters.Others.Argument1 01408 )); 01409 01410 // 01411 // our device control dispatch routine stores an event in the next 01412 // stack location to signal when startio has completed. We need to 01413 // pass this in so that the update capacity completion routine can 01414 // set it rather than completing the Irp. 01415 // 01416 01417 status = CdRomUpdateCapacity(deviceExtension, 01418 Irp, 01419 nextIrpStack->Parameters.Others.Argument1 01420 ); 01421 01422 DebugPrint((2, "ScsiCdRomStartIo: [%lx] UpdateCapacity returned %lx\n", Irp, status)); 01423 ASSERT(status == STATUS_PENDING); 01424 return; 01425 } 01426 } 01427 01428 cdData = (PCDROM_DATA)(deviceExtension + 1); 01429 use6Byte = cdData->XAFlags & XA_USE_6_BYTE; 01430 01431 if (currentIrpStack->MajorFunction == IRP_MJ_READ) { 01432 01433 // 01434 // Add partition byte offset to make starting byte relative to 01435 // beginning of disk. In addition, add in skew for DM Driver, if any. 01436 // 01437 01438 currentIrpStack->Parameters.Read.ByteOffset.QuadPart += (deviceExtension->StartingOffset.QuadPart); 01439 01440 // 01441 // Calculate number of pages in this transfer. 01442 // 01443 01444 transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp->MdlAddress), 01445 currentIrpStack->Parameters.Read.Length); 01446 01447 // 01448 // Check if request length is greater than the maximum number of 01449 // bytes that the hardware can transfer. 01450 // 01451 01452 if (cdData->RawAccess) { 01453 01454 ASSERT(!(cdData->XAFlags & XA_USE_READ_CD)); 01455 01456 // 01457 // Fire off a mode select to switch back to cooked sectors. 01458 // 01459 01460 irp2 = IoAllocateIrp((CCHAR)(deviceExtension->DeviceObject->StackSize+1), 01461 FALSE); 01462 01463 if (!irp2) { 01464 Irp->IoStatus.Information = 0; 01465 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 01466 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 01467 IoStartNextPacket(DeviceObject, FALSE); 01468 return; 01469 } 01470 01471 srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK)); 01472 if (!srb) { 01473 Irp->IoStatus.Information = 0; 01474 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 01475 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 01476 IoFreeIrp(irp2); 01477 IoStartNextPacket(DeviceObject, FALSE); 01478 return; 01479 } 01480 01481 RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK)); 01482 01483 cdb = (PCDB)srb->Cdb; 01484 01485 // 01486 // Allocate sense buffer. 01487 // 01488 01489 senseBuffer = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE); 01490 01491 if (!senseBuffer) { 01492 Irp->IoStatus.Information = 0; 01493 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 01494 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 01495 ExFreePool(srb); 01496 IoFreeIrp(irp2); 01497 IoStartNextPacket(DeviceObject, FALSE); 01498 return; 01499 } 01500 01501 // 01502 // Set up the irp. 01503 // 01504 01505 IoSetNextIrpStackLocation(irp2); 01506 irp2->IoStatus.Status = STATUS_SUCCESS; 01507 irp2->IoStatus.Information = 0; 01508 irp2->Flags = 0; 01509 irp2->UserBuffer = NULL; 01510 01511 // 01512 // Save the device object and irp in a private stack location. 01513 // 01514 01515 irpStack = IoGetCurrentIrpStackLocation(irp2); 01516 irpStack->DeviceObject = deviceExtension->DeviceObject; 01517 irpStack->Parameters.Others.Argument2 = (PVOID) Irp; 01518 01519 // 01520 // The retry count will be in the real Irp, as the retry logic will 01521 // recreate our private irp. 01522 // 01523 01524 if (!(nextIrpStack->Parameters.Others.Argument1)) { 01525 01526 // 01527 // Only jam this in if it doesn't exist. The completion routines can 01528 // call StartIo directly in the case of retries and resetting it will 01529 // cause infinite loops. 01530 // 01531 01532 nextIrpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES; 01533 } 01534 01535 // 01536 // Construct the IRP stack for the lower level driver. 01537 // 01538 01539 irpStack = IoGetNextIrpStackLocation(irp2); 01540 irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; 01541 irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN; 01542 irpStack->Parameters.Scsi.Srb = srb; 01543 01544 srb->Length = SCSI_REQUEST_BLOCK_SIZE; 01545 srb->PathId = deviceExtension->PathId; 01546 srb->TargetId = deviceExtension->TargetId; 01547 srb->Lun = deviceExtension->Lun; 01548 srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 01549 srb->Cdb[1] |= deviceExtension->Lun << 5; 01550 srb->SrbStatus = srb->ScsiStatus = 0; 01551 srb->NextSrb = 0; 01552 srb->OriginalRequest = irp2; 01553 srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE; 01554 srb->SenseInfoBuffer = senseBuffer; 01555 01556 transferByteCount = (use6Byte) ? sizeof(ERROR_RECOVERY_DATA) : sizeof(ERROR_RECOVERY_DATA10); 01557 dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned, transferByteCount ); 01558 if (!dataBuffer) { 01559 Irp->IoStatus.Information = 0; 01560 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 01561 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 01562 ExFreePool(senseBuffer); 01563 ExFreePool(srb); 01564 IoFreeIrp(irp2); 01565 IoStartNextPacket(DeviceObject, FALSE); 01566 return; 01567 01568 } 01569 01570 irp2->MdlAddress = IoAllocateMdl(dataBuffer, 01571 transferByteCount, 01572 FALSE, 01573 FALSE, 01574 (PIRP) NULL); 01575 01576 if (!irp2->MdlAddress) { 01577 Irp->IoStatus.Information = 0; 01578 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 01579 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 01580 ExFreePool(senseBuffer); 01581 ExFreePool(srb); 01582 ExFreePool(dataBuffer); 01583 IoFreeIrp(irp2); 01584 IoStartNextPacket(DeviceObject, FALSE); 01585 return; 01586 } 01587 01588 // 01589 // Prepare the MDL 01590 // 01591 01592 MmBuildMdlForNonPagedPool(irp2->MdlAddress); 01593 01594 srb->DataBuffer = dataBuffer; 01595 01596 // 01597 // Set the new block size in the descriptor. 01598 // 01599 01600 cdData->u1.BlockDescriptor.BlockLength[0] = (UCHAR)(COOKED_SECTOR_SIZE >> 16) & 0xFF; 01601 cdData->u1.BlockDescriptor.BlockLength[1] = (UCHAR)(COOKED_SECTOR_SIZE >> 8) & 0xFF; 01602 cdData->u1.BlockDescriptor.BlockLength[2] = (UCHAR)(COOKED_SECTOR_SIZE & 0xFF); 01603 01604 // 01605 // Move error page into dataBuffer. 01606 // 01607 01608 RtlCopyMemory(srb->DataBuffer, &cdData->u1.Header, transferByteCount); 01609 01610 // 01611 // Build and send a mode select to switch into raw mode. 01612 // 01613 01614 srb->SrbFlags = deviceExtension->SrbFlags; 01615 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_OUT); 01616 srb->DataTransferLength = transferByteCount; 01617 srb->TimeOutValue = deviceExtension->TimeOutValue * 2; 01618 01619 if (use6Byte) { 01620 srb->CdbLength = 6; 01621 cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT; 01622 cdb->MODE_SELECT.PFBit = 1; 01623 cdb->MODE_SELECT.ParameterListLength = (UCHAR)transferByteCount; 01624 } else { 01625 01626 srb->CdbLength = 10; 01627 cdb->MODE_SELECT10.OperationCode = SCSIOP_MODE_SELECT10; 01628 cdb->MODE_SELECT10.PFBit = 1; 01629 cdb->MODE_SELECT10.ParameterListLength[0] = (UCHAR)(transferByteCount >> 8); 01630 cdb->MODE_SELECT10.ParameterListLength[1] = (UCHAR)(transferByteCount & 0xFF); 01631 } 01632 01633 // 01634 // Update completion routine. 01635 // 01636 01637 IoSetCompletionRoutine(irp2, 01638 CdRomSwitchModeCompletion, 01639 srb, 01640 TRUE, 01641 TRUE, 01642 TRUE); 01643 01644 IoCallDriver(deviceExtension->PortDeviceObject, irp2); 01645 return; 01646 } 01647 01648 if ((currentIrpStack->Parameters.Read.Length > maximumTransferLength) || 01649 (transferPages > 01650 deviceExtension->PortCapabilities->MaximumPhysicalPages)) { 01651 01652 // 01653 // Request needs to be split. Completion of each portion of the 01654 // request will fire off the next portion. The final request will 01655 // signal Io to send a new request. 01656 // 01657 01658 transferPages = 01659 deviceExtension->PortCapabilities->MaximumPhysicalPages - 1; 01660 01661 if(maximumTransferLength > transferPages << PAGE_SHIFT) { 01662 maximumTransferLength = transferPages << PAGE_SHIFT; 01663 } 01664 01665 // 01666 // Check that the maximum transfer size is not zero 01667 // 01668 01669 if(maximumTransferLength == 0) { 01670 maximumTransferLength = PAGE_SIZE; 01671 } 01672 01673 ScsiClassSplitRequest(DeviceObject, Irp, maximumTransferLength); 01674 return; 01675 01676 } else { 01677 01678 // 01679 // Build SRB and CDB for this IRP. 01680 // 01681 01682 ScsiClassBuildRequest(DeviceObject, Irp); 01683 01684 } 01685 01686 01687 } else if (currentIrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) { 01688 01689 // 01690 // Allocate an irp, srb and associated structures. 01691 // 01692 01693 irp2 = IoAllocateIrp((CCHAR)(deviceExtension->DeviceObject->StackSize+1), 01694 FALSE); 01695 01696 if (!irp2) { 01697 Irp->IoStatus.Information = 0; 01698 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 01699 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 01700 IoStartNextPacket(DeviceObject, FALSE); 01701 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp, Irp->IoStatus.Status, __LINE__)); 01702 return; 01703 } 01704 01705 srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK)); 01706 if (!srb) { 01707 Irp->IoStatus.Information = 0; 01708 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 01709 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 01710 IoFreeIrp(irp2); 01711 IoStartNextPacket(DeviceObject, FALSE); 01712 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp, Irp->IoStatus.Status, __LINE__)); 01713 return; 01714 } 01715 01716 RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK)); 01717 01718 cdb = (PCDB)srb->Cdb; 01719 01720 // 01721 // Allocate sense buffer. 01722 // 01723 01724 senseBuffer = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE); 01725 01726 if (!senseBuffer) { 01727 Irp->IoStatus.Information = 0; 01728 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 01729 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 01730 ExFreePool(srb); 01731 IoFreeIrp(irp2); 01732 IoStartNextPacket(DeviceObject, FALSE); 01733 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp, Irp->IoStatus.Status, __LINE__)); 01734 return; 01735 } 01736 01737 // 01738 // Set up the irp. 01739 // 01740 01741 IoSetNextIrpStackLocation(irp2); 01742 irp2->IoStatus.Status = STATUS_SUCCESS; 01743 irp2->IoStatus.Information = 0; 01744 irp2->Flags = 0; 01745 irp2->UserBuffer = NULL; 01746 01747 // 01748 // Save the device object and irp in a private stack location. 01749 // 01750 01751 irpStack = IoGetCurrentIrpStackLocation(irp2); 01752 irpStack->DeviceObject = deviceExtension->DeviceObject; 01753 irpStack->Parameters.Others.Argument2 = (PVOID) Irp; 01754 01755 // 01756 // The retry count will be in the real Irp, as the retry logic will 01757 // recreate our private irp. 01758 // 01759 01760 if (!(nextIrpStack->Parameters.Others.Argument1)) { 01761 01762 // 01763 // Only jam this in if it doesn't exist. The completion routines can 01764 // call StartIo directly in the case of retries and resetting it will 01765 // cause infinite loops. 01766 // 01767 01768 nextIrpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES; 01769 } 01770 01771 // 01772 // Construct the IRP stack for the lower level driver. 01773 // 01774 01775 irpStack = IoGetNextIrpStackLocation(irp2); 01776 irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; 01777 irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN; 01778 irpStack->Parameters.Scsi.Srb = srb; 01779 01780 IoSetCompletionRoutine(irp2, 01781 CdRomDeviceControlCompletion, 01782 srb, 01783 TRUE, 01784 TRUE, 01785 TRUE); 01786 // 01787 // Setup those fields that are generic to all requests. 01788 // 01789 01790 srb->Length = SCSI_REQUEST_BLOCK_SIZE; 01791 srb->PathId = deviceExtension->PathId; 01792 srb->TargetId = deviceExtension->TargetId; 01793 srb->Lun = deviceExtension->Lun; 01794 srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 01795 srb->Cdb[1] |= deviceExtension->Lun << 5; 01796 srb->SrbStatus = srb->ScsiStatus = 0; 01797 srb->NextSrb = 0; 01798 srb->OriginalRequest = irp2; 01799 srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE; 01800 srb->SenseInfoBuffer = senseBuffer; 01801 01802 switch (currentIrpStack->Parameters.DeviceIoControl.IoControlCode) { 01803 01804 case IOCTL_CDROM_RAW_READ: { 01805 01806 // 01807 // Determine whether the drive is currently in raw or cooked mode, 01808 // and which command to use to read the data. 01809 // 01810 01811 if (!(cdData->XAFlags & XA_USE_READ_CD)) { 01812 01813 PRAW_READ_INFO rawReadInfo = 01814 (PRAW_READ_INFO)currentIrpStack->Parameters.DeviceIoControl.Type3InputBuffer; 01815 ULONG maximumTransferLength; 01816 ULONG transferPages; 01817 01818 if (cdData->RawAccess) { 01819 01820 ULONG startingSector; 01821 01822 // 01823 // Free the recently allocated irp, as we don't need it. 01824 // 01825 01826 IoFreeIrp(irp2); 01827 01828 cdb = (PCDB)srb->Cdb; 01829 RtlZeroMemory(cdb, 12); 01830 01831 // 01832 // Calculate starting offset. 01833 // 01834 01835 startingSector = (ULONG)(rawReadInfo->DiskOffset.QuadPart >> deviceExtension->SectorShift); 01836 transferByteCount = rawReadInfo->SectorCount * RAW_SECTOR_SIZE; 01837 maximumTransferLength = deviceExtension->PortCapabilities->MaximumTransferLength; 01838 transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp->MdlAddress), 01839 transferByteCount); 01840 01841 // 01842 // Determine if request is within limits imposed by miniport. 01843 // 01844 01845 if (transferByteCount > maximumTransferLength || 01846 transferPages > deviceExtension->PortCapabilities->MaximumPhysicalPages) { 01847 01848 // 01849 // The claim is that this won't happen, and is backed up by 01850 // ActiveMovie usage, which does unbuffered XA reads of 0x18000, yet 01851 // we get only 4 sector requests. 01852 // 01853 01854 01855 Irp->IoStatus.Information = 0; 01856 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; 01857 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 01858 ExFreePool(senseBuffer); 01859 ExFreePool(srb); 01860 IoStartNextPacket(DeviceObject, FALSE); 01861 return; 01862 01863 } 01864 01865 srb->OriginalRequest = Irp; 01866 srb->SrbFlags = deviceExtension->SrbFlags; 01867 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN); 01868 srb->DataTransferLength = transferByteCount; 01869 srb->TimeOutValue = deviceExtension->TimeOutValue; 01870 srb->CdbLength = 10; 01871 srb->DataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress); 01872 01873 if (rawReadInfo->TrackMode == CDDA) { 01874 if (cdData->XAFlags & PLEXTOR_CDDA) { 01875 01876 srb->CdbLength = 12; 01877 01878 cdb->PLXTR_READ_CDDA.LogicalUnitNumber = deviceExtension->Lun; 01879 cdb->PLXTR_READ_CDDA.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF); 01880 cdb->PLXTR_READ_CDDA.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF); 01881 cdb->PLXTR_READ_CDDA.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF); 01882 cdb->PLXTR_READ_CDDA.LogicalBlockByte0 = (UCHAR) ((startingSector >> 24) & 0xFF); 01883 01884 cdb->PLXTR_READ_CDDA.TransferBlockByte3 = (UCHAR) (rawReadInfo->SectorCount & 0xFF); 01885 cdb->PLXTR_READ_CDDA.TransferBlockByte2 = (UCHAR) (rawReadInfo->SectorCount >> 8); 01886 cdb->PLXTR_READ_CDDA.TransferBlockByte1 = 0; 01887 cdb->PLXTR_READ_CDDA.TransferBlockByte0 = 0; 01888 01889 cdb->PLXTR_READ_CDDA.SubCode = 0; 01890 cdb->PLXTR_READ_CDDA.OperationCode = 0xD8; 01891 01892 } else if (cdData->XAFlags & NEC_CDDA) { 01893 01894 cdb->NEC_READ_CDDA.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF); 01895 cdb->NEC_READ_CDDA.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF); 01896 cdb->NEC_READ_CDDA.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF); 01897 cdb->NEC_READ_CDDA.LogicalBlockByte0 = (UCHAR) ((startingSector >> 24) & 0xFF); 01898 01899 cdb->NEC_READ_CDDA.TransferBlockByte1 = (UCHAR) (rawReadInfo->SectorCount & 0xFF); 01900 cdb->NEC_READ_CDDA.TransferBlockByte0 = (UCHAR) (rawReadInfo->SectorCount >> 8); 01901 01902 cdb->NEC_READ_CDDA.OperationCode = 0xD4; 01903 } 01904 } else { 01905 01906 cdb->CDB10.LogicalUnitNumber = deviceExtension->Lun; 01907 01908 cdb->CDB10.TransferBlocksMsb = (UCHAR) (rawReadInfo->SectorCount >> 8); 01909 cdb->CDB10.TransferBlocksLsb = (UCHAR) (rawReadInfo->SectorCount & 0xFF); 01910 01911 cdb->CDB10.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF); 01912 cdb->CDB10.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF); 01913 cdb->CDB10.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF); 01914 cdb->CDB10.LogicalBlockByte0 = (UCHAR) ((startingSector >> 24) & 0xFF); 01915 01916 cdb->CDB10.OperationCode = SCSIOP_READ; 01917 } 01918 01919 srb->SrbStatus = srb->ScsiStatus = 0; 01920 01921 nextIrpStack->MajorFunction = IRP_MJ_SCSI; 01922 nextIrpStack->Parameters.Scsi.Srb = srb; 01923 01924 if (!(nextIrpStack->Parameters.Others.Argument1)) { 01925 01926 // 01927 // Only jam this in if it doesn't exist. The completion routines can 01928 // call StartIo directly in the case of retries and resetting it will 01929 // cause infinite loops. 01930 // 01931 01932 nextIrpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES; 01933 } 01934 01935 // 01936 // Set up IoCompletion routine address. 01937 // 01938 01939 IoSetCompletionRoutine(Irp, 01940 CdRomXACompletion, 01941 srb, 01942 TRUE, 01943 TRUE, 01944 TRUE); 01945 01946 IoCallDriver(deviceExtension->PortDeviceObject, Irp); 01947 return; 01948 01949 } else { 01950 01951 transferByteCount = (use6Byte) ? sizeof(ERROR_RECOVERY_DATA) : sizeof(ERROR_RECOVERY_DATA10); 01952 dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned, transferByteCount ); 01953 if (!dataBuffer) { 01954 Irp->IoStatus.Information = 0; 01955 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 01956 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 01957 ExFreePool(senseBuffer); 01958 ExFreePool(srb); 01959 IoFreeIrp(irp2); 01960 IoStartNextPacket(DeviceObject, FALSE); 01961 return; 01962 01963 } 01964 01965 irp2->MdlAddress = IoAllocateMdl(dataBuffer, 01966 transferByteCount, 01967 FALSE, 01968 FALSE, 01969 (PIRP) NULL); 01970 01971 if (!irp2->MdlAddress) { 01972 Irp->IoStatus.Information = 0; 01973 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 01974 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 01975 ExFreePool(senseBuffer); 01976 ExFreePool(srb); 01977 ExFreePool(dataBuffer); 01978 IoFreeIrp(irp2); 01979 IoStartNextPacket(DeviceObject, FALSE); 01980 return; 01981 } 01982 01983 // 01984 // Prepare the MDL 01985 // 01986 01987 MmBuildMdlForNonPagedPool(irp2->MdlAddress); 01988 01989 srb->DataBuffer = dataBuffer; 01990 01991 // 01992 // Set the new block size in the descriptor. 01993 // 01994 01995 cdData->u1.BlockDescriptor.BlockLength[0] = (UCHAR)(RAW_SECTOR_SIZE >> 16) & 0xFF; 01996 cdData->u1.BlockDescriptor.BlockLength[1] = (UCHAR)(RAW_SECTOR_SIZE >> 8) & 0xFF; 01997 cdData->u1.BlockDescriptor.BlockLength[2] = (UCHAR)(RAW_SECTOR_SIZE & 0xFF); 01998 01999 02000 // 02001 // TODO: Set density code, based on operation 02002 // 02003 02004 cdData->u1.BlockDescriptor.DensityCode = 0; 02005 02006 02007 // 02008 // Move error page into dataBuffer. 02009 // 02010 02011 RtlCopyMemory(srb->DataBuffer, &cdData->u1.Header, transferByteCount); 02012 02013 02014 // 02015 // Build and send a mode select to switch into raw mode. 02016 // 02017 02018 srb->SrbFlags = deviceExtension->SrbFlags; 02019 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_OUT); 02020 srb->DataTransferLength = transferByteCount; 02021 srb->TimeOutValue = deviceExtension->TimeOutValue * 2; 02022 02023 if (use6Byte) { 02024 srb->CdbLength = 6; 02025 cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT; 02026 cdb->MODE_SELECT.PFBit = 1; 02027 cdb->MODE_SELECT.ParameterListLength = (UCHAR)transferByteCount; 02028 } else { 02029 02030 srb->CdbLength = 10; 02031 cdb->MODE_SELECT10.OperationCode = SCSIOP_MODE_SELECT10; 02032 cdb->MODE_SELECT10.PFBit = 1; 02033 cdb->MODE_SELECT10.ParameterListLength[0] = (UCHAR)(transferByteCount >> 8); 02034 cdb->MODE_SELECT10.ParameterListLength[1] = (UCHAR)(transferByteCount & 0xFF); 02035 } 02036 02037 // 02038 // Update completion routine. 02039 // 02040 02041 IoSetCompletionRoutine(irp2, 02042 CdRomSwitchModeCompletion, 02043 srb, 02044 TRUE, 02045 TRUE, 02046 TRUE); 02047 02048 } 02049 02050 } else { 02051 02052 PRAW_READ_INFO rawReadInfo = 02053 (PRAW_READ_INFO)currentIrpStack->Parameters.DeviceIoControl.Type3InputBuffer; 02054 ULONG startingSector; 02055 02056 // 02057 // Free the recently allocated irp, as we don't need it. 02058 // 02059 02060 IoFreeIrp(irp2); 02061 02062 cdb = (PCDB)srb->Cdb; 02063 RtlZeroMemory(cdb, 12); 02064 02065 02066 // 02067 // Calculate starting offset. 02068 // 02069 02070 startingSector = (ULONG)(rawReadInfo->DiskOffset.QuadPart >> deviceExtension->SectorShift); 02071 transferByteCount = rawReadInfo->SectorCount * RAW_SECTOR_SIZE; 02072 02073 02074 srb->OriginalRequest = Irp; 02075 srb->SrbFlags = deviceExtension->SrbFlags; 02076 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN); 02077 srb->DataTransferLength = transferByteCount; 02078 srb->TimeOutValue = deviceExtension->TimeOutValue; 02079 srb->DataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress); 02080 srb->CdbLength = 12; 02081 srb->SrbStatus = srb->ScsiStatus = 0; 02082 02083 // 02084 // Fill in CDB fields. 02085 // 02086 02087 cdb = (PCDB)srb->Cdb; 02088 02089 02090 cdb->READ_CD.TransferBlocks[2] = (UCHAR) (rawReadInfo->SectorCount & 0xFF); 02091 cdb->READ_CD.TransferBlocks[1] = (UCHAR) (rawReadInfo->SectorCount >> 8 ); 02092 cdb->READ_CD.TransferBlocks[0] = (UCHAR) (rawReadInfo->SectorCount >> 16); 02093 02094 02095 cdb->READ_CD.StartingLBA[3] = (UCHAR) (startingSector & 0xFF); 02096 cdb->READ_CD.StartingLBA[2] = (UCHAR) ((startingSector >> 8)); 02097 cdb->READ_CD.StartingLBA[1] = (UCHAR) ((startingSector >> 16)); 02098 cdb->READ_CD.StartingLBA[0] = (UCHAR) ((startingSector >> 24)); 02099 02100 // 02101 // Setup cdb depending upon the sector type we want. 02102 // 02103 02104 switch (rawReadInfo->TrackMode) { 02105 case CDDA: 02106 02107 cdb->READ_CD.ExpectedSectorType = CD_DA_SECTOR; 02108 cdb->READ_CD.IncludeUserData = 1; 02109 cdb->READ_CD.HeaderCode = 3; 02110 cdb->READ_CD.IncludeSyncData = 1; 02111 break; 02112 02113 case YellowMode2: 02114 02115 cdb->READ_CD.ExpectedSectorType = YELLOW_MODE2_SECTOR; 02116 cdb->READ_CD.IncludeUserData = 1; 02117 cdb->READ_CD.HeaderCode = 1; 02118 cdb->READ_CD.IncludeSyncData = 1; 02119 break; 02120 02121 case XAForm2: 02122 02123 cdb->READ_CD.ExpectedSectorType = FORM2_MODE2_SECTOR; 02124 cdb->READ_CD.IncludeUserData = 1; 02125 cdb->READ_CD.HeaderCode = 3; 02126 cdb->READ_CD.IncludeSyncData = 1; 02127 break; 02128 02129 default: 02130 Irp->IoStatus.Information = 0; 02131 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; 02132 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 02133 ExFreePool(senseBuffer); 02134 ExFreePool(srb); 02135 IoFreeIrp(irp2); 02136 IoStartNextPacket(DeviceObject, FALSE); 02137 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp, Irp->IoStatus.Status, __LINE__)); 02138 return; 02139 } 02140 02141 cdb->READ_CD.OperationCode = SCSIOP_READ_CD; 02142 02143 nextIrpStack->MajorFunction = IRP_MJ_SCSI; 02144 nextIrpStack->Parameters.Scsi.Srb = srb; 02145 02146 if (!(nextIrpStack->Parameters.Others.Argument1)) { 02147 02148 // 02149 // Only jam this in if it doesn't exist. The completion routines can 02150 // call StartIo directly in the case of retries and resetting it will 02151 // cause infinite loops. 02152 // 02153 02154 nextIrpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES; 02155 } 02156 02157 // 02158 // Set up IoCompletion routine address. 02159 // 02160 02161 IoSetCompletionRoutine(Irp, 02162 CdRomXACompletion, 02163 srb, 02164 TRUE, 02165 TRUE, 02166 TRUE); 02167 02168 IoCallDriver(deviceExtension->PortDeviceObject, Irp); 02169 return; 02170 02171 } 02172 02173 IoCallDriver(deviceExtension->PortDeviceObject, irp2); 02174 return; 02175 } 02176 02177 case IOCTL_CDROM_GET_DRIVE_GEOMETRY: { 02178 02179 // 02180 // Issue ReadCapacity to update device extension 02181 // with information for current media. 02182 // 02183 02184 DebugPrint((3, 02185 "CdRomStartIo: Get drive capacity\n")); 02186 02187 // 02188 // setup remaining srb and cdb parameters. 02189 // 02190 02191 srb->SrbFlags = deviceExtension->SrbFlags; 02192 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN); 02193 srb->DataTransferLength = sizeof(READ_CAPACITY_DATA); 02194 srb->CdbLength = 10; 02195 srb->TimeOutValue = deviceExtension->TimeOutValue; 02196 02197 dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned, sizeof(READ_CAPACITY_DATA)); 02198 if (!dataBuffer) { 02199 Irp->IoStatus.Information = 0; 02200 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 02201 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 02202 ExFreePool(senseBuffer); 02203 ExFreePool(srb); 02204 IoFreeIrp(irp2); 02205 IoStartNextPacket(DeviceObject, FALSE); 02206 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp, Irp->IoStatus.Status, __LINE__)); 02207 return; 02208 02209 } 02210 02211 irp2->MdlAddress = IoAllocateMdl(dataBuffer, 02212 sizeof(READ_CAPACITY_DATA), 02213 FALSE, 02214 FALSE, 02215 (PIRP) NULL); 02216 02217 if (!irp2->MdlAddress) { 02218 Irp->IoStatus.Information = 0; 02219 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 02220 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 02221 ExFreePool(senseBuffer); 02222 ExFreePool(srb); 02223 ExFreePool(dataBuffer); 02224 IoFreeIrp(irp2); 02225 IoStartNextPacket(DeviceObject, FALSE); 02226 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp, Irp->IoStatus.Status, __LINE__)); 02227 return; 02228 } 02229 02230 // 02231 // Prepare the MDL 02232 // 02233 02234 MmBuildMdlForNonPagedPool(irp2->MdlAddress); 02235 02236 srb->DataBuffer = dataBuffer; 02237 cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY; 02238 02239 IoCallDriver(deviceExtension->PortDeviceObject, irp2); 02240 return; 02241 } 02242 02243 case IOCTL_CDROM_CHECK_VERIFY: { 02244 02245 // 02246 // Since a test unit ready is about to be performed, reset the timer 02247 // value to decrease the opportunities for it to race with this code. 02248 // 02249 02250 cdData->MediaChangeCountDown = MEDIA_CHANGE_DEFAULT_TIME; 02251 02252 // 02253 // Set up the SRB/CDB 02254 // 02255 02256 srb->CdbLength = 6; 02257 cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY; 02258 srb->TimeOutValue = deviceExtension->TimeOutValue * 2; 02259 srb->SrbFlags = deviceExtension->SrbFlags; 02260 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_DATA_TRANSFER); 02261 02262 DebugPrint((2, "ScsiCdRomStartIo: [%lx] Sending CHECK_VERIFY irp %lx\n", Irp, irp2)); 02263 IoCallDriver(deviceExtension->PortDeviceObject, irp2); 02264 return; 02265 } 02266 02267 case IOCTL_CDROM_GET_LAST_SESSION: 02268 02269 // 02270 // Set format to return first and last session numbers. 02271 // 02272 02273 cdb->READ_TOC.Format = GET_LAST_SESSION; 02274 02275 // 02276 // Fall through to READ TOC code. 02277 // 02278 02279 case IOCTL_CDROM_READ_TOC: { 02280 02281 02282 if (currentIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_READ_TOC) { 02283 02284 // 02285 // Use MSF addressing if not request for session information. 02286 // 02287 02288 cdb->READ_TOC.Msf = CDB_USE_MSF; 02289 } 02290 02291 // 02292 // Set size of TOC structure. 02293 // 02294 02295 transferByteCount = 02296 currentIrpStack->Parameters.Read.Length > 02297 sizeof(CDROM_TOC) ? sizeof(CDROM_TOC): 02298 currentIrpStack->Parameters.Read.Length; 02299 02300 cdb->READ_TOC.AllocationLength[0] = (UCHAR) (transferByteCount >> 8); 02301 cdb->READ_TOC.AllocationLength[1] = (UCHAR) (transferByteCount & 0xFF); 02302 02303 cdb->READ_TOC.Control = 0; 02304 02305 // 02306 // Start at beginning of disc. 02307 // 02308 02309 cdb->READ_TOC.StartingTrack = 0; 02310 02311 // 02312 // setup remaining srb and cdb parameters. 02313 // 02314 02315 srb->SrbFlags = deviceExtension->SrbFlags; 02316 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN); 02317 srb->DataTransferLength = transferByteCount; 02318 srb->CdbLength = 10; 02319 srb->TimeOutValue = deviceExtension->TimeOutValue; 02320 02321 dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned, transferByteCount); 02322 if (!dataBuffer) { 02323 Irp->IoStatus.Information = 0; 02324 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 02325 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 02326 ExFreePool(senseBuffer); 02327 ExFreePool(srb); 02328 IoFreeIrp(irp2); 02329 IoStartNextPacket(DeviceObject, FALSE); 02330 return; 02331 02332 } 02333 02334 irp2->MdlAddress = IoAllocateMdl(dataBuffer, 02335 transferByteCount, 02336 FALSE, 02337 FALSE, 02338 (PIRP) NULL); 02339 02340 if (!irp2->MdlAddress) { 02341 Irp->IoStatus.Information = 0; 02342 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 02343 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 02344 ExFreePool(senseBuffer); 02345 ExFreePool(srb); 02346 ExFreePool(dataBuffer); 02347 IoFreeIrp(irp2); 02348 IoStartNextPacket(DeviceObject, FALSE); 02349 return; 02350 } 02351 02352 // 02353 // Prepare the MDL 02354 // 02355 02356 MmBuildMdlForNonPagedPool(irp2->MdlAddress); 02357 02358 srb->DataBuffer = dataBuffer; 02359 cdb->READ_TOC.OperationCode = SCSIOP_READ_TOC; 02360 02361 IoCallDriver(deviceExtension->PortDeviceObject, irp2); 02362 return; 02363 02364 } 02365 02366 case IOCTL_CDROM_PLAY_AUDIO_MSF: { 02367 02368 PCDROM_PLAY_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer; 02369 02370 // 02371 // Set up the SRB/CDB 02372 // 02373 02374 srb->CdbLength = 10; 02375 cdb->PLAY_AUDIO_MSF.OperationCode = SCSIOP_PLAY_AUDIO_MSF; 02376 02377 cdb->PLAY_AUDIO_MSF.StartingM = inputBuffer->StartingM; 02378 cdb->PLAY_AUDIO_MSF.StartingS = inputBuffer->StartingS; 02379 cdb->PLAY_AUDIO_MSF.StartingF = inputBuffer->StartingF; 02380 02381 cdb->PLAY_AUDIO_MSF.EndingM = inputBuffer->EndingM; 02382 cdb->PLAY_AUDIO_MSF.EndingS = inputBuffer->EndingS; 02383 cdb->PLAY_AUDIO_MSF.EndingF = inputBuffer->EndingF; 02384 02385 srb->TimeOutValue = deviceExtension->TimeOutValue; 02386 srb->SrbFlags = deviceExtension->SrbFlags; 02387 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_DATA_TRANSFER); 02388 02389 IoCallDriver(deviceExtension->PortDeviceObject, irp2); 02390 return; 02391 02392 } 02393 02394 case IOCTL_CDROM_READ_Q_CHANNEL: { 02395 02396 PCDROM_SUB_Q_DATA_FORMAT inputBuffer = 02397 Irp->AssociatedIrp.SystemBuffer; 02398 02399 // 02400 // Allocate buffer for subq channel information. 02401 // 02402 02403 dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned, 02404 sizeof(SUB_Q_CHANNEL_DATA)); 02405 02406 if (!dataBuffer) { 02407 Irp->IoStatus.Information = 0; 02408 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 02409 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 02410 ExFreePool(senseBuffer); 02411 ExFreePool(srb); 02412 IoFreeIrp(irp2); 02413 IoStartNextPacket(DeviceObject, FALSE); 02414 return; 02415 02416 } 02417 02418 irp2->MdlAddress = IoAllocateMdl(dataBuffer, 02419 transferByteCount, 02420 FALSE, 02421 FALSE, 02422 (PIRP) NULL); 02423 02424 if (!irp2->MdlAddress) { 02425 Irp->IoStatus.Information = 0; 02426 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 02427 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 02428 ExFreePool(senseBuffer); 02429 ExFreePool(srb); 02430 ExFreePool(dataBuffer); 02431 IoFreeIrp(irp2); 02432 IoStartNextPacket(DeviceObject, FALSE); 02433 return; 02434 } 02435 02436 // 02437 // Prepare the MDL 02438 // 02439 02440 MmBuildMdlForNonPagedPool(irp2->MdlAddress); 02441 02442 srb->DataBuffer = dataBuffer; 02443 02444 // 02445 // Always logical unit 0, but only use MSF addressing 02446 // for IOCTL_CDROM_CURRENT_POSITION 02447 // 02448 02449 if (inputBuffer->Format==IOCTL_CDROM_CURRENT_POSITION) 02450 cdb->SUBCHANNEL.Msf = CDB_USE_MSF; 02451 02452 // 02453 // Return subchannel data 02454 // 02455 02456 cdb->SUBCHANNEL.SubQ = CDB_SUBCHANNEL_BLOCK; 02457 02458 // 02459 // Specify format of informatin to return 02460 // 02461 02462 cdb->SUBCHANNEL.Format = inputBuffer->Format; 02463 02464 // 02465 // Specify which track to access (only used by Track ISRC reads) 02466 // 02467 02468 if (inputBuffer->Format==IOCTL_CDROM_TRACK_ISRC) { 02469 cdb->SUBCHANNEL.TrackNumber = inputBuffer->Track; 02470 } 02471 02472 // 02473 // Set size of channel data -- however, this is dependent on 02474 // what information we are requesting (which Format) 02475 // 02476 02477 switch( inputBuffer->Format ) { 02478 02479 case IOCTL_CDROM_CURRENT_POSITION: 02480 transferByteCount = sizeof(SUB_Q_CURRENT_POSITION); 02481 break; 02482 02483 case IOCTL_CDROM_MEDIA_CATALOG: 02484 transferByteCount = sizeof(SUB_Q_MEDIA_CATALOG_NUMBER); 02485 break; 02486 02487 case IOCTL_CDROM_TRACK_ISRC: 02488 transferByteCount = sizeof(SUB_Q_TRACK_ISRC); 02489 break; 02490 } 02491 02492 cdb->SUBCHANNEL.AllocationLength[0] = (UCHAR) (transferByteCount >> 8); 02493 cdb->SUBCHANNEL.AllocationLength[1] = (UCHAR) (transferByteCount & 0xFF); 02494 cdb->SUBCHANNEL.OperationCode = SCSIOP_READ_SUB_CHANNEL; 02495 srb->SrbFlags = deviceExtension->SrbFlags; 02496 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN); 02497 srb->DataTransferLength = transferByteCount; 02498 srb->CdbLength = 10; 02499 srb->TimeOutValue = deviceExtension->TimeOutValue; 02500 02501 IoCallDriver(deviceExtension->PortDeviceObject, irp2); 02502 return; 02503 02504 } 02505 02506 case IOCTL_CDROM_PAUSE_AUDIO: { 02507 02508 cdb->PAUSE_RESUME.OperationCode = SCSIOP_PAUSE_RESUME; 02509 cdb->PAUSE_RESUME.Action = CDB_AUDIO_PAUSE; 02510 02511 srb->CdbLength = 10; 02512 srb->TimeOutValue = deviceExtension->TimeOutValue; 02513 srb->SrbFlags = deviceExtension->SrbFlags; 02514 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_DATA_TRANSFER); 02515 02516 IoCallDriver(deviceExtension->PortDeviceObject, irp2); 02517 return; 02518 } 02519 02520 case IOCTL_CDROM_RESUME_AUDIO: { 02521 02522 cdb->PAUSE_RESUME.OperationCode = SCSIOP_PAUSE_RESUME; 02523 cdb->PAUSE_RESUME.Action = CDB_AUDIO_RESUME; 02524 02525 srb->CdbLength = 10; 02526 srb->TimeOutValue = deviceExtension->TimeOutValue; 02527 srb->SrbFlags = deviceExtension->SrbFlags; 02528 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_DATA_TRANSFER); 02529 02530 IoCallDriver(deviceExtension->PortDeviceObject, irp2); 02531 return; 02532 } 02533 02534 case IOCTL_CDROM_SEEK_AUDIO_MSF: { 02535 02536 PCDROM_SEEK_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer; 02537 ULONG logicalBlockAddress; 02538 02539 logicalBlockAddress = MSF_TO_LBA(inputBuffer->M, inputBuffer->S, inputBuffer->F); 02540 02541 cdb->SEEK.OperationCode = SCSIOP_SEEK; 02542 cdb->SEEK.LogicalBlockAddress[0] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte3; 02543 cdb->SEEK.LogicalBlockAddress[1] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte2; 02544 cdb->SEEK.LogicalBlockAddress[2] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte1; 02545 cdb->SEEK.LogicalBlockAddress[3] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte0; 02546 02547 srb->CdbLength = 10; 02548 srb->TimeOutValue = deviceExtension->TimeOutValue; 02549 srb->SrbFlags = deviceExtension->SrbFlags; 02550 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_DATA_TRANSFER); 02551 02552 IoCallDriver(deviceExtension->PortDeviceObject, irp2); 02553 return; 02554 02555 } 02556 02557 case IOCTL_CDROM_STOP_AUDIO: { 02558 02559 cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT; 02560 cdb->START_STOP.Immediate = 1; 02561 cdb->START_STOP.Start = 0; 02562 cdb->START_STOP.LoadEject = 0; 02563 02564 srb->CdbLength = 6; 02565 srb->TimeOutValue = deviceExtension->TimeOutValue; 02566 02567 srb->SrbFlags = deviceExtension->SrbFlags; 02568 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_DATA_TRANSFER); 02569 02570 IoCallDriver(deviceExtension->PortDeviceObject, irp2); 02571 return; 02572 } 02573 02574 case IOCTL_CDROM_GET_CONTROL: { 02575 // 02576 // Allocate buffer for volume control information. 02577 // 02578 02579 dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned, 02580 MODE_DATA_SIZE); 02581 02582 if (!dataBuffer) { 02583 Irp->IoStatus.Information = 0; 02584 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 02585 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 02586 ExFreePool(senseBuffer); 02587 ExFreePool(srb); 02588 IoFreeIrp(irp2); 02589 IoStartNextPacket(DeviceObject, FALSE); 02590 return; 02591 02592 } 02593 02594 irp2->MdlAddress = IoAllocateMdl(dataBuffer, 02595 MODE_DATA_SIZE, 02596 FALSE, 02597 FALSE, 02598 (PIRP) NULL); 02599 02600 if (!irp2->MdlAddress) { 02601 Irp->IoStatus.Information = 0; 02602 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 02603 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 02604 ExFreePool(senseBuffer); 02605 ExFreePool(srb); 02606 ExFreePool(dataBuffer); 02607 IoFreeIrp(irp2); 02608 IoStartNextPacket(DeviceObject, FALSE); 02609 return; 02610 } 02611 02612 // 02613 // Prepare the MDL 02614 // 02615 02616 MmBuildMdlForNonPagedPool(irp2->MdlAddress); 02617 srb->DataBuffer = dataBuffer; 02618 02619 RtlZeroMemory(dataBuffer, MODE_DATA_SIZE); 02620 02621 // 02622 // Setup for either 6 or 10 byte CDBs. 02623 // 02624 02625 if (use6Byte) { 02626 02627 cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE; 02628 cdb->MODE_SENSE.PageCode = CDROM_AUDIO_CONTROL_PAGE; 02629 cdb->MODE_SENSE.AllocationLength = MODE_DATA_SIZE; 02630 02631 // 02632 // Disable block descriptors. 02633 // 02634 02635 cdb->MODE_SENSE.Dbd = TRUE; 02636 02637 srb->CdbLength = 6; 02638 } else { 02639 02640 cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10; 02641 cdb->MODE_SENSE10.PageCode = CDROM_AUDIO_CONTROL_PAGE; 02642 cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(MODE_DATA_SIZE >> 8); 02643 cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(MODE_DATA_SIZE & 0xFF); 02644 02645 // 02646 // Disable block descriptors. 02647 // 02648 02649 cdb->MODE_SENSE10.Dbd = TRUE; 02650 02651 srb->CdbLength = 10; 02652 } 02653 02654 srb->TimeOutValue = deviceExtension->TimeOutValue; 02655 srb->DataTransferLength = MODE_DATA_SIZE; 02656 srb->SrbFlags = deviceExtension->SrbFlags; 02657 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN); 02658 02659 IoCallDriver(deviceExtension->PortDeviceObject, irp2); 02660 return; 02661 02662 } 02663 02664 case IOCTL_CDROM_GET_VOLUME: 02665 case IOCTL_CDROM_SET_VOLUME: { 02666 02667 dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned, 02668 MODE_DATA_SIZE); 02669 02670 if (!dataBuffer) { 02671 Irp->IoStatus.Information = 0; 02672 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 02673 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 02674 ExFreePool(senseBuffer); 02675 ExFreePool(srb); 02676 IoFreeIrp(irp2); 02677 IoStartNextPacket(DeviceObject, FALSE); 02678 return; 02679 } 02680 02681 irp2->MdlAddress = IoAllocateMdl(dataBuffer, 02682 MODE_DATA_SIZE, 02683 FALSE, 02684 FALSE, 02685 (PIRP) NULL); 02686 02687 if (!irp2->MdlAddress) { 02688 Irp->IoStatus.Information = 0; 02689 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 02690 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 02691 ExFreePool(senseBuffer); 02692 ExFreePool(srb); 02693 ExFreePool(dataBuffer); 02694 IoFreeIrp(irp2); 02695 IoStartNextPacket(DeviceObject, FALSE); 02696 return; 02697 } 02698 02699 // 02700 // Prepare the MDL 02701 // 02702 02703 MmBuildMdlForNonPagedPool(irp2->MdlAddress); 02704 srb->DataBuffer = dataBuffer; 02705 02706 RtlZeroMemory(dataBuffer, MODE_DATA_SIZE); 02707 02708 02709 if (use6Byte) { 02710 cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE; 02711 cdb->MODE_SENSE.PageCode = CDROM_AUDIO_CONTROL_PAGE; 02712 cdb->MODE_SENSE.AllocationLength = MODE_DATA_SIZE; 02713 02714 srb->CdbLength = 6; 02715 02716 } else { 02717 02718 cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10; 02719 cdb->MODE_SENSE10.PageCode = CDROM_AUDIO_CONTROL_PAGE; 02720 cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(MODE_DATA_SIZE >> 8); 02721 cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(MODE_DATA_SIZE & 0xFF); 02722 02723 srb->CdbLength = 10; 02724 } 02725 02726 srb->TimeOutValue = deviceExtension->TimeOutValue; 02727 srb->DataTransferLength = MODE_DATA_SIZE; 02728 srb->SrbFlags = deviceExtension->SrbFlags; 02729 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN); 02730 02731 if (currentIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_SET_VOLUME) { 02732 02733 // 02734 // Setup a different completion routine as the mode sense data is needed in order 02735 // to send the mode select. 02736 // 02737 02738 IoSetCompletionRoutine(irp2, 02739 CdRomSetVolumeIntermediateCompletion, 02740 srb, 02741 TRUE, 02742 TRUE, 02743 TRUE); 02744 02745 } 02746 02747 IoCallDriver(deviceExtension->PortDeviceObject, irp2); 02748 return; 02749 02750 } 02751 02752 default: 02753 02754 // 02755 // Just complete the request - CdRomClassIoctlCompletion will take 02756 // care of it for us 02757 // 02758 02759 IoCompleteRequest(Irp, IO_NO_INCREMENT); 02760 return; 02761 02762 } // end switch() 02763 } 02764 02765 // 02766 // If a read or an unhandled IRP_MJ_XX, end up here. The unhandled IRP_MJ's 02767 // are expected and composed of AutoRun Irps, at present. 02768 // 02769 02770 IoCallDriver(deviceExtension->PortDeviceObject, Irp); 02771 return; 02772 } 02773 02774 02775 NTSTATUS 02776 NTAPI 02777 ScsiCdRomReadVerification( 02778 IN PDEVICE_OBJECT DeviceObject, 02779 IN PIRP Irp 02780 ) 02781 02782 /*++ 02783 02784 Routine Description: 02785 02786 This is the entry called by the I/O system for read requests. 02787 It builds the SRB and sends it to the port driver. 02788 02789 Arguments: 02790 02791 DeviceObject - the system object for the device. 02792 Irp - IRP involved. 02793 02794 Return Value: 02795 02796 NT Status 02797 02798 --*/ 02799 02800 { 02801 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 02802 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp); 02803 ULONG transferByteCount = currentIrpStack->Parameters.Read.Length; 02804 LARGE_INTEGER startingOffset = currentIrpStack->Parameters.Read.ByteOffset; 02805 02806 // 02807 // If the cd is playing music then reject this request. 02808 // 02809 02810 if (PLAY_ACTIVE(deviceExtension)) { 02811 Irp->IoStatus.Status = STATUS_DEVICE_BUSY; 02812 return STATUS_DEVICE_BUSY; 02813 } 02814 02815 // 02816 // Verify parameters of this request. 02817 // Check that ending sector is on disc and 02818 // that number of bytes to transfer is a multiple of 02819 // the sector size. 02820 // 02821 02822 startingOffset.QuadPart = currentIrpStack->Parameters.Read.ByteOffset.QuadPart + 02823 transferByteCount; 02824 02825 if (!deviceExtension->DiskGeometry->Geometry.BytesPerSector) { 02826 deviceExtension->DiskGeometry->Geometry.BytesPerSector = 2048; 02827 } 02828 02829 if ((startingOffset.QuadPart > deviceExtension->PartitionLength.QuadPart) || 02830 (transferByteCount & (deviceExtension->DiskGeometry->Geometry.BytesPerSector - 1))) { 02831 02832 DebugPrint((1,"ScsiCdRomRead: Invalid I/O parameters\n")); 02833 DebugPrint((1, "\toffset %x:%x, Length %x:%x\n", 02834 startingOffset.u.HighPart, 02835 startingOffset.u.LowPart, 02836 deviceExtension->PartitionLength.u.HighPart, 02837 deviceExtension->PartitionLength.u.LowPart)); 02838 DebugPrint((1, "\tbps %x\n", deviceExtension->DiskGeometry->Geometry.BytesPerSector)); 02839 02840 // 02841 // Fail request with status of invalid parameters. 02842 // 02843 02844 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; 02845 02846 return STATUS_INVALID_PARAMETER; 02847 } 02848 02849 02850 return STATUS_SUCCESS; 02851 02852 } // end ScsiCdRomReadVerification() 02853 02854 02855 NTSTATUS 02856 NTAPI 02857 CdRomDeviceControlCompletion( 02858 IN PDEVICE_OBJECT DeviceObject, 02859 IN PIRP Irp, 02860 IN PVOID Context 02861 ) 02862 { 02863 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 02864 PDEVICE_EXTENSION physicalExtension = deviceExtension->PhysicalDevice->DeviceExtension; 02865 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); 02866 PCDROM_DATA cdData = (PCDROM_DATA)(deviceExtension + 1); 02867 BOOLEAN use6Byte = cdData->XAFlags & XA_USE_6_BYTE; 02868 PIO_STACK_LOCATION realIrpStack; 02869 PIO_STACK_LOCATION realIrpNextStack; 02870 PSCSI_REQUEST_BLOCK srb = Context; 02871 PIRP realIrp = NULL; 02872 NTSTATUS status; 02873 BOOLEAN retry; 02874 02875 // 02876 // Extract the 'real' irp from the irpstack. 02877 // 02878 02879 realIrp = (PIRP) irpStack->Parameters.Others.Argument2; 02880 realIrpStack = IoGetCurrentIrpStackLocation(realIrp); 02881 realIrpNextStack = IoGetNextIrpStackLocation(realIrp); 02882 02883 // 02884 // Check SRB status for success of completing request. 02885 // 02886 02887 if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) { 02888 02889 DebugPrint((2, 02890 "CdRomDeviceControlCompletion: Irp %lx, Srb %lx Real Irp %lx Status %lx\n", 02891 Irp, 02892 srb, 02893 realIrp, 02894 srb->SrbStatus)); 02895 02896 // 02897 // Release the queue if it is frozen. 02898 // 02899 02900 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) { 02901 DebugPrint((2, "CdRomDeviceControlCompletion: Releasing Queue\n")); 02902 ScsiClassReleaseQueue(DeviceObject); 02903 } 02904 02905 02906 retry = ScsiClassInterpretSenseInfo(DeviceObject, 02907 srb, 02908 irpStack->MajorFunction, 02909 irpStack->Parameters.DeviceIoControl.IoControlCode, 02910 MAXIMUM_RETRIES - ((ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1), 02911 &status); 02912 02913 DebugPrint((2, "CdRomDeviceControlCompletion: IRP will %sbe retried\n", 02914 (retry ? "" : "not "))); 02915 02916 // 02917 // Some of the Device Controls need special cases on non-Success status's. 02918 // 02919 02920 if (realIrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) { 02921 if ((realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_GET_LAST_SESSION) || 02922 (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_READ_TOC) || 02923 (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_GET_CONTROL) || 02924 (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_GET_VOLUME)) { 02925 02926 if (status == STATUS_DATA_OVERRUN) { 02927 status = STATUS_SUCCESS; 02928 retry = FALSE; 02929 } 02930 } 02931 02932 if (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_READ_Q_CHANNEL) { 02933 PLAY_ACTIVE(deviceExtension) = FALSE; 02934 } 02935 } 02936 02937 // 02938 // If the status is verified required and the this request 02939 // should bypass verify required then retry the request. 02940 // 02941 02942 if (realIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME && 02943 status == STATUS_VERIFY_REQUIRED) { 02944 02945 if (((realIrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) || 02946 (realIrpStack->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL)) && 02947 (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_CHECK_VERIFY)) { 02948 02949 // 02950 // Update the geometry information, as the media could have changed. 02951 // The completion routine for this will complete the real irp and start 02952 // the next packet. 02953 // 02954 02955 status = CdRomUpdateCapacity(deviceExtension,realIrp, NULL); 02956 DebugPrint((2, "CdRomDeviceControlCompletion: [%lx] CdRomUpdateCapacity completed with status %lx\n", realIrp, status)); 02957 ASSERT(status == STATUS_PENDING); 02958 02959 return STATUS_MORE_PROCESSING_REQUIRED; 02960 02961 } else { 02962 02963 status = STATUS_IO_DEVICE_ERROR; 02964 retry = TRUE; 02965 } 02966 02967 } 02968 02969 if (retry && (realIrpNextStack->Parameters.Others.Argument1 = (PVOID)((ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1-1))) { 02970 02971 02972 if (((ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1)) { 02973 02974 // 02975 // Retry request. 02976 // 02977 02978 DebugPrint((1, "Retry request %lx - Calling StartIo\n", Irp)); 02979 02980 02981 ExFreePool(srb->SenseInfoBuffer); 02982 if (srb->DataBuffer) { 02983 ExFreePool(srb->DataBuffer); 02984 } 02985 ExFreePool(srb); 02986 if (Irp->MdlAddress) { 02987 IoFreeMdl(Irp->MdlAddress); 02988 } 02989 02990 IoFreeIrp(Irp); 02991 02992 // 02993 // Call StartIo directly since IoStartNextPacket hasn't been called, 02994 // the serialisation is still intact. 02995 // 02996 02997 ScsiCdRomStartIo(DeviceObject, realIrp); 02998 return STATUS_MORE_PROCESSING_REQUIRED; 02999 03000 } 03001 03002 // 03003 // Exhausted retries. Fall through and complete the request with the appropriate status. 03004 // 03005 03006 } 03007 } else { 03008 03009 // 03010 // Set status for successful request. 03011 // 03012 03013 status = STATUS_SUCCESS; 03014 } 03015 03016 if (NT_SUCCESS(status)) { 03017 03018 switch (realIrpStack->Parameters.DeviceIoControl.IoControlCode) { 03019 03020 case IOCTL_CDROM_GET_DRIVE_GEOMETRY: { 03021 03022 PREAD_CAPACITY_DATA readCapacityBuffer = srb->DataBuffer; 03023 ULONG lastSector; 03024 ULONG bps; 03025 ULONG lastBit; 03026 ULONG tmp; 03027 03028 // 03029 // Swizzle bytes from Read Capacity and translate into 03030 // the necessary geometry information in the device extension. 03031 // 03032 03033 tmp = readCapacityBuffer->BytesPerBlock; 03034 ((PFOUR_BYTE)&bps)->Byte0 = ((PFOUR_BYTE)&tmp)->Byte3; 03035 ((PFOUR_BYTE)&bps)->Byte1 = ((PFOUR_BYTE)&tmp)->Byte2; 03036 ((PFOUR_BYTE)&bps)->Byte2 = ((PFOUR_BYTE)&tmp)->Byte1; 03037 ((PFOUR_BYTE)&bps)->Byte3 = ((PFOUR_BYTE)&tmp)->Byte0; 03038 03039 // 03040 // Insure that bps is a power of 2. 03041 // This corrects a problem with the HP 4020i CDR where it 03042 // returns an incorrect number for bytes per sector. 03043 // 03044 03045 if (!bps) { 03046 bps = 2048; 03047 } else { 03048 lastBit = (ULONG) -1; 03049 while (bps) { 03050 lastBit++; 03051 bps = bps >> 1; 03052 } 03053 03054 bps = 1 << lastBit; 03055 } 03056 deviceExtension->DiskGeometry->Geometry.BytesPerSector = bps; 03057 03058 DebugPrint((2, 03059 "CdRomDeviceControlCompletion: Calculated bps %#x\n", 03060 deviceExtension->DiskGeometry->Geometry.BytesPerSector)); 03061 03062 // 03063 // Copy last sector in reverse byte order. 03064 // 03065 03066 tmp = readCapacityBuffer->LogicalBlockAddress; 03067 ((PFOUR_BYTE)&lastSector)->Byte0 = ((PFOUR_BYTE)&tmp)->Byte3; 03068 ((PFOUR_BYTE)&lastSector)->Byte1 = ((PFOUR_BYTE)&tmp)->Byte2; 03069 ((PFOUR_BYTE)&lastSector)->Byte2 = ((PFOUR_BYTE)&tmp)->Byte1; 03070 ((PFOUR_BYTE)&lastSector)->Byte3 = ((PFOUR_BYTE)&tmp)->Byte0; 03071 03072 // 03073 // Calculate sector to byte shift. 03074 // 03075 03076 WHICH_BIT(bps, deviceExtension->SectorShift); 03077 03078 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Sector size is %d\n", 03079 deviceExtension->DiskGeometry->Geometry.BytesPerSector)); 03080 03081 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Number of Sectors is %d\n", 03082 lastSector + 1)); 03083 03084 // 03085 // Calculate media capacity in bytes. 03086 // 03087 03088 deviceExtension->PartitionLength.QuadPart = (LONGLONG)(lastSector + 1); 03089 03090 // 03091 // Calculate number of cylinders. 03092 // 03093 03094 deviceExtension->DiskGeometry->Geometry.Cylinders.QuadPart = (LONGLONG)((lastSector + 1)/(32 * 64)); 03095 03096 deviceExtension->PartitionLength.QuadPart = 03097 (deviceExtension->PartitionLength.QuadPart << deviceExtension->SectorShift); 03098 03099 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) { 03100 03101 // 03102 // This device supports removable media. 03103 // 03104 03105 deviceExtension->DiskGeometry->Geometry.MediaType = RemovableMedia; 03106 03107 } else { 03108 03109 // 03110 // Assume media type is fixed disk. 03111 // 03112 03113 deviceExtension->DiskGeometry->Geometry.MediaType = FixedMedia; 03114 } 03115 03116 // 03117 // Assume sectors per track are 32; 03118 // 03119 03120 deviceExtension->DiskGeometry->Geometry.SectorsPerTrack = 32; 03121 03122 // 03123 // Assume tracks per cylinder (number of heads) is 64. 03124 // 03125 03126 deviceExtension->DiskGeometry->Geometry.TracksPerCylinder = 64; 03127 03128 // 03129 // Copy the device extension's geometry info into the user buffer. 03130 // 03131 03132 RtlMoveMemory(realIrp->AssociatedIrp.SystemBuffer, 03133 deviceExtension->DiskGeometry, 03134 sizeof(DISK_GEOMETRY)); 03135 03136 // 03137 // update information field. 03138 // 03139 03140 realIrp->IoStatus.Information = sizeof(DISK_GEOMETRY); 03141 break; 03142 } 03143 03144 case IOCTL_CDROM_CHECK_VERIFY: 03145 03146 if((realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_CHECK_VERIFY) && 03147 (realIrpStack->Parameters.DeviceIoControl.OutputBufferLength)) { 03148 03149 *((PULONG)realIrp->AssociatedIrp.SystemBuffer) = 03150 physicalExtension->MediaChangeCount; 03151 realIrp->IoStatus.Information = sizeof(ULONG); 03152 } else { 03153 realIrp->IoStatus.Information = 0; 03154 } 03155 03156 DebugPrint((2, "CdRomDeviceControlCompletion: [%lx] completing CHECK_VERIFY buddy irp %lx\n", realIrp, Irp)); 03157 break; 03158 03159 case IOCTL_CDROM_GET_LAST_SESSION: 03160 case IOCTL_CDROM_READ_TOC: { 03161 03162 PCDROM_TOC toc = srb->DataBuffer; 03163 03164 // 03165 // Copy the device extension's geometry info into the user buffer. 03166 // 03167 03168 RtlMoveMemory(realIrp->AssociatedIrp.SystemBuffer, 03169 toc, 03170 srb->DataTransferLength); 03171 03172 // 03173 // update information field. 03174 // 03175 03176 realIrp->IoStatus.Information = srb->DataTransferLength; 03177 break; 03178 } 03179 03180 case IOCTL_CDROM_PLAY_AUDIO_MSF: 03181 03182 PLAY_ACTIVE(deviceExtension) = TRUE; 03183 03184 break; 03185 03186 case IOCTL_CDROM_READ_Q_CHANNEL: { 03187 03188 PSUB_Q_CHANNEL_DATA userChannelData = realIrp->AssociatedIrp.SystemBuffer; 03189 #if DBG 03190 PCDROM_SUB_Q_DATA_FORMAT inputBuffer = realIrp->AssociatedIrp.SystemBuffer; 03191 #endif 03192 PSUB_Q_CHANNEL_DATA subQPtr = srb->DataBuffer; 03193 03194 #if DBG 03195 switch( inputBuffer->Format ) { 03196 03197 case IOCTL_CDROM_CURRENT_POSITION: 03198 DebugPrint((2,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr->CurrentPosition.Header.AudioStatus )); 03199 DebugPrint((2,"CdRomDeviceControlCompletion: ADR = 0x%x\n", subQPtr->CurrentPosition.ADR )); 03200 DebugPrint((2,"CdRomDeviceControlCompletion: Control = 0x%x\n", subQPtr->CurrentPosition.Control )); 03201 DebugPrint((2,"CdRomDeviceControlCompletion: Track = %u\n", subQPtr->CurrentPosition.TrackNumber )); 03202 DebugPrint((2,"CdRomDeviceControlCompletion: Index = %u\n", subQPtr->CurrentPosition.IndexNumber )); 03203 DebugPrint((2,"CdRomDeviceControlCompletion: Absolute Address = %x\n", *((PULONG)subQPtr->CurrentPosition.AbsoluteAddress) )); 03204 DebugPrint((2,"CdRomDeviceControlCompletion: Relative Address = %x\n", *((PULONG)subQPtr->CurrentPosition.TrackRelativeAddress) )); 03205 break; 03206 03207 case IOCTL_CDROM_MEDIA_CATALOG: 03208 DebugPrint((2,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr->MediaCatalog.Header.AudioStatus )); 03209 DebugPrint((2,"CdRomDeviceControlCompletion: Mcval is %u\n", subQPtr->MediaCatalog.Mcval )); 03210 break; 03211 03212 case IOCTL_CDROM_TRACK_ISRC: 03213 DebugPrint((2,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr->TrackIsrc.Header.AudioStatus )); 03214 DebugPrint((2,"CdRomDeviceControlCompletion: Tcval is %u\n", subQPtr->TrackIsrc.Tcval )); 03215 break; 03216 03217 } 03218 #endif 03219 03220 // 03221 // Update the play active status. 03222 // 03223 03224 if (subQPtr->CurrentPosition.Header.AudioStatus == AUDIO_STATUS_IN_PROGRESS) { 03225 03226 PLAY_ACTIVE(deviceExtension) = TRUE; 03227 03228 } else { 03229 03230 PLAY_ACTIVE(deviceExtension) = FALSE; 03231 03232 } 03233 03234 // 03235 // Check if output buffer is large enough to contain 03236 // the data. 03237 // 03238 03239 if (realIrpStack->Parameters.DeviceIoControl.OutputBufferLength < 03240 srb->DataTransferLength) { 03241 03242 srb->DataTransferLength = 03243 realIrpStack->Parameters.DeviceIoControl.OutputBufferLength; 03244 } 03245 03246 // 03247 // Copy our buffer into users. 03248 // 03249 03250 RtlMoveMemory(userChannelData, 03251 subQPtr, 03252 srb->DataTransferLength); 03253 03254 realIrp->IoStatus.Information = srb->DataTransferLength; 03255 break; 03256 } 03257 03258 case IOCTL_CDROM_PAUSE_AUDIO: 03259 03260 PLAY_ACTIVE(deviceExtension) = FALSE; 03261 realIrp->IoStatus.Information = 0; 03262 break; 03263 03264 case IOCTL_CDROM_RESUME_AUDIO: 03265 03266 realIrp->IoStatus.Information = 0; 03267 break; 03268 03269 case IOCTL_CDROM_SEEK_AUDIO_MSF: 03270 03271 realIrp->IoStatus.Information = 0; 03272 break; 03273 03274 case IOCTL_CDROM_STOP_AUDIO: 03275 03276 PLAY_ACTIVE(deviceExtension) = FALSE; 03277 03278 realIrp->IoStatus.Information = 0; 03279 break; 03280 03281 case IOCTL_CDROM_GET_CONTROL: { 03282 03283 PCDROM_AUDIO_CONTROL audioControl = srb->DataBuffer; 03284 PAUDIO_OUTPUT audioOutput; 03285 ULONG bytesTransferred; 03286 03287 audioOutput = ScsiClassFindModePage((PCHAR)audioControl, 03288 srb->DataTransferLength, 03289 CDROM_AUDIO_CONTROL_PAGE, 03290 use6Byte); 03291 // 03292 // Verify the page is as big as expected. 03293 // 03294 03295 bytesTransferred = (PCHAR) audioOutput - (PCHAR) audioControl + 03296 sizeof(AUDIO_OUTPUT); 03297 03298 if (audioOutput != NULL && 03299 srb->DataTransferLength >= bytesTransferred) { 03300 03301 audioControl->LbaFormat = audioOutput->LbaFormat; 03302 03303 audioControl->LogicalBlocksPerSecond = 03304 (audioOutput->LogicalBlocksPerSecond[0] << (UCHAR)8) | 03305 audioOutput->LogicalBlocksPerSecond[1]; 03306 03307 realIrp->IoStatus.Information = sizeof(CDROM_AUDIO_CONTROL); 03308 03309 } else { 03310 realIrp->IoStatus.Information = 0; 03311 status = STATUS_INVALID_DEVICE_REQUEST; 03312 } 03313 break; 03314 } 03315 03316 case IOCTL_CDROM_GET_VOLUME: { 03317 03318 PAUDIO_OUTPUT audioOutput; 03319 PVOLUME_CONTROL volumeControl = srb->DataBuffer; 03320 ULONG i,bytesTransferred; 03321 03322 audioOutput = ScsiClassFindModePage((PCHAR)volumeControl, 03323 srb->DataTransferLength, 03324 CDROM_AUDIO_CONTROL_PAGE, 03325 use6Byte); 03326 03327 // 03328 // Verify the page is as big as expected. 03329 // 03330 03331 bytesTransferred = (PCHAR) audioOutput - (PCHAR) volumeControl + 03332 sizeof(AUDIO_OUTPUT); 03333 03334 if (audioOutput != NULL && 03335 srb->DataTransferLength >= bytesTransferred) { 03336 03337 for (i=0; i<4; i++) { 03338 volumeControl->PortVolume[i] = 03339 audioOutput->PortOutput[i].Volume; 03340 } 03341 03342 // 03343 // Set bytes transferred in IRP. 03344 // 03345 03346 realIrp->IoStatus.Information = sizeof(VOLUME_CONTROL); 03347 03348 } else { 03349 realIrp->IoStatus.Information = 0; 03350 status = STATUS_INVALID_DEVICE_REQUEST; 03351 } 03352 03353 break; 03354 } 03355 03356 case IOCTL_CDROM_SET_VOLUME: 03357 03358 realIrp->IoStatus.Information = sizeof(VOLUME_CONTROL); 03359 break; 03360 03361 default: 03362 03363 ASSERT(FALSE); 03364 realIrp->IoStatus.Information = 0; 03365 status = STATUS_INVALID_DEVICE_REQUEST; 03366 03367 } // end switch() 03368 } 03369 03370 // 03371 // Deallocate srb and sense buffer. 03372 // 03373 03374 if (srb) { 03375 if (srb->DataBuffer) { 03376 ExFreePool(srb->DataBuffer); 03377 } 03378 if (srb->SenseInfoBuffer) { 03379 ExFreePool(srb->SenseInfoBuffer); 03380 } 03381 ExFreePool(srb); 03382 } 03383 03384 if (realIrp->PendingReturned) { 03385 IoMarkIrpPending(realIrp); 03386 } 03387 03388 if (Irp->MdlAddress) { 03389 IoFreeMdl(Irp->MdlAddress); 03390 } 03391 03392 IoFreeIrp(Irp); 03393 03394 // 03395 // Set status in completing IRP. 03396 // 03397 03398 realIrp->IoStatus.Status = status; 03399 03400 // 03401 // Set the hard error if necessary. 03402 // 03403 03404 if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) { 03405 03406 // 03407 // Store DeviceObject for filesystem, and clear 03408 // in IoStatus.Information field. 03409 // 03410 03411 DebugPrint((1, "CdRomDeviceCompletion - Setting Hard Error on realIrp %lx\n", 03412 realIrp)); 03413 IoSetHardErrorOrVerifyDevice(realIrp, DeviceObject); 03414 realIrp->IoStatus.Information = 0; 03415 } 03416 03417 IoCompleteRequest(realIrp, IO_DISK_INCREMENT); 03418 03419 IoStartNextPacket(DeviceObject, FALSE); 03420 03421 return STATUS_MORE_PROCESSING_REQUIRED; 03422 } 03423 03424 NTSTATUS 03425 NTAPI 03426 CdRomSetVolumeIntermediateCompletion( 03427 IN PDEVICE_OBJECT DeviceObject, 03428 IN PIRP Irp, 03429 IN PVOID Context 03430 ) 03431 { 03432 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 03433 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); 03434 PCDROM_DATA cdData = (PCDROM_DATA)(deviceExtension + 1); 03435 BOOLEAN use6Byte = cdData->XAFlags & XA_USE_6_BYTE; 03436 PIO_STACK_LOCATION realIrpStack; 03437 PIO_STACK_LOCATION realIrpNextStack; 03438 PSCSI_REQUEST_BLOCK srb = Context; 03439 PIRP realIrp = NULL; 03440 NTSTATUS status; 03441 BOOLEAN retry; 03442 03443 // 03444 // Extract the 'real' irp from the irpstack. 03445 // 03446 03447 realIrp = (PIRP) irpStack->Parameters.Others.Argument2; 03448 realIrpStack = IoGetCurrentIrpStackLocation(realIrp); 03449 realIrpNextStack = IoGetNextIrpStackLocation(realIrp); 03450 03451 // 03452 // Check SRB status for success of completing request. 03453 // 03454 03455 if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) { 03456 03457 DebugPrint((2, 03458 "CdRomSetVolumeIntermediateCompletion: Irp %lx, Srb %lx Real Irp\n", 03459 Irp, 03460 srb, 03461 realIrp)); 03462 03463 // 03464 // Release the queue if it is frozen. 03465 // 03466 03467 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) { 03468 ScsiClassReleaseQueue(DeviceObject); 03469 } 03470 03471 03472 retry = ScsiClassInterpretSenseInfo(DeviceObject, 03473 srb, 03474 irpStack->MajorFunction, 03475 irpStack->Parameters.DeviceIoControl.IoControlCode, 03476 MAXIMUM_RETRIES - ((ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1), 03477 &status); 03478 03479 if (status == STATUS_DATA_OVERRUN) { 03480 status = STATUS_SUCCESS; 03481 retry = FALSE; 03482 } 03483 03484 // 03485 // If the status is verified required and the this request 03486 // should bypass verify required then retry the request. 03487 // 03488 03489 if (realIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME && 03490 status == STATUS_VERIFY_REQUIRED) { 03491 03492 status = STATUS_IO_DEVICE_ERROR; 03493 retry = TRUE; 03494 } 03495 03496 if (retry && (realIrpNextStack->Parameters.Others.Argument1 = (PVOID)((ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1-1))) { 03497 03498 if (((ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1)) { 03499 03500 // 03501 // Retry request. 03502 // 03503 03504 DebugPrint((1, "Retry request %lx - Calling StartIo\n", Irp)); 03505 03506 03507 ExFreePool(srb->SenseInfoBuffer); 03508 ExFreePool(srb->DataBuffer); 03509 ExFreePool(srb); 03510 if (Irp->MdlAddress) { 03511 IoFreeMdl(Irp->MdlAddress); 03512 } 03513 03514 IoFreeIrp(Irp); 03515 03516 // 03517 // Call StartIo directly since IoStartNextPacket hasn't been called, 03518 // the serialisation is still intact. 03519 // 03520 ScsiCdRomStartIo(DeviceObject, realIrp); 03521 return STATUS_MORE_PROCESSING_REQUIRED; 03522 03523 } 03524 03525 // 03526 // Exhausted retries. Fall through and complete the request with the appropriate status. 03527 // 03528 03529 } 03530 } else { 03531 03532 // 03533 // Set status for successful request. 03534 // 03535 03536 status = STATUS_SUCCESS; 03537 } 03538 03539 if (NT_SUCCESS(status)) { 03540 03541 PAUDIO_OUTPUT audioInput = NULL; 03542 PAUDIO_OUTPUT audioOutput; 03543 PVOLUME_CONTROL volumeControl = realIrp->AssociatedIrp.SystemBuffer; 03544 ULONG i,bytesTransferred,headerLength; 03545 PVOID dataBuffer; 03546 PCDB cdb; 03547 03548 audioInput = ScsiClassFindModePage((PCHAR)srb->DataBuffer, 03549 srb->DataTransferLength, 03550 CDROM_AUDIO_CONTROL_PAGE, 03551 use6Byte); 03552 03553 // 03554 // Check to make sure the mode sense data is valid before we go on 03555 // 03556 03557 if(audioInput == NULL) { 03558 03559 DebugPrint((1, "Mode Sense Page %d not found\n", 03560 CDROM_AUDIO_CONTROL_PAGE)); 03561 03562 realIrp->IoStatus.Information = 0; 03563 realIrp->IoStatus.Status = STATUS_IO_DEVICE_ERROR; 03564 IoCompleteRequest(realIrp, IO_DISK_INCREMENT); 03565 ExFreePool(srb->SenseInfoBuffer); 03566 ExFreePool(srb); 03567 IoFreeMdl(Irp->MdlAddress); 03568 IoFreeIrp(Irp); 03569 return STATUS_MORE_PROCESSING_REQUIRED; 03570 } 03571 03572 if (use6Byte) { 03573 headerLength = sizeof(MODE_PARAMETER_HEADER); 03574 } else { 03575 headerLength = sizeof(MODE_PARAMETER_HEADER10); 03576 } 03577 03578 bytesTransferred = sizeof(AUDIO_OUTPUT) + headerLength; 03579 03580 // 03581 // Allocate a new buffer for the mode select. 03582 // 03583 03584 dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned, bytesTransferred); 03585 03586 if (!dataBuffer) { 03587 realIrp->IoStatus.Information = 0; 03588 realIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 03589 IoCompleteRequest(realIrp, IO_DISK_INCREMENT); 03590 ExFreePool(srb->SenseInfoBuffer); 03591 ExFreePool(srb); 03592 IoFreeMdl(Irp->MdlAddress); 03593 IoFreeIrp(Irp); 03594 return STATUS_MORE_PROCESSING_REQUIRED; 03595 } 03596 03597 RtlZeroMemory(dataBuffer, bytesTransferred); 03598 03599 // 03600 // Rebuild the data buffer to include the user requested values. 03601 // 03602 03603 audioOutput = (PAUDIO_OUTPUT) ((PCHAR) dataBuffer + headerLength); 03604 03605 for (i=0; i<4; i++) { 03606 audioOutput->PortOutput[i].Volume = 03607 volumeControl->PortVolume[i]; 03608 audioOutput->PortOutput[i].ChannelSelection = 03609 audioInput->PortOutput[i].ChannelSelection; 03610 } 03611 03612 audioOutput->CodePage = CDROM_AUDIO_CONTROL_PAGE; 03613 audioOutput->ParameterLength = sizeof(AUDIO_OUTPUT) - 2; 03614 audioOutput->Immediate = MODE_SELECT_IMMEDIATE; 03615 03616 // 03617 // Free the old data buffer, mdl. 03618 // 03619 03620 ExFreePool(srb->DataBuffer); 03621 IoFreeMdl(Irp->MdlAddress); 03622 03623 // 03624 // rebuild the srb. 03625 // 03626 03627 cdb = (PCDB)srb->Cdb; 03628 RtlZeroMemory(cdb, CDB12GENERIC_LENGTH); 03629 03630 srb->SrbStatus = srb->ScsiStatus = 0; 03631 srb->SrbFlags = deviceExtension->SrbFlags; 03632 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_OUT); 03633 srb->DataTransferLength = bytesTransferred; 03634 03635 if (use6Byte) { 03636 03637 cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT; 03638 cdb->MODE_SELECT.ParameterListLength = (UCHAR) bytesTransferred; 03639 cdb->MODE_SELECT.PFBit = 1; 03640 srb->CdbLength = 6; 03641 } else { 03642 03643 cdb->MODE_SELECT10.OperationCode = SCSIOP_MODE_SELECT10; 03644 cdb->MODE_SELECT10.ParameterListLength[0] = (UCHAR) (bytesTransferred >> 8); 03645 cdb->MODE_SELECT10.ParameterListLength[1] = (UCHAR) (bytesTransferred & 0xFF); 03646 cdb->MODE_SELECT10.PFBit = 1; 03647 srb->CdbLength = 10; 03648 } 03649 03650 // 03651 // Prepare the MDL 03652 // 03653 03654 Irp->MdlAddress = IoAllocateMdl(dataBuffer, 03655 bytesTransferred, 03656 FALSE, 03657 FALSE, 03658 (PIRP) NULL); 03659 03660 if (!Irp->MdlAddress) { 03661 realIrp->IoStatus.Information = 0; 03662 realIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 03663 IoCompleteRequest(realIrp, IO_DISK_INCREMENT); 03664 ExFreePool(srb->SenseInfoBuffer); 03665 ExFreePool(srb); 03666 ExFreePool(dataBuffer); 03667 IoFreeIrp(Irp); 03668 return STATUS_MORE_PROCESSING_REQUIRED; 03669 03670 } 03671 03672 MmBuildMdlForNonPagedPool(Irp->MdlAddress); 03673 srb->DataBuffer = dataBuffer; 03674 03675 irpStack = IoGetNextIrpStackLocation(Irp); 03676 irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; 03677 irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN; 03678 irpStack->Parameters.Scsi.Srb = srb; 03679 03680 // 03681 // reset the irp completion. 03682 // 03683 03684 IoSetCompletionRoutine(Irp, 03685 CdRomDeviceControlCompletion, 03686 srb, 03687 TRUE, 03688 TRUE, 03689 TRUE); 03690 // 03691 // Call the port driver. 03692 // 03693 03694 IoCallDriver(deviceExtension->PortDeviceObject, Irp); 03695 03696 return STATUS_MORE_PROCESSING_REQUIRED; 03697 } 03698 03699 // 03700 // Deallocate srb and sense buffer. 03701 // 03702 03703 if (srb) { 03704 if (srb->DataBuffer) { 03705 ExFreePool(srb->DataBuffer); 03706 } 03707 if (srb->SenseInfoBuffer) { 03708 ExFreePool(srb->SenseInfoBuffer); 03709 } 03710 ExFreePool(srb); 03711 } 03712 03713 if (Irp->PendingReturned) { 03714 IoMarkIrpPending(Irp); 03715 } 03716 03717 if (realIrp->PendingReturned) { 03718 IoMarkIrpPending(realIrp); 03719 } 03720 03721 if (Irp->MdlAddress) { 03722 IoFreeMdl(Irp->MdlAddress); 03723 } 03724 03725 IoFreeIrp(Irp); 03726 03727 // 03728 // Set status in completing IRP. 03729 // 03730 03731 realIrp->IoStatus.Status = status; 03732 03733 // 03734 // Set the hard error if necessary. 03735 // 03736 03737 if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) { 03738 03739 // 03740 // Store DeviceObject for filesystem, and clear 03741 // in IoStatus.Information field. 03742 // 03743 03744 IoSetHardErrorOrVerifyDevice(realIrp, DeviceObject); 03745 realIrp->IoStatus.Information = 0; 03746 } 03747 03748 IoCompleteRequest(realIrp, IO_DISK_INCREMENT); 03749 03750 IoStartNextPacket(DeviceObject, FALSE); 03751 03752 return STATUS_MORE_PROCESSING_REQUIRED; 03753 } 03754 03755 03756 NTSTATUS 03757 NTAPI 03758 CdRomSwitchModeCompletion( 03759 IN PDEVICE_OBJECT DeviceObject, 03760 IN PIRP Irp, 03761 IN PVOID Context 03762 ) 03763 { 03764 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 03765 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); 03766 PCDROM_DATA cdData = (PCDROM_DATA)(deviceExtension + 1); 03767 PIO_STACK_LOCATION realIrpStack; 03768 PIO_STACK_LOCATION realIrpNextStack; 03769 PSCSI_REQUEST_BLOCK srb = Context; 03770 PIRP realIrp = NULL; 03771 NTSTATUS status; 03772 BOOLEAN retry; 03773 03774 // 03775 // Extract the 'real' irp from the irpstack. 03776 // 03777 03778 realIrp = (PIRP) irpStack->Parameters.Others.Argument2; 03779 realIrpStack = IoGetCurrentIrpStackLocation(realIrp); 03780 realIrpNextStack = IoGetNextIrpStackLocation(realIrp); 03781 03782 // 03783 // Check SRB status for success of completing request. 03784 // 03785 03786 if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) { 03787 03788 DebugPrint((2, 03789 "CdRomSetVolumeIntermediateCompletion: Irp %lx, Srb %lx Real Irp\n", 03790 Irp, 03791 srb, 03792 realIrp)); 03793 03794 // 03795 // Release the queue if it is frozen. 03796 // 03797 03798 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) { 03799 ScsiClassReleaseQueue(DeviceObject); 03800 } 03801 03802 03803 retry = ScsiClassInterpretSenseInfo(DeviceObject, 03804 srb, 03805 irpStack->MajorFunction, 03806 irpStack->Parameters.DeviceIoControl.IoControlCode, 03807 MAXIMUM_RETRIES - ((ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1), 03808 &status); 03809 03810 // 03811 // If the status is verified required and the this request 03812 // should bypass verify required then retry the request. 03813 // 03814 03815 if (realIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME && 03816 status == STATUS_VERIFY_REQUIRED) { 03817 03818 status = STATUS_IO_DEVICE_ERROR; 03819 retry = TRUE; 03820 } 03821 03822 if (retry && (realIrpNextStack->Parameters.Others.Argument1 = (PVOID)((ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1-1))) { 03823 03824 if (((ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1)) { 03825 03826 // 03827 // Retry request. 03828 // 03829 03830 DebugPrint((1, "Retry request %lx - Calling StartIo\n", Irp)); 03831 03832 03833 ExFreePool(srb->SenseInfoBuffer); 03834 ExFreePool(srb->DataBuffer); 03835 ExFreePool(srb); 03836 if (Irp->MdlAddress) { 03837 IoFreeMdl(Irp->MdlAddress); 03838 } 03839 03840 IoFreeIrp(Irp); 03841 03842 // 03843 // Call StartIo directly since IoStartNextPacket hasn't been called, 03844 // the serialisation is still intact. 03845 // 03846 03847 ScsiCdRomStartIo(DeviceObject, realIrp); 03848 return STATUS_MORE_PROCESSING_REQUIRED; 03849 03850 } 03851 03852 // 03853 // Exhausted retries. Fall through and complete the request with the appropriate status. 03854 // 03855 } 03856 } else { 03857 03858 // 03859 // Set status for successful request. 03860 // 03861 03862 status = STATUS_SUCCESS; 03863 } 03864 03865 if (NT_SUCCESS(status)) { 03866 03867 ULONG sectorSize, startingSector, transferByteCount; 03868 PCDB cdb; 03869 03870 // 03871 // Update device ext. to show which mode we are currently using. 03872 // 03873 03874 sectorSize = cdData->u1.BlockDescriptor.BlockLength[0] << 16; 03875 sectorSize |= (cdData->u1.BlockDescriptor.BlockLength[1] << 8); 03876 sectorSize |= (cdData->u1.BlockDescriptor.BlockLength[2]); 03877 03878 cdData->RawAccess = (sectorSize == RAW_SECTOR_SIZE) ? TRUE : FALSE; 03879 03880 // 03881 // Free the old data buffer, mdl. 03882 // 03883 03884 ExFreePool(srb->DataBuffer); 03885 IoFreeMdl(Irp->MdlAddress); 03886 IoFreeIrp(Irp); 03887 03888 // 03889 // rebuild the srb. 03890 // 03891 03892 cdb = (PCDB)srb->Cdb; 03893 RtlZeroMemory(cdb, CDB12GENERIC_LENGTH); 03894 03895 03896 if (cdData->RawAccess) { 03897 03898 PRAW_READ_INFO rawReadInfo = 03899 (PRAW_READ_INFO)realIrpStack->Parameters.DeviceIoControl.Type3InputBuffer; 03900 03901 ULONG maximumTransferLength; 03902 ULONG transferPages; 03903 03904 // 03905 // Calculate starting offset. 03906 // 03907 03908 startingSector = (ULONG)(rawReadInfo->DiskOffset.QuadPart >> deviceExtension->SectorShift); 03909 transferByteCount = rawReadInfo->SectorCount * RAW_SECTOR_SIZE; 03910 maximumTransferLength = deviceExtension->PortCapabilities->MaximumTransferLength; 03911 transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(realIrp->MdlAddress), 03912 transferByteCount); 03913 03914 // 03915 // Determine if request is within limits imposed by miniport. 03916 // If the request is larger than the miniport's capabilities, split it. 03917 // 03918 03919 if (transferByteCount > maximumTransferLength || 03920 transferPages > deviceExtension->PortCapabilities->MaximumPhysicalPages) { 03921 03922 realIrp->IoStatus.Information = 0; 03923 realIrp->IoStatus.Status = STATUS_INVALID_PARAMETER; 03924 IoCompleteRequest(realIrp, IO_DISK_INCREMENT); 03925 03926 ExFreePool(srb->SenseInfoBuffer); 03927 ExFreePool(srb->DataBuffer); 03928 ExFreePool(srb); 03929 IoFreeMdl(Irp->MdlAddress); 03930 IoFreeIrp(Irp); 03931 03932 IoStartNextPacket(DeviceObject, FALSE); 03933 03934 return STATUS_MORE_PROCESSING_REQUIRED; 03935 } 03936 03937 srb->OriginalRequest = realIrp; 03938 srb->SrbFlags = deviceExtension->SrbFlags; 03939 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN); 03940 srb->DataTransferLength = transferByteCount; 03941 srb->TimeOutValue = deviceExtension->TimeOutValue; 03942 srb->CdbLength = 10; 03943 srb->DataBuffer = MmGetMdlVirtualAddress(realIrp->MdlAddress); 03944 03945 if (rawReadInfo->TrackMode == CDDA) { 03946 if (cdData->XAFlags & PLEXTOR_CDDA) { 03947 03948 srb->CdbLength = 12; 03949 03950 cdb->PLXTR_READ_CDDA.LogicalUnitNumber = deviceExtension->Lun; 03951 cdb->PLXTR_READ_CDDA.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF); 03952 cdb->PLXTR_READ_CDDA.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF); 03953 cdb->PLXTR_READ_CDDA.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF); 03954 cdb->PLXTR_READ_CDDA.LogicalBlockByte0 = (UCHAR) ((startingSector >> 24) & 0xFF); 03955 03956 cdb->PLXTR_READ_CDDA.TransferBlockByte3 = (UCHAR) (rawReadInfo->SectorCount & 0xFF); 03957 cdb->PLXTR_READ_CDDA.TransferBlockByte2 = (UCHAR) (rawReadInfo->SectorCount >> 8); 03958 cdb->PLXTR_READ_CDDA.TransferBlockByte1 = 0; 03959 cdb->PLXTR_READ_CDDA.TransferBlockByte0 = 0; 03960 03961 cdb->PLXTR_READ_CDDA.SubCode = 0; 03962 cdb->PLXTR_READ_CDDA.OperationCode = 0xD8; 03963 03964 } else if (cdData->XAFlags & NEC_CDDA) { 03965 03966 cdb->NEC_READ_CDDA.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF); 03967 cdb->NEC_READ_CDDA.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF); 03968 cdb->NEC_READ_CDDA.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF); 03969 cdb->NEC_READ_CDDA.LogicalBlockByte0 = (UCHAR) ((startingSector >> 24) & 0xFF); 03970 03971 cdb->NEC_READ_CDDA.TransferBlockByte1 = (UCHAR) (rawReadInfo->SectorCount & 0xFF); 03972 cdb->NEC_READ_CDDA.TransferBlockByte0 = (UCHAR) (rawReadInfo->SectorCount >> 8); 03973 03974 cdb->NEC_READ_CDDA.OperationCode = 0xD4; 03975 } 03976 } else { 03977 cdb->CDB10.LogicalUnitNumber = deviceExtension->Lun; 03978 03979 cdb->CDB10.TransferBlocksMsb = (UCHAR) (rawReadInfo->SectorCount >> 8); 03980 cdb->CDB10.TransferBlocksLsb = (UCHAR) (rawReadInfo->SectorCount & 0xFF); 03981 03982 cdb->CDB10.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF); 03983 cdb->CDB10.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF); 03984 cdb->CDB10.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF); 03985 cdb->CDB10.LogicalBlockByte0 = (UCHAR) ((startingSector >> 24) & 0xFF); 03986 03987 cdb->CDB10.OperationCode = SCSIOP_READ; 03988 } 03989 03990 srb->SrbStatus = srb->ScsiStatus = 0; 03991 03992 03993 irpStack = IoGetNextIrpStackLocation(realIrp); 03994 irpStack->MajorFunction = IRP_MJ_SCSI; 03995 irpStack->Parameters.Scsi.Srb = srb; 03996 03997 if (!(irpStack->Parameters.Others.Argument1)) { 03998 03999 // 04000 // Only jam this in if it doesn't exist. The completion routines can 04001 // call StartIo directly in the case of retries and resetting it will 04002 // cause infinite loops. 04003 // 04004 04005 irpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES; 04006 } 04007 04008 // 04009 // Set up IoCompletion routine address. 04010 // 04011 04012 IoSetCompletionRoutine(realIrp, 04013 CdRomXACompletion, 04014 srb, 04015 TRUE, 04016 TRUE, 04017 TRUE); 04018 } else { 04019 04020 ULONG maximumTransferLength = deviceExtension->PortCapabilities->MaximumTransferLength; 04021 ULONG transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(realIrp->MdlAddress), 04022 realIrpStack->Parameters.Read.Length); 04023 // 04024 // Back to cooked sectors. Build and send a normal read. 04025 // The real work for setting offsets and checking for splitrequests was 04026 // done in startio 04027 // 04028 04029 if ((realIrpStack->Parameters.Read.Length > maximumTransferLength) || 04030 (transferPages > deviceExtension->PortCapabilities->MaximumPhysicalPages)) { 04031 04032 // 04033 // Request needs to be split. Completion of each portion of the request will 04034 // fire off the next portion. The final request will signal Io to send a new request. 04035 // 04036 04037 ScsiClassSplitRequest(DeviceObject, realIrp, maximumTransferLength); 04038 return STATUS_MORE_PROCESSING_REQUIRED; 04039 04040 } else { 04041 04042 // 04043 // Build SRB and CDB for this IRP. 04044 // 04045 04046 ScsiClassBuildRequest(DeviceObject, realIrp); 04047 04048 } 04049 } 04050 04051 // 04052 // Call the port driver. 04053 // 04054 04055 IoCallDriver(deviceExtension->PortDeviceObject, realIrp); 04056 04057 return STATUS_MORE_PROCESSING_REQUIRED; 04058 } 04059 04060 // 04061 // Update device Extension flags to indicate that XA isn't supported. 04062 // 04063 04064 cdData->XAFlags |= XA_NOT_SUPPORTED; 04065 04066 // 04067 // Deallocate srb and sense buffer. 04068 // 04069 04070 if (srb) { 04071 if (srb->DataBuffer) { 04072 ExFreePool(srb->DataBuffer); 04073 } 04074 if (srb->SenseInfoBuffer) { 04075 ExFreePool(srb->SenseInfoBuffer); 04076 } 04077 ExFreePool(srb); 04078 } 04079 04080 if (Irp->PendingReturned) { 04081 IoMarkIrpPending(Irp); 04082 } 04083 04084 if (realIrp->PendingReturned) { 04085 IoMarkIrpPending(realIrp); 04086 } 04087 04088 if (Irp->MdlAddress) { 04089 IoFreeMdl(Irp->MdlAddress); 04090 } 04091 04092 IoFreeIrp(Irp); 04093 04094 // 04095 // Set status in completing IRP. 04096 // 04097 04098 realIrp->IoStatus.Status = status; 04099 04100 // 04101 // Set the hard error if necessary. 04102 // 04103 04104 if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) { 04105 04106 // 04107 // Store DeviceObject for filesystem, and clear 04108 // in IoStatus.Information field. 04109 // 04110 04111 IoSetHardErrorOrVerifyDevice(realIrp, DeviceObject); 04112 realIrp->IoStatus.Information = 0; 04113 } 04114 04115 IoCompleteRequest(realIrp, IO_DISK_INCREMENT); 04116 04117 IoStartNextPacket(DeviceObject, FALSE); 04118 04119 return STATUS_MORE_PROCESSING_REQUIRED; 04120 } 04121 04122 NTSTATUS 04123 NTAPI 04124 CdRomXACompletion( 04125 IN PDEVICE_OBJECT DeviceObject, 04126 IN PIRP Irp, 04127 IN PVOID Context 04128 ) 04129 04130 /*++ 04131 04132 Routine Description: 04133 04134 This routine executes when the port driver has completed a request. 04135 It looks at the SRB status in the completing SRB and if not success 04136 it checks for valid request sense buffer information. If valid, the 04137 info is used to update status with more precise message of type of 04138 error. This routine deallocates the SRB. 04139 04140 Arguments: 04141 04142 DeviceObject - Supplies the device object which represents the logical 04143 unit. 04144 04145 Irp - Supplies the Irp which has completed. 04146 04147 Context - Supplies a pointer to the SRB. 04148 04149 Return Value: 04150 04151 NT status 04152 04153 --*/ 04154 04155 { 04156 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); 04157 PIO_STACK_LOCATION irpNextStack = IoGetNextIrpStackLocation(Irp); 04158 PSCSI_REQUEST_BLOCK srb = Context; 04159 NTSTATUS status; 04160 BOOLEAN retry; 04161 04162 // 04163 // Check SRB status for success of completing request. 04164 // 04165 04166 if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) { 04167 04168 DebugPrint((2,"ScsiClassIoComplete: IRP %lx, SRB %lx\n", Irp, srb)); 04169 04170 // 04171 // Release the queue if it is frozen. 04172 // 04173 04174 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) { 04175 ScsiClassReleaseQueue(DeviceObject); 04176 } 04177 04178 retry = ScsiClassInterpretSenseInfo( 04179 DeviceObject, 04180 srb, 04181 irpStack->MajorFunction, 04182 irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL ? irpStack->Parameters.DeviceIoControl.IoControlCode : 0, 04183 MAXIMUM_RETRIES - ((ULONG_PTR)irpNextStack->Parameters.Others.Argument1), 04184 &status); 04185 04186 // 04187 // If the status is verified required and the this request 04188 // should bypass verify required then retry the request. 04189 // 04190 04191 if (irpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME && 04192 status == STATUS_VERIFY_REQUIRED) { 04193 04194 status = STATUS_IO_DEVICE_ERROR; 04195 retry = TRUE; 04196 } 04197 04198 if (retry && (irpNextStack->Parameters.Others.Argument1 = (PVOID)((ULONG_PTR)irpNextStack->Parameters.Others.Argument1-1))) { 04199 04200 if (((ULONG_PTR)irpNextStack->Parameters.Others.Argument1)) { 04201 04202 // 04203 // Retry request. 04204 // 04205 04206 DebugPrint((1, "CdRomXACompletion: Retry request %lx - Calling StartIo\n", Irp)); 04207 04208 04209 ExFreePool(srb->SenseInfoBuffer); 04210 ExFreePool(srb->DataBuffer); 04211 ExFreePool(srb); 04212 04213 // 04214 // Call StartIo directly since IoStartNextPacket hasn't been called, 04215 // the serialisation is still intact. 04216 // 04217 04218 ScsiCdRomStartIo(DeviceObject, Irp); 04219 return STATUS_MORE_PROCESSING_REQUIRED; 04220 04221 } 04222 04223 // 04224 // Exhausted retries. Fall through and complete the request with the appropriate status. 04225 // 04226 } 04227 } else { 04228 04229 // 04230 // Set status for successful request. 04231 // 04232 04233 status = STATUS_SUCCESS; 04234 04235 } // end if (SRB_STATUS(srb->SrbStatus) ... 04236 04237 // 04238 // Return SRB to nonpaged pool. 04239 // 04240 04241 ExFreePool(srb); 04242 04243 // 04244 // Set status in completing IRP. 04245 // 04246 04247 Irp->IoStatus.Status = status; 04248 04249 // 04250 // Set the hard error if necessary. 04251 // 04252 04253 if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) { 04254 04255 // 04256 // Store DeviceObject for filesystem, and clear 04257 // in IoStatus.Information field. 04258 // 04259 04260 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject); 04261 Irp->IoStatus.Information = 0; 04262 } 04263 04264 // 04265 // If pending has be returned for this irp then mark the current stack as 04266 // pending. 04267 // 04268 04269 if (Irp->PendingReturned) { 04270 IoMarkIrpPending(Irp); 04271 } 04272 04273 //IoCompleteRequest(Irp, IO_DISK_INCREMENT); 04274 IoStartNextPacket(DeviceObject, FALSE); 04275 04276 return status; 04277 } 04278 04279 NTSTATUS 04280 NTAPI 04281 CdRomDeviceControl( 04282 IN PDEVICE_OBJECT DeviceObject, 04283 IN PIRP Irp 04284 ) 04285 04286 /*++ 04287 04288 Routine Description: 04289 04290 This is the NT device control handler for CDROMs. 04291 04292 Arguments: 04293 04294 DeviceObject - for this CDROM 04295 04296 Irp - IO Request packet 04297 04298 Return Value: 04299 04300 NTSTATUS 04301 04302 --*/ 04303 04304 { 04305 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); 04306 PIO_STACK_LOCATION nextStack; 04307 PKEVENT deviceControlEvent; 04308 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 04309 PCDROM_DATA cdData = (PCDROM_DATA)(deviceExtension+1); 04310 SCSI_REQUEST_BLOCK srb; 04311 NTSTATUS status; 04312 KIRQL irql; 04313 04314 ULONG ioctlCode; 04315 ULONG baseCode; 04316 ULONG functionCode; 04317 04318 RetryControl: 04319 04320 // 04321 // Zero the SRB on stack. 04322 // 04323 04324 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK)); 04325 04326 Irp->IoStatus.Information = 0; 04327 04328 // 04329 // if this is a class driver ioctl then we need to change the base code 04330 // to IOCTL_CDROM_BASE so that the switch statement can handle it. 04331 // 04332 // WARNING - currently the scsi class ioctl function codes are between 04333 // 0x200 & 0x300. this routine depends on that fact 04334 // 04335 04336 ioctlCode = irpStack->Parameters.DeviceIoControl.IoControlCode; 04337 baseCode = ioctlCode >> 16; 04338 functionCode = (ioctlCode & (~0xffffc003)) >> 2; 04339 04340 DebugPrint((1, "CdRomDeviceControl: Ioctl Code = %#08lx, Base Code = %#lx," 04341 " Function Code = %#lx\n", 04342 ioctlCode, 04343 baseCode, 04344 functionCode 04345 )); 04346 04347 if((functionCode >= 0x200) && (functionCode <= 0x300)) { 04348 04349 ioctlCode = (ioctlCode & 0x0000ffff) | CTL_CODE(IOCTL_CDROM_BASE, 0, 0, 0); 04350 04351 DebugPrint((1, "CdRomDeviceControl: Class Code - new ioctl code is %#08lx\n", 04352 ioctlCode)); 04353 04354 irpStack->Parameters.DeviceIoControl.IoControlCode = ioctlCode; 04355 04356 } 04357 04358 switch (ioctlCode) { 04359 04360 case IOCTL_CDROM_RAW_READ: { 04361 04362 LARGE_INTEGER startingOffset; 04363 ULONG transferBytes; 04364 PRAW_READ_INFO rawReadInfo = (PRAW_READ_INFO)irpStack->Parameters.DeviceIoControl.Type3InputBuffer; 04365 PUCHAR userData = (PUCHAR)Irp->AssociatedIrp.SystemBuffer; 04366 04367 // 04368 // Ensure that XA reads are supported. 04369 // 04370 04371 if (cdData->XAFlags & XA_NOT_SUPPORTED) { 04372 04373 DebugPrint((1, 04374 "CdRomDeviceControl: XA Reads not supported. Flags (%x)\n", 04375 cdData->XAFlags)); 04376 04377 status = STATUS_INVALID_DEVICE_REQUEST; 04378 break; 04379 } 04380 04381 // 04382 // Check that ending sector is on disc and buffers are there and of 04383 // correct size. 04384 // 04385 04386 if (rawReadInfo == NULL) { 04387 04388 // 04389 // Called from user space. Validate the buffers. 04390 // 04391 04392 rawReadInfo = (PRAW_READ_INFO)userData; 04393 irpStack->Parameters.DeviceIoControl.Type3InputBuffer = (PVOID)userData; 04394 04395 if (rawReadInfo == NULL) { 04396 04397 DebugPrint((1,"CdRomDeviceControl: Invalid I/O parameters for XA Read (No extent info\n")); 04398 04399 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; 04400 04401 IoCompleteRequest(Irp, IO_NO_INCREMENT); 04402 return STATUS_INVALID_PARAMETER; 04403 } 04404 04405 if (irpStack->Parameters.DeviceIoControl.InputBufferLength != sizeof(RAW_READ_INFO)) { 04406 04407 DebugPrint((1,"CdRomDeviceControl: Invalid I/O parameters for XA Read (Invalid info buffer\n")); 04408 04409 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; 04410 04411 IoCompleteRequest(Irp, IO_NO_INCREMENT); 04412 return STATUS_INVALID_PARAMETER; 04413 } 04414 } 04415 04416 startingOffset.QuadPart = rawReadInfo->DiskOffset.QuadPart; 04417 transferBytes = rawReadInfo->SectorCount * RAW_SECTOR_SIZE; 04418 04419 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < transferBytes) { 04420 04421 DebugPrint((1,"CdRomDeviceControl: Invalid I/O parameters for XA Read (Bad buffer size)\n")); 04422 04423 // 04424 // Fail request with status of invalid parameters. 04425 // 04426 04427 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; 04428 04429 IoCompleteRequest(Irp, IO_NO_INCREMENT); 04430 return STATUS_INVALID_PARAMETER; 04431 } 04432 04433 if ((startingOffset.QuadPart + transferBytes) > deviceExtension->PartitionLength.QuadPart) { 04434 04435 DebugPrint((1,"CdRomDeviceControl: Invalid I/O parameters for XA Read (Request Out of Bounds)\n")); 04436 04437 // 04438 // Fail request with status of invalid parameters. 04439 // 04440 04441 status = STATUS_INVALID_PARAMETER; 04442 break; 04443 } 04444 04445 IoMarkIrpPending(Irp); 04446 IoStartPacket(DeviceObject, Irp, NULL, NULL); 04447 04448 return STATUS_PENDING; 04449 } 04450 04451 case IOCTL_CDROM_GET_DRIVE_GEOMETRY: { 04452 04453 DebugPrint((2,"CdRomDeviceControl: Get drive geometry\n")); 04454 04455 if ( irpStack->Parameters.DeviceIoControl.OutputBufferLength < 04456 sizeof( DISK_GEOMETRY ) ) { 04457 04458 status = STATUS_INFO_LENGTH_MISMATCH; 04459 break; 04460 } 04461 04462 IoMarkIrpPending(Irp); 04463 IoStartPacket(DeviceObject,Irp, NULL,NULL); 04464 04465 return STATUS_PENDING; 04466 } 04467 04468 case IOCTL_CDROM_GET_LAST_SESSION: 04469 case IOCTL_CDROM_READ_TOC: { 04470 04471 // 04472 // If the cd is playing music then reject this request. 04473 // 04474 04475 if (CdRomIsPlayActive(DeviceObject)) { 04476 Irp->IoStatus.Status = STATUS_DEVICE_BUSY; 04477 IoCompleteRequest(Irp, IO_NO_INCREMENT); 04478 return STATUS_DEVICE_BUSY; 04479 } 04480 04481 IoMarkIrpPending(Irp); 04482 IoStartPacket(DeviceObject, Irp, NULL, NULL); 04483 04484 return STATUS_PENDING; 04485 } 04486 04487 case IOCTL_CDROM_PLAY_AUDIO_MSF: { 04488 04489 // 04490 // Play Audio MSF 04491 // 04492 04493 DebugPrint((2,"CdRomDeviceControl: Play audio MSF\n")); 04494 04495 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < 04496 sizeof(CDROM_PLAY_AUDIO_MSF)) { 04497 04498 // 04499 // Indicate unsuccessful status. 04500 // 04501 04502 status = STATUS_BUFFER_TOO_SMALL; 04503 break; 04504 } 04505 04506 IoMarkIrpPending(Irp); 04507 IoStartPacket(DeviceObject, Irp, NULL, NULL); 04508 04509 return STATUS_PENDING; 04510 } 04511 04512 case IOCTL_CDROM_SEEK_AUDIO_MSF: { 04513 04514 04515 // 04516 // Seek Audio MSF 04517 // 04518 04519 DebugPrint((2,"CdRomDeviceControl: Seek audio MSF\n")); 04520 04521 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < 04522 sizeof(CDROM_SEEK_AUDIO_MSF)) { 04523 04524 // 04525 // Indicate unsuccessful status. 04526 // 04527 04528 status = STATUS_BUFFER_TOO_SMALL; 04529 break; 04530 } else { 04531 IoMarkIrpPending(Irp); 04532 IoStartPacket(DeviceObject, Irp, NULL, NULL); 04533 04534 return STATUS_PENDING; 04535 04536 } 04537 } 04538 04539 case IOCTL_CDROM_PAUSE_AUDIO: { 04540 04541 // 04542 // Pause audio 04543 // 04544 04545 DebugPrint((2, "CdRomDeviceControl: Pause audio\n")); 04546 04547 IoMarkIrpPending(Irp); 04548 IoStartPacket(DeviceObject, Irp, NULL, NULL); 04549 04550 return STATUS_PENDING; 04551 04552 break; 04553 } 04554 04555 case IOCTL_CDROM_RESUME_AUDIO: { 04556 04557 // 04558 // Resume audio 04559 // 04560 04561 DebugPrint((2, "CdRomDeviceControl: Resume audio\n")); 04562 04563 IoMarkIrpPending(Irp); 04564 IoStartPacket(DeviceObject, Irp, NULL, NULL); 04565 04566 return STATUS_PENDING; 04567 } 04568 04569 case IOCTL_CDROM_READ_Q_CHANNEL: { 04570 04571 if(irpStack->Parameters.DeviceIoControl.InputBufferLength < 04572 sizeof(CDROM_SUB_Q_DATA_FORMAT)) { 04573 04574 status = STATUS_BUFFER_TOO_SMALL; 04575 Irp->IoStatus.Information = 0; 04576 break; 04577 } 04578 04579 IoMarkIrpPending(Irp); 04580 IoStartPacket(DeviceObject, Irp, NULL, NULL); 04581 04582 return STATUS_PENDING; 04583 } 04584 04585 case IOCTL_CDROM_GET_CONTROL: { 04586 04587 DebugPrint((2, "CdRomDeviceControl: Get audio control\n")); 04588 04589 // 04590 // Verify user buffer is large enough for the data. 04591 // 04592 04593 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 04594 sizeof(CDROM_AUDIO_CONTROL)) { 04595 04596 // 04597 // Indicate unsuccessful status and no data transferred. 04598 // 04599 04600 status = STATUS_BUFFER_TOO_SMALL; 04601 Irp->IoStatus.Information = 0; 04602 break; 04603 04604 } else { 04605 04606 IoMarkIrpPending(Irp); 04607 IoStartPacket(DeviceObject, Irp, NULL, NULL); 04608 04609 return STATUS_PENDING; 04610 } 04611 } 04612 04613 case IOCTL_CDROM_GET_VOLUME: { 04614 04615 DebugPrint((2, "CdRomDeviceControl: Get volume control\n")); 04616 04617 // 04618 // Verify user buffer is large enough for data. 04619 // 04620 04621 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 04622 sizeof(VOLUME_CONTROL)) { 04623 04624 // 04625 // Indicate unsuccessful status and no data transferred. 04626 // 04627 04628 status = STATUS_BUFFER_TOO_SMALL; 04629 Irp->IoStatus.Information = 0; 04630 break; 04631 04632 } else { 04633 IoMarkIrpPending(Irp); 04634 IoStartPacket(DeviceObject, Irp, NULL, NULL); 04635 04636 return STATUS_PENDING; 04637 } 04638 } 04639 04640 case IOCTL_CDROM_SET_VOLUME: { 04641 04642 DebugPrint((2, "CdRomDeviceControl: Set volume control\n")); 04643 04644 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < 04645 sizeof(VOLUME_CONTROL)) { 04646 04647 // 04648 // Indicate unsuccessful status. 04649 // 04650 04651 status = STATUS_BUFFER_TOO_SMALL; 04652 break; 04653 } else { 04654 04655 IoMarkIrpPending(Irp); 04656 IoStartPacket(DeviceObject, Irp, NULL, NULL); 04657 04658 return STATUS_PENDING; 04659 } 04660 } 04661 04662 case IOCTL_CDROM_STOP_AUDIO: { 04663 04664 // 04665 // Stop play. 04666 // 04667 04668 DebugPrint((2, "CdRomDeviceControl: Stop audio\n")); 04669 04670 IoMarkIrpPending(Irp); 04671 IoStartPacket(DeviceObject,Irp, NULL,NULL); 04672 04673 return STATUS_PENDING; 04674 } 04675 04676 case IOCTL_CDROM_CHECK_VERIFY: { 04677 DebugPrint((1, "CdRomDeviceControl: [%lx] Check Verify\n", Irp)); 04678 IoMarkIrpPending(Irp); 04679 04680 if((irpStack->Parameters.DeviceIoControl.OutputBufferLength) && 04681 (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG))) { 04682 04683 DebugPrint((1, "CdRomDeviceControl: Check Verify: media count " 04684 "buffer too small\n")); 04685 04686 status = STATUS_BUFFER_TOO_SMALL; 04687 break; 04688 } 04689 04690 IoStartPacket(DeviceObject,Irp, NULL,NULL); 04691 04692 return STATUS_PENDING; 04693 } 04694 04695 default: { 04696 04697 // 04698 // allocate an event and stuff it into our stack location. 04699 // 04700 04701 deviceControlEvent = ExAllocatePool(NonPagedPool, sizeof(KEVENT)); 04702 04703 if(!deviceControlEvent) { 04704 04705 status = STATUS_INSUFFICIENT_RESOURCES; 04706 04707 } else { 04708 04709 PIO_STACK_LOCATION currentStack; 04710 04711 KeInitializeEvent(deviceControlEvent, NotificationEvent, FALSE); 04712 04713 currentStack = IoGetCurrentIrpStackLocation(Irp); 04714 nextStack = IoGetNextIrpStackLocation(Irp); 04715 04716 // 04717 // Copy the stack down a notch 04718 // 04719 04720 *nextStack = *currentStack; 04721 04722 IoSetCompletionRoutine( 04723 Irp, 04724 CdRomClassIoctlCompletion, 04725 deviceControlEvent, 04726 TRUE, 04727 TRUE, 04728 TRUE 04729 ); 04730 04731 IoSetNextIrpStackLocation(Irp); 04732 04733 Irp->IoStatus.Status = STATUS_SUCCESS; 04734 Irp->IoStatus.Information = 0; 04735 04736 // 04737 // Override volume verifies on this stack location so that we 04738 // will be forced through the synchronization. Once this location 04739 // goes away we get the old value back 04740 // 04741 04742 nextStack->Flags |= SL_OVERRIDE_VERIFY_VOLUME; 04743 04744 IoMarkIrpPending(Irp); 04745 04746 IoStartPacket(DeviceObject, Irp, NULL, NULL); 04747 04748 // 04749 // Wait for CdRomClassIoctlCompletion to set the event. This 04750 // ensures serialization remains intact for these unhandled device 04751 // controls. 04752 // 04753 04754 KeWaitForSingleObject( 04755 deviceControlEvent, 04756 Suspended, 04757 KernelMode, 04758 FALSE, 04759 NULL); 04760 04761 ExFreePool(deviceControlEvent); 04762 04763 DebugPrint((2, "CdRomDeviceControl: irp %#08lx synchronized\n", Irp)); 04764 04765 // 04766 // If an error occured then propagate that back up - we are no longer 04767 // guaranteed synchronization and the upper layers will have to 04768 // retry. 04769 // 04770 // If no error occured, call down to the class driver directly 04771 // then start up the next request. 04772 // 04773 04774 if(Irp->IoStatus.Status == STATUS_SUCCESS) { 04775 04776 status = ScsiClassDeviceControl(DeviceObject, Irp); 04777 04778 KeRaiseIrql(DISPATCH_LEVEL, &irql); 04779 04780 IoStartNextPacket(DeviceObject, FALSE); 04781 04782 KeLowerIrql(irql); 04783 } 04784 } 04785 04786 return status; 04787 } 04788 04789 } // end switch() 04790 04791 if (status == STATUS_VERIFY_REQUIRED) { 04792 04793 // 04794 // If the status is verified required and this request 04795 // should bypass verify required then retry the request. 04796 // 04797 04798 if (irpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME) { 04799 04800 status = STATUS_IO_DEVICE_ERROR; 04801 goto RetryControl; 04802 04803 } 04804 } 04805 04806 if (IoIsErrorUserInduced(status)) { 04807 04808 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject); 04809 04810 } 04811 04812 // 04813 // Update IRP with completion status. 04814 // 04815 04816 Irp->IoStatus.Status = status; 04817 04818 // 04819 // Complete the request. 04820 // 04821 04822 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 04823 DebugPrint((2, "CdRomDeviceControl: Status is %lx\n", status)); 04824 return status; 04825 04826 } // end ScsiCdRomDeviceControl() 04827 04828 VOID 04829 NTAPI 04830 ScanForSpecial( 04831 PDEVICE_OBJECT DeviceObject, 04832 PINQUIRYDATA InquiryData, 04833 PIO_SCSI_CAPABILITIES PortCapabilities 04834 ) 04835 04836 /*++ 04837 04838 Routine Description: 04839 04840 This function checks to see if an SCSI logical unit requires an special 04841 initialization or error processing. 04842 04843 Arguments: 04844 04845 DeviceObject - Supplies the device object to be tested. 04846 04847 InquiryData - Supplies the inquiry data returned by the device of interest. 04848 04849 PortCapabilities - Supplies the capabilities of the device object. 04850 04851 Return Value: 04852 04853 None. 04854 04855 --*/ 04856 04857 { 04858 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 04859 PCDROM_DATA cdData = (PCDROM_DATA)(deviceExtension+1); 04860 04861 // 04862 // Look for a Hitachi CDR-1750. Read-ahead must be disabled in order 04863 // to get this cdrom drive to work on scsi adapters that use PIO. 04864 // 04865 04866 if ((strncmp((PCHAR)InquiryData->VendorId, "HITACHI CDR-1750S", strlen("HITACHI CDR-1750S")) == 0 || 04867 strncmp((PCHAR)InquiryData->VendorId, "HITACHI CDR-3650/1650S", strlen("HITACHI CDR-3650/1650S")) == 0) 04868 && PortCapabilities->AdapterUsesPio) { 04869 04870 DebugPrint((1, "CdRom ScanForSpecial: Found Hitachi CDR-1750S.\n")); 04871 04872 // 04873 // Setup an error handler to reinitialize the cd rom after it is reset. 04874 // 04875 04876 deviceExtension->ClassError = HitachProcessError; 04877 04878 } else if (( RtlCompareMemory( InquiryData->VendorId,"FUJITSU", 7 ) == 7 ) && 04879 (( RtlCompareMemory( InquiryData->ProductId,"FMCD-101", 8 ) == 8 ) || 04880 ( RtlCompareMemory( InquiryData->ProductId,"FMCD-102", 8 ) == 8 ))) { 04881 04882 // 04883 // When Read command is issued to FMCD-101 or FMCD-102 and there is a music 04884 // cd in it. It takes longer time than SCSI_CDROM_TIMEOUT before returning 04885 // error status. 04886 // 04887 04888 deviceExtension->TimeOutValue = 20; 04889 04890 } else if (( RtlCompareMemory( InquiryData->VendorId,"TOSHIBA", 7) == 7) && 04891 (( RtlCompareMemory( InquiryData->ProductId,"CD-ROM XM-34", 12) == 12))) { 04892 04893 SCSI_REQUEST_BLOCK srb; 04894 PCDB cdb; 04895 ULONG length; 04896 PUCHAR buffer; 04897 NTSTATUS status; 04898 04899 // 04900 // Set the density code and the error handler. 04901 // 04902 04903 length = (sizeof(MODE_READ_RECOVERY_PAGE) + MODE_BLOCK_DESC_LENGTH + MODE_HEADER_LENGTH); 04904 04905 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK)); 04906 04907 // 04908 // Build the MODE SENSE CDB. 04909 // 04910 04911 srb.CdbLength = 6; 04912 cdb = (PCDB)srb.Cdb; 04913 04914 // 04915 // Set timeout value from device extension. 04916 // 04917 04918 srb.TimeOutValue = deviceExtension->TimeOutValue; 04919 04920 cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE; 04921 cdb->MODE_SENSE.PageCode = 0x1; 04922 cdb->MODE_SENSE.AllocationLength = (UCHAR)length; 04923 04924 buffer = ExAllocatePool(NonPagedPoolCacheAligned, (sizeof(MODE_READ_RECOVERY_PAGE) + MODE_BLOCK_DESC_LENGTH + MODE_HEADER_LENGTH)); 04925 if (!buffer) { 04926 return; 04927 } 04928 04929 status = ScsiClassSendSrbSynchronous(DeviceObject, 04930 &srb, 04931 buffer, 04932 length, 04933 FALSE); 04934 04935 ((PERROR_RECOVERY_DATA)buffer)->BlockDescriptor.DensityCode = 0x83; 04936 ((PERROR_RECOVERY_DATA)buffer)->Header.ModeDataLength = 0x0; 04937 04938 RtlCopyMemory(&cdData->u1.Header, buffer, sizeof(ERROR_RECOVERY_DATA)); 04939 04940 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK)); 04941 04942 // 04943 // Build the MODE SENSE CDB. 04944 // 04945 04946 srb.CdbLength = 6; 04947 cdb = (PCDB)srb.Cdb; 04948 04949 // 04950 // Set timeout value from device extension. 04951 // 04952 04953 srb.TimeOutValue = deviceExtension->TimeOutValue; 04954 04955 cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT; 04956 cdb->MODE_SELECT.PFBit = 1; 04957 cdb->MODE_SELECT.ParameterListLength = (UCHAR)length; 04958 04959 status = ScsiClassSendSrbSynchronous(DeviceObject, 04960 &srb, 04961 buffer, 04962 length, 04963 TRUE); 04964 04965 if (!NT_SUCCESS(status)) { 04966 DebugPrint((1, 04967 "Cdrom.ScanForSpecial: Setting density code on Toshiba failed [%x]\n", 04968 status)); 04969 } 04970 04971 deviceExtension->ClassError = ToshibaProcessError; 04972 04973 ExFreePool(buffer); 04974 04975 } 04976 04977 // 04978 // Determine special CD-DA requirements. 04979 // 04980 04981 if (RtlCompareMemory( InquiryData->VendorId,"PLEXTOR",7) == 7) { 04982 cdData->XAFlags |= PLEXTOR_CDDA; 04983 } else if (RtlCompareMemory ( InquiryData->VendorId,"NEC",3) == 3) { 04984 cdData->XAFlags |= NEC_CDDA; 04985 } 04986 04987 return; 04988 } 04989 04990 VOID 04991 NTAPI 04992 HitachProcessError( 04993 PDEVICE_OBJECT DeviceObject, 04994 PSCSI_REQUEST_BLOCK Srb, 04995 NTSTATUS *Status, 04996 BOOLEAN *Retry 04997 ) 04998 /*++ 04999 05000 Routine Description: 05001 05002 This routine checks the type of error. If the error indicates CD-ROM the 05003 CD-ROM needs to be reinitialized then a Mode sense command is sent to the 05004 device. This command disables read-ahead for the device. 05005 05006 Arguments: 05007 05008 DeviceObject - Supplies a pointer to the device object. 05009 05010 Srb - Supplies a pointer to the failing Srb. 05011 05012 Status - Not used. 05013 05014 Retry - Not used. 05015 05016 Return Value: 05017 05018 None. 05019 05020 --*/ 05021 05022 { 05023 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 05024 PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer; 05025 LARGE_INTEGER largeInt; 05026 PUCHAR modePage; 05027 PIO_STACK_LOCATION irpStack; 05028 PIRP irp; 05029 PSCSI_REQUEST_BLOCK srb; 05030 PCOMPLETION_CONTEXT context; 05031 PCDB cdb; 05032 ULONG alignment; 05033 05034 UNREFERENCED_PARAMETER(Status); 05035 UNREFERENCED_PARAMETER(Retry); 05036 05037 largeInt.QuadPart = (LONGLONG) 1; 05038 05039 // 05040 // Check the status. The initialization command only needs to be sent 05041 // if UNIT ATTENTION is returned. 05042 // 05043 05044 if (!(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID)) { 05045 05046 // 05047 // The drive does not require reinitialization. 05048 // 05049 05050 return; 05051 } 05052 05053 // 05054 // Found a bad HITACHI cd-rom. These devices do not work with PIO 05055 // adapters when read-ahead is enabled. Read-ahead is disabled by 05056 // a mode select command. The mode select page code is zero and the 05057 // length is 6 bytes. All of the other bytes should be zero. 05058 // 05059 05060 05061 if ((senseBuffer->SenseKey & 0xf) == SCSI_SENSE_UNIT_ATTENTION) { 05062 05063 DebugPrint((1, "HitachiProcessError: Reinitializing the CD-ROM.\n")); 05064 05065 // 05066 // Send the special mode select command to disable read-ahead 05067 // on the CD-ROM reader. 05068 // 05069 05070 alignment = DeviceObject->AlignmentRequirement ? 05071 DeviceObject->AlignmentRequirement : 1; 05072 05073 context = ExAllocatePool( 05074 NonPagedPool, 05075 sizeof(COMPLETION_CONTEXT) + HITACHI_MODE_DATA_SIZE + alignment 05076 ); 05077 05078 if (context == NULL) { 05079 05080 // 05081 // If there is not enough memory to fulfill this request, 05082 // simply return. A subsequent retry will fail and another 05083 // chance to start the unit. 05084 // 05085 05086 return; 05087 } 05088 05089 context->DeviceObject = DeviceObject; 05090 srb = &context->Srb; 05091 05092 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE); 05093 05094 // 05095 // Write length to SRB. 05096 // 05097 05098 srb->Length = SCSI_REQUEST_BLOCK_SIZE; 05099 05100 // 05101 // Set up SCSI bus address. 05102 // 05103 05104 srb->PathId = deviceExtension->PathId; 05105 srb->TargetId = deviceExtension->TargetId; 05106 srb->Lun = deviceExtension->Lun; 05107 05108 srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 05109 srb->TimeOutValue = deviceExtension->TimeOutValue; 05110 05111 // 05112 // Set the transfer length. 05113 // 05114 05115 srb->DataTransferLength = HITACHI_MODE_DATA_SIZE; 05116 srb->SrbFlags = SRB_FLAGS_DATA_OUT | SRB_FLAGS_DISABLE_AUTOSENSE | SRB_FLAGS_DISABLE_SYNCH_TRANSFER; 05117 05118 // 05119 // The data buffer must be aligned. 05120 // 05121 05122 srb->DataBuffer = (PVOID) (((ULONG_PTR) (context + 1) + (alignment - 1)) & 05123 ~(alignment - 1)); 05124 05125 05126 // 05127 // Build the HITACHI read-ahead mode select CDB. 05128 // 05129 05130 srb->CdbLength = 6; 05131 cdb = (PCDB)srb->Cdb; 05132 cdb->MODE_SENSE.LogicalUnitNumber = srb->Lun; 05133 cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SELECT; 05134 cdb->MODE_SENSE.AllocationLength = HITACHI_MODE_DATA_SIZE; 05135 05136 // 05137 // Initialize the mode sense data. 05138 // 05139 05140 modePage = srb->DataBuffer; 05141 05142 RtlZeroMemory(modePage, HITACHI_MODE_DATA_SIZE); 05143 05144 // 05145 // Set the page length field to 6. 05146 // 05147 05148 modePage[5] = 6; 05149 05150 // 05151 // Build the asynchronous request to be sent to the port driver. 05152 // 05153 05154 irp = IoBuildAsynchronousFsdRequest(IRP_MJ_WRITE, 05155 DeviceObject, 05156 srb->DataBuffer, 05157 srb->DataTransferLength, 05158 &largeInt, 05159 NULL); 05160 05161 IoSetCompletionRoutine(irp, 05162 (PIO_COMPLETION_ROUTINE)ScsiClassAsynchronousCompletion, 05163 context, 05164 TRUE, 05165 TRUE, 05166 TRUE); 05167 05168 irpStack = IoGetNextIrpStackLocation(irp); 05169 05170 irpStack->MajorFunction = IRP_MJ_SCSI; 05171 05172 srb->OriginalRequest = irp; 05173 05174 // 05175 // Save SRB address in next stack for port driver. 05176 // 05177 05178 irpStack->Parameters.Scsi.Srb = (PVOID)srb; 05179 05180 // 05181 // Set up IRP Address. 05182 // 05183 05184 (VOID)IoCallDriver(deviceExtension->PortDeviceObject, irp); 05185 05186 } 05187 } 05188 05189 NTSTATUS 05190 NTAPI 05191 ToshibaProcessErrorCompletion( 05192 PDEVICE_OBJECT DeviceObject, 05193 PIRP Irp, 05194 PVOID Context 05195 ) 05196 05197 /*++ 05198 05199 Routine Description: 05200 05201 Completion routine for the ClassError routine to handle older Toshiba units 05202 that require setting the density code. 05203 05204 Arguments: 05205 05206 DeviceObject - Supplies a pointer to the device object. 05207 05208 Irp - Pointer to irp created to set the density code. 05209 05210 Context - Supplies a pointer to the Mode Select Srb. 05211 05212 05213 Return Value: 05214 05215 STATUS_MORE_PROCESSING_REQUIRED 05216 05217 --*/ 05218 05219 { 05220 05221 PSCSI_REQUEST_BLOCK srb = Context; 05222 05223 // 05224 // Check for a frozen queue. 05225 // 05226 05227 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) { 05228 05229 // 05230 // Unfreeze the queue getting the device object from the context. 05231 // 05232 05233 ScsiClassReleaseQueue(DeviceObject); 05234 } 05235 05236 // 05237 // Free all of the allocations. 05238 // 05239 05240 ExFreePool(srb->DataBuffer); 05241 ExFreePool(srb); 05242 IoFreeMdl(Irp->MdlAddress); 05243 IoFreeIrp(Irp); 05244 05245 // 05246 // Indicate the I/O system should stop processing the Irp completion. 05247 // 05248 05249 return STATUS_MORE_PROCESSING_REQUIRED; 05250 } 05251 05252 VOID 05253 NTAPI 05254 ToshibaProcessError( 05255 PDEVICE_OBJECT DeviceObject, 05256 PSCSI_REQUEST_BLOCK Srb, 05257 NTSTATUS *Status, 05258 BOOLEAN *Retry 05259 ) 05260 05261 /*++ 05262 05263 Routine Description: 05264 05265 This routine checks the type of error. If the error indicates a unit attention, 05266 the density code needs to be set via a Mode select command. 05267 05268 Arguments: 05269 05270 DeviceObject - Supplies a pointer to the device object. 05271 05272 Srb - Supplies a pointer to the failing Srb. 05273 05274 Status - Not used. 05275 05276 Retry - Not used. 05277 05278 Return Value: 05279 05280 None. 05281 05282 --*/ 05283 05284 { 05285 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 05286 PCDROM_DATA cdData = (PCDROM_DATA)(deviceExtension+1); 05287 PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer; 05288 PIO_STACK_LOCATION irpStack; 05289 PIRP irp; 05290 PSCSI_REQUEST_BLOCK srb; 05291 ULONG length; 05292 PCDB cdb; 05293 PUCHAR dataBuffer; 05294 05295 05296 if (!(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID)) { 05297 return; 05298 } 05299 05300 // 05301 // The Toshiba's require the density code to be set on power up and media changes. 05302 // 05303 05304 if ((senseBuffer->SenseKey & 0xf) == SCSI_SENSE_UNIT_ATTENTION) { 05305 05306 05307 irp = IoAllocateIrp((CCHAR)(deviceExtension->DeviceObject->StackSize+1), 05308 FALSE); 05309 05310 if (!irp) { 05311 return; 05312 } 05313 05314 srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK)); 05315 if (!srb) { 05316 IoFreeIrp(irp); 05317 return; 05318 } 05319 05320 05321 length = sizeof(ERROR_RECOVERY_DATA); 05322 dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned, length); 05323 if (!dataBuffer) { 05324 ExFreePool(srb); 05325 IoFreeIrp(irp); 05326 return; 05327 } 05328 05329 irp->MdlAddress = IoAllocateMdl(dataBuffer, 05330 length, 05331 FALSE, 05332 FALSE, 05333 (PIRP) NULL); 05334 05335 if (!irp->MdlAddress) { 05336 ExFreePool(srb); 05337 ExFreePool(dataBuffer); 05338 IoFreeIrp(irp); 05339 return; 05340 } 05341 05342 // 05343 // Prepare the MDL 05344 // 05345 05346 MmBuildMdlForNonPagedPool(irp->MdlAddress); 05347 05348 RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK)); 05349 05350 srb->DataBuffer = dataBuffer; 05351 cdb = (PCDB)srb->Cdb; 05352 05353 // 05354 // Set up the irp. 05355 // 05356 05357 IoSetNextIrpStackLocation(irp); 05358 irp->IoStatus.Status = STATUS_SUCCESS; 05359 irp->IoStatus.Information = 0; 05360 irp->Flags = 0; 05361 irp->UserBuffer = NULL; 05362 05363 // 05364 // Save the device object and irp in a private stack location. 05365 // 05366 05367 irpStack = IoGetCurrentIrpStackLocation(irp); 05368 irpStack->DeviceObject = deviceExtension->DeviceObject; 05369 05370 // 05371 // Construct the IRP stack for the lower level driver. 05372 // 05373 05374 irpStack = IoGetNextIrpStackLocation(irp); 05375 irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; 05376 irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_OUT; 05377 irpStack->Parameters.Scsi.Srb = srb; 05378 05379 IoSetCompletionRoutine(irp, 05380 ToshibaProcessErrorCompletion, 05381 srb, 05382 TRUE, 05383 TRUE, 05384 TRUE); 05385 05386 srb->Length = SCSI_REQUEST_BLOCK_SIZE; 05387 srb->PathId = deviceExtension->PathId; 05388 srb->TargetId = deviceExtension->TargetId; 05389 srb->Lun = deviceExtension->Lun; 05390 srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 05391 srb->Cdb[1] |= deviceExtension->Lun << 5; 05392 srb->SrbStatus = srb->ScsiStatus = 0; 05393 srb->NextSrb = 0; 05394 srb->OriginalRequest = irp; 05395 srb->SenseInfoBufferLength = 0; 05396 05397 // 05398 // Set the transfer length. 05399 // 05400 05401 srb->DataTransferLength = length; 05402 srb->SrbFlags = SRB_FLAGS_DATA_OUT | SRB_FLAGS_DISABLE_AUTOSENSE | SRB_FLAGS_DISABLE_SYNCH_TRANSFER; 05403 05404 05405 srb->CdbLength = 6; 05406 cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT; 05407 cdb->MODE_SELECT.PFBit = 1; 05408 cdb->MODE_SELECT.ParameterListLength = (UCHAR)length; 05409 05410 // 05411 // Copy the Mode page into the databuffer. 05412 // 05413 05414 RtlCopyMemory(srb->DataBuffer, &cdData->u1.Header, length); 05415 05416 // 05417 // Set the density code. 05418 // 05419 05420 ((PERROR_RECOVERY_DATA)srb->DataBuffer)->BlockDescriptor.DensityCode = 0x83; 05421 05422 IoCallDriver(deviceExtension->PortDeviceObject, irp); 05423 } 05424 } 05425 05426 BOOLEAN 05427 NTAPI 05428 CdRomIsPlayActive( 05429 IN PDEVICE_OBJECT DeviceObject 05430 ) 05431 05432 /*++ 05433 05434 Routine Description: 05435 05436 This routine determines if the cd is currently playing music. 05437 05438 Arguments: 05439 05440 DeviceObject - Device object to test. 05441 05442 Return Value: 05443 05444 TRUE if the device is playing music. 05445 05446 --*/ 05447 { 05448 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 05449 PIRP irp; 05450 IO_STATUS_BLOCK ioStatus; 05451 KEVENT event; 05452 NTSTATUS status; 05453 PSUB_Q_CURRENT_POSITION currentBuffer; 05454 05455 if (!PLAY_ACTIVE(deviceExtension)) { 05456 return(FALSE); 05457 } 05458 05459 currentBuffer = ExAllocatePool(NonPagedPoolCacheAligned, sizeof(SUB_Q_CURRENT_POSITION)); 05460 05461 if (currentBuffer == NULL) { 05462 return(FALSE); 05463 } 05464 05465 ((PCDROM_SUB_Q_DATA_FORMAT) currentBuffer)->Format = IOCTL_CDROM_CURRENT_POSITION; 05466 ((PCDROM_SUB_Q_DATA_FORMAT) currentBuffer)->Track = 0; 05467 05468 // 05469 // Create notification event object to be used to signal the 05470 // request completion. 05471 // 05472 05473 KeInitializeEvent(&event, NotificationEvent, FALSE); 05474 05475 // 05476 // Build the synchronous request to be sent to the port driver 05477 // to perform the request. 05478 // 05479 05480 irp = IoBuildDeviceIoControlRequest(IOCTL_CDROM_READ_Q_CHANNEL, 05481 deviceExtension->DeviceObject, 05482 currentBuffer, 05483 sizeof(CDROM_SUB_Q_DATA_FORMAT), 05484 currentBuffer, 05485 sizeof(SUB_Q_CURRENT_POSITION), 05486 FALSE, 05487 &event, 05488 &ioStatus); 05489 05490 if (irp == NULL) { 05491 ExFreePool(currentBuffer); 05492 return FALSE; 05493 } 05494 05495 // 05496 // Pass request to port driver and wait for request to complete. 05497 // 05498 05499 status = IoCallDriver(deviceExtension->DeviceObject, irp); 05500 05501 if (status == STATUS_PENDING) { 05502 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL); 05503 status = ioStatus.Status; 05504 } 05505 05506 if (!NT_SUCCESS(status)) { 05507 ExFreePool(currentBuffer); 05508 return FALSE; 05509 } 05510 05511 ExFreePool(currentBuffer); 05512 05513 return(PLAY_ACTIVE(deviceExtension)); 05514 05515 } 05516 05517 IO_COMPLETION_ROUTINE CdRomMediaChangeCompletion; 05518 NTSTATUS 05519 NTAPI 05520 CdRomMediaChangeCompletion( 05521 PDEVICE_OBJECT DeviceObject, 05522 PIRP Irp, 05523 PVOID Context 05524 ) 05525 05526 /*++ 05527 05528 Routine Description: 05529 05530 This routine handles the completion of the test unit ready irps 05531 used to determine if the media has changed. If the media has 05532 changed, this code signals the named event to wake up other 05533 system services that react to media change (aka AutoPlay). 05534 05535 Arguments: 05536 05537 DeviceObject - the object for the completion 05538 Irp - the IRP being completed 05539 Context - the SRB from the IRP 05540 05541 Return Value: 05542 05543 NTSTATUS 05544 05545 --*/ 05546 05547 { 05548 PSCSI_REQUEST_BLOCK srb = (PSCSI_REQUEST_BLOCK) Context; 05549 PIO_STACK_LOCATION cdStack = IoGetCurrentIrpStackLocation(Irp); 05550 PIO_STACK_LOCATION irpNextStack = IoGetNextIrpStackLocation(Irp); 05551 PDEVICE_EXTENSION deviceExtension; 05552 PDEVICE_EXTENSION physicalExtension; 05553 PSENSE_DATA senseBuffer; 05554 PCDROM_DATA cddata; 05555 05556 ASSERT(Irp); 05557 ASSERT(cdStack); 05558 DeviceObject = cdStack->DeviceObject; 05559 ASSERT(DeviceObject); 05560 05561 deviceExtension = DeviceObject->DeviceExtension; 05562 physicalExtension = deviceExtension->PhysicalDevice->DeviceExtension; 05563 cddata = (PCDROM_DATA)(deviceExtension + 1); 05564 05565 ASSERT(cddata->MediaChangeIrp == NULL); 05566 05567 // 05568 // If the sense data field is valid, look for a media change. 05569 // otherwise this iteration of the polling will just assume nothing 05570 // changed. 05571 // 05572 05573 DebugPrint((3, "CdRomMediaChangeHandler: Completing Autorun Irp 0x%lx " 05574 "for device %d\n", 05575 Irp, deviceExtension->DeviceNumber)); 05576 05577 if (srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) { 05578 if (srb->SenseInfoBufferLength >= FIELD_OFFSET(SENSE_DATA, CommandSpecificInformation)) { 05579 05580 // 05581 // See if this is a media change. 05582 // 05583 05584 senseBuffer = srb->SenseInfoBuffer; 05585 if ((senseBuffer->SenseKey & 0x0f) == SCSI_SENSE_UNIT_ATTENTION) { 05586 if (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_MEDIUM_CHANGED) { 05587 05588 DebugPrint((1, "CdRomMediaChangeCompletion: New media inserted " 05589 "into CdRom%d [irp = 0x%lx]\n", 05590 deviceExtension->DeviceNumber, Irp)); 05591 05592 // 05593 // Media change event occurred - signal the named event. 05594 // 05595 05596 KeSetEvent(deviceExtension->MediaChangeEvent, 05597 (KPRIORITY) 0, 05598 FALSE); 05599 05600 deviceExtension->MediaChangeNoMedia = FALSE; 05601 05602 } 05603 05604 if (DeviceObject->Vpb->Flags & VPB_MOUNTED) { 05605 05606 // 05607 // Must remember the media changed and force the 05608 // file system to verify on next access 05609 // 05610 05611 DeviceObject->Flags |= DO_VERIFY_VOLUME; 05612 } 05613 05614 physicalExtension->MediaChangeCount++; 05615 05616 } else if(((senseBuffer->SenseKey & 0x0f) == SCSI_SENSE_NOT_READY)&& 05617 (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_NO_MEDIA_IN_DEVICE)&& 05618 (!deviceExtension->MediaChangeNoMedia)){ 05619 05620 // 05621 // If there was no media in the device then signal the waiters if 05622 // we haven't already done so before. 05623 // 05624 05625 DebugPrint((1, "CdRomMediaChangeCompletion: No media in device" 05626 "CdRom%d [irp = 0x%lx]\n", 05627 deviceExtension->DeviceNumber, Irp)); 05628 05629 KeSetEvent(deviceExtension->MediaChangeEvent, 05630 (KPRIORITY) 0, 05631 FALSE); 05632 05633 deviceExtension->MediaChangeNoMedia = TRUE; 05634 05635 } 05636 } 05637 } else if((srb->SrbStatus == SRB_STATUS_SUCCESS)&& 05638 (deviceExtension->MediaChangeNoMedia)) { 05639 // 05640 // We didn't have any media before and now the requests are succeeding 05641 // we probably missed the Media change somehow. Signal the change 05642 // anyway 05643 // 05644 05645 DebugPrint((1, "CdRomMediaChangeCompletion: Request completed normally" 05646 "for CdRom%d which was marked w/NoMedia [irp = 0x%lx]\n", 05647 deviceExtension->DeviceNumber, Irp)); 05648 05649 KeSetEvent(deviceExtension->MediaChangeEvent, 05650 (KPRIORITY) 0, 05651 FALSE); 05652 05653 deviceExtension->MediaChangeNoMedia = FALSE; 05654 05655 } 05656 05657 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) { 05658 ScsiClassReleaseQueue(deviceExtension->DeviceObject); 05659 } 05660 05661 // 05662 // Remember the IRP and SRB for use the next time. 05663 // 05664 05665 irpNextStack->Parameters.Scsi.Srb = srb; 05666 cddata->MediaChangeIrp = Irp; 05667 05668 if (deviceExtension->ClassError) { 05669 05670 NTSTATUS status; 05671 BOOLEAN retry; 05672 05673 // 05674 // Throw away the status and retry values. Just give the error routine a chance 05675 // to do what it needs to. 05676 // 05677 05678 deviceExtension->ClassError(DeviceObject, 05679 srb, 05680 &status, 05681 &retry); 05682 } 05683 05684 IoStartNextPacket(DeviceObject, FALSE); 05685 05686 return STATUS_MORE_PROCESSING_REQUIRED; 05687 } 05688 05689 VOID 05690 NTAPI 05691 CdRomTickHandler( 05692 IN PDEVICE_OBJECT DeviceObject, 05693 IN PVOID Context 05694 ) 05695 05696 /*++ 05697 05698 Routine Description: 05699 05700 This routine handles the once per second timer provided by the 05701 Io subsystem. It is only used when the cdrom device itself is 05702 a candidate for autoplay support. It should never be called if 05703 the cdrom device is a changer device. 05704 05705 Arguments: 05706 05707 DeviceObject - what to check. 05708 Context - not used. 05709 05710 Return Value: 05711 05712 None. 05713 05714 --*/ 05715 05716 { 05717 PIRP irp; 05718 PIRP heldIrpList; 05719 PIRP nextIrp; 05720 PLIST_ENTRY listEntry; 05721 PCDROM_DATA cddata; 05722 PIO_STACK_LOCATION irpStack; 05723 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 05724 05725 cddata = (PCDROM_DATA)(deviceExtension + 1); 05726 05727 if (cddata->MediaChange) { 05728 if (cddata->MediaChangeIrp != NULL) { 05729 05730 // 05731 // Media change support is active and the IRP is waiting. 05732 // Decrement the timer. 05733 // There is no MP protection on the timer counter. This 05734 // code is the only code that will manipulate the timer 05735 // and only one instance of it should be running at any 05736 // given time. 05737 // 05738 05739 cddata->MediaChangeCountDown--; 05740 05741 #if DBG 05742 cddata->MediaChangeIrpTimeInUse = 0; 05743 cddata->MediaChangeIrpLost = FALSE; 05744 #endif 05745 05746 if (!cddata->MediaChangeCountDown) { 05747 PSCSI_REQUEST_BLOCK srb; 05748 PIO_STACK_LOCATION irpNextStack; 05749 PCDB cdb; 05750 05751 // 05752 // Reset the timer. 05753 // 05754 05755 cddata->MediaChangeCountDown = MEDIA_CHANGE_DEFAULT_TIME; 05756 05757 // 05758 // Prepare the IRP for the test unit ready 05759 // 05760 05761 irp = cddata->MediaChangeIrp; 05762 cddata->MediaChangeIrp = NULL; 05763 05764 irp->IoStatus.Status = STATUS_SUCCESS; 05765 irp->IoStatus.Information = 0; 05766 irp->Flags = 0; 05767 irp->UserBuffer = NULL; 05768 05769 // 05770 // If the irp is sent down when the volume needs to be 05771 // verified, CdRomUpdateGeometryCompletion won't complete 05772 // it since it's not associated with a thread. Marking 05773 // it to override the verify causes it always be sent 05774 // to the port driver 05775 // 05776 05777 irpStack = IoGetCurrentIrpStackLocation(irp); 05778 irpStack->Flags |= SL_OVERRIDE_VERIFY_VOLUME; 05779 05780 irpNextStack = IoGetNextIrpStackLocation(irp); 05781 irpNextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; 05782 irpNextStack->Parameters.DeviceIoControl.IoControlCode = 05783 IOCTL_SCSI_EXECUTE_NONE; 05784 05785 // 05786 // Prepare the SRB for execution. 05787 // 05788 05789 srb = irpNextStack->Parameters.Scsi.Srb; 05790 srb->SrbStatus = srb->ScsiStatus = 0; 05791 srb->NextSrb = 0; 05792 srb->Length = SCSI_REQUEST_BLOCK_SIZE; 05793 srb->PathId = deviceExtension->PathId; 05794 srb->TargetId = deviceExtension->TargetId; 05795 srb->Lun = deviceExtension->Lun; 05796 srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 05797 srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER | 05798 SRB_FLAGS_DISABLE_SYNCH_TRANSFER; 05799 srb->DataTransferLength = 0; 05800 srb->OriginalRequest = irp; 05801 05802 RtlZeroMemory(srb->SenseInfoBuffer, SENSE_BUFFER_SIZE); 05803 srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE; 05804 05805 cdb = (PCDB) &srb->Cdb[0]; 05806 cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY; 05807 cdb->CDB6GENERIC.LogicalUnitNumber = srb->Lun; 05808 05809 // 05810 // Setup the IRP to perform a test unit ready. 05811 // 05812 05813 IoSetCompletionRoutine(irp, 05814 CdRomMediaChangeCompletion, 05815 srb, 05816 TRUE, 05817 TRUE, 05818 TRUE); 05819 05820 // 05821 // Issue the request. 05822 // 05823 05824 IoStartPacket(DeviceObject, irp, NULL, NULL); 05825 } 05826 } else { 05827 05828 #if DBG 05829 if(cddata->MediaChangeIrpLost == FALSE) { 05830 if(cddata->MediaChangeIrpTimeInUse++ > 05831 MEDIA_CHANGE_TIMEOUT_TIME) { 05832 05833 DebugPrint((0, "CdRom%d: AutoPlay has lost it's irp and " 05834 "doesn't know where to find it. Leave it " 05835 "alone and it'll come home dragging it's " 05836 "stack behind it.\n", 05837 deviceExtension->DeviceNumber)); 05838 cddata->MediaChangeIrpLost = TRUE; 05839 } 05840 } 05841 05842 #endif 05843 } 05844 } 05845 05846 // 05847 // Process all generic timer IRPS in the timer list. As IRPs are pulled 05848 // off of the TimerIrpList they must be remembered in the first loop 05849 // if they are not sent to the lower driver. After all items have 05850 // been pulled off the list, it is possible to put the held IRPs back 05851 // into the TimerIrpList. 05852 // 05853 05854 heldIrpList = NULL; 05855 if (IsListEmpty(&cddata->TimerIrpList)) { 05856 listEntry = NULL; 05857 } else { 05858 listEntry = ExInterlockedRemoveHeadList(&cddata->TimerIrpList, 05859 &cddata->TimerIrpSpinLock); 05860 } 05861 while (listEntry) { 05862 05863 // 05864 // There is something in the timer list. Pick up the IRP and 05865 // see if it is ready to be submitted. 05866 // 05867 05868 irp = CONTAINING_RECORD(listEntry, IRP, Tail.Overlay.ListEntry); 05869 irpStack = IoGetCurrentIrpStackLocation(irp); 05870 05871 if (irpStack->Parameters.Others.Argument3) { 05872 ULONG_PTR count; 05873 05874 // 05875 // Decrement the countdown timer and put the IRP back in the list. 05876 // 05877 05878 count = (ULONG_PTR) irpStack->Parameters.Others.Argument3; 05879 count--; 05880 irpStack->Parameters.Others.Argument3 = (PVOID) count; 05881 05882 ASSERT(irp->AssociatedIrp.MasterIrp == NULL); 05883 if (heldIrpList) { 05884 irp->AssociatedIrp.MasterIrp = (PVOID) heldIrpList; 05885 } 05886 heldIrpList = irp; 05887 05888 } else { 05889 05890 // 05891 // Submit this IRP to the lower driver. This IRP does not 05892 // need to be remembered here. It will be handled again when 05893 // it completes. 05894 // 05895 05896 DebugPrint((1, "CdRomTickHandler: Reissuing request %lx (thread = %lx)\n", irp, irp->Tail.Overlay.Thread)); 05897 05898 // 05899 // feed this to the appropriate port driver 05900 // 05901 05902 IoCallDriver (deviceExtension->PortDeviceObject, irp); 05903 05904 } 05905 05906 // 05907 // Pick up the next IRP from the timer list. 05908 // 05909 05910 listEntry = ExInterlockedRemoveHeadList(&cddata->TimerIrpList, 05911 &cddata->TimerIrpSpinLock); 05912 } 05913 05914 // 05915 // Move all held IRPs back onto the timer list. 05916 // 05917 05918 while (heldIrpList) { 05919 05920 // 05921 // Save the single list pointer before queueing this IRP. 05922 // 05923 05924 nextIrp = (PIRP) heldIrpList->AssociatedIrp.MasterIrp; 05925 heldIrpList->AssociatedIrp.MasterIrp = NULL; 05926 05927 // 05928 // Return the held IRP to the timer list. 05929 // 05930 05931 ExInterlockedInsertTailList(&cddata->TimerIrpList, 05932 &heldIrpList->Tail.Overlay.ListEntry, 05933 &cddata->TimerIrpSpinLock); 05934 05935 // 05936 // Continue processing the held IRPs 05937 // 05938 05939 heldIrpList = nextIrp; 05940 } 05941 } 05942 05943 BOOLEAN 05944 NTAPI 05945 CdRomCheckRegistryForMediaChangeValue( 05946 IN PUNICODE_STRING RegistryPath, 05947 IN ULONG DeviceNumber 05948 ) 05949 05950 /*++ 05951 05952 Routine Description: 05953 05954 The user must specify that AutoPlay is to run on the platform 05955 by setting the registry value HKEY_LOCAL_MACHINE\System\CurrentControlSet\ 05956 Services\Cdrom\Autorun:REG_DWORD:1. 05957 05958 The user can override the global setting to enable or disable Autorun on a 05959 specific cdrom device by setting the key HKEY_LOCAL_MACHINE\System\ 05960 CurrentControlSet\Services\Cdrom\Device<N>\Autorun:REG_DWORD to one or zero. 05961 (CURRENTLY UNIMPLEMENTED) 05962 05963 If this registry value does not exist or contains the value zero then 05964 the timer to check for media change does not run. 05965 05966 Arguments: 05967 05968 RegistryPath - pointer to the unicode string inside 05969 ...\CurrentControlSet\Services\Cdrom 05970 DeviceNumber - The number of the device object 05971 05972 Return Value: 05973 05974 TRUE - Autorun is enabled. 05975 FALSE - no autorun. 05976 05977 --*/ 05978 05979 { 05980 #define ITEMS_TO_QUERY 2 /* always 1 greater than what is searched */ 05981 PRTL_QUERY_REGISTRY_TABLE parameters = NULL; 05982 NTSTATUS status; 05983 LONG zero = 0; 05984 05985 LONG tmp = 0; 05986 LONG doRun = 0; 05987 05988 CHAR buf[32]; 05989 ANSI_STRING paramNum; 05990 05991 UNICODE_STRING paramStr; 05992 05993 UNICODE_STRING paramSuffix; 05994 UNICODE_STRING paramPath; 05995 UNICODE_STRING paramDevPath; 05996 05997 // 05998 // First append \Parameters to the passed in registry path 05999 // 06000 06001 RtlInitUnicodeString(¶mStr, L"\\Parameters"); 06002 06003 RtlInitUnicodeString(¶mPath, NULL); 06004 06005 paramPath.MaximumLength = RegistryPath->Length + 06006 paramStr.Length + 06007 sizeof(WCHAR); 06008 06009 paramPath.Buffer = ExAllocatePool(PagedPool, paramPath.MaximumLength); 06010 06011 if(!paramPath.Buffer) { 06012 06013 DebugPrint((1,"CdRomCheckRegAP: couldn't allocate paramPath\n")); 06014 06015 return FALSE; 06016 } 06017 06018 RtlZeroMemory(paramPath.Buffer, paramPath.MaximumLength); 06019 RtlAppendUnicodeToString(¶mPath, RegistryPath->Buffer); 06020 RtlAppendUnicodeToString(¶mPath, paramStr.Buffer); 06021 06022 DebugPrint((2, "CdRomCheckRegAP: paramPath [%d] = %ws\n", 06023 paramPath.Length, 06024 paramPath.Buffer)); 06025 06026 // 06027 // build a counted ANSI string that contains 06028 // the suffix for the path 06029 // 06030 06031 sprintf(buf, "\\Device%lu", DeviceNumber); 06032 RtlInitAnsiString(¶mNum, buf); 06033 06034 // 06035 // Next convert this into a unicode string 06036 // 06037 06038 status = RtlAnsiStringToUnicodeString(¶mSuffix, ¶mNum, TRUE); 06039 06040 if(!NT_SUCCESS(status)) { 06041 DebugPrint((1,"CdRomCheckRegAP: couldn't convert paramNum to paramSuffix\n")); 06042 ExFreePool(paramPath.Buffer); 06043 return FALSE; 06044 } 06045 06046 RtlInitUnicodeString(¶mDevPath, NULL); 06047 06048 // 06049 // now build the device specific path 06050 // 06051 06052 paramDevPath.MaximumLength = paramPath.Length + 06053 paramSuffix.Length + 06054 sizeof(WCHAR); 06055 paramDevPath.Buffer = ExAllocatePool(PagedPool, paramDevPath.MaximumLength); 06056 06057 if(!paramDevPath.Buffer) { 06058 RtlFreeUnicodeString(¶mSuffix); 06059 ExFreePool(paramPath.Buffer); 06060 return FALSE; 06061 } 06062 06063 RtlZeroMemory(paramDevPath.Buffer, paramDevPath.MaximumLength); 06064 RtlAppendUnicodeToString(¶mDevPath, paramPath.Buffer); 06065 RtlAppendUnicodeToString(¶mDevPath, paramSuffix.Buffer); 06066 06067 DebugPrint((2, "CdRomCheckRegAP: paramDevPath [%d] = %ws\n", 06068 paramPath.Length, 06069 paramPath.Buffer)); 06070 06071 parameters = ExAllocatePool(NonPagedPool, 06072 sizeof(RTL_QUERY_REGISTRY_TABLE)*ITEMS_TO_QUERY); 06073 06074 if (parameters) { 06075 06076 // 06077 // Check for the Autorun value. 06078 // 06079 06080 RtlZeroMemory(parameters, 06081 (sizeof(RTL_QUERY_REGISTRY_TABLE)*ITEMS_TO_QUERY)); 06082 06083 parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT; 06084 parameters[0].Name = L"Autorun"; 06085 parameters[0].EntryContext = &doRun; 06086 parameters[0].DefaultType = REG_DWORD; 06087 parameters[0].DefaultData = &zero; 06088 parameters[0].DefaultLength = sizeof(ULONG); 06089 06090 status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL, 06091 RegistryPath->Buffer, 06092 parameters, 06093 NULL, 06094 NULL); 06095 06096 DebugPrint((2, "CdRomCheckRegAP: cdrom/Autorun flag = %d\n", doRun)); 06097 06098 RtlZeroMemory(parameters, 06099 (sizeof(RTL_QUERY_REGISTRY_TABLE)*ITEMS_TO_QUERY)); 06100 06101 parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT; 06102 parameters[0].Name = L"Autorun"; 06103 parameters[0].EntryContext = &tmp; 06104 parameters[0].DefaultType = REG_DWORD; 06105 parameters[0].DefaultData = &doRun; 06106 parameters[0].DefaultLength = sizeof(ULONG); 06107 06108 status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL, 06109 paramPath.Buffer, 06110 parameters, 06111 NULL, 06112 NULL); 06113 06114 DebugPrint((2, "CdRomCheckRegAP: cdrom/parameters/autorun flag = %d\n", tmp)); 06115 06116 RtlZeroMemory(parameters, 06117 (sizeof(RTL_QUERY_REGISTRY_TABLE) * ITEMS_TO_QUERY)); 06118 06119 parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT; 06120 parameters[0].Name = L"Autorun"; 06121 parameters[0].EntryContext = &doRun; 06122 parameters[0].DefaultType = REG_DWORD; 06123 parameters[0].DefaultData = &tmp; 06124 parameters[0].DefaultLength = sizeof(ULONG); 06125 06126 status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL, 06127 paramDevPath.Buffer, 06128 parameters, 06129 NULL, 06130 NULL); 06131 06132 DebugPrint((1, "CdRomCheckRegAP: cdrom/parameters/device%d/autorun flag = %d\n", DeviceNumber, doRun)); 06133 06134 ExFreePool(parameters); 06135 06136 } 06137 06138 ExFreePool(paramPath.Buffer); 06139 ExFreePool(paramDevPath.Buffer); 06140 RtlFreeUnicodeString(¶mSuffix); 06141 06142 DebugPrint((1, "CdRomCheckRegAP: Autoplay for device %d is %s\n", 06143 DeviceNumber, 06144 (doRun ? "on" : "off"))); 06145 06146 if(doRun) { 06147 return TRUE; 06148 } 06149 06150 return FALSE; 06151 } 06152 06153 06154 BOOLEAN 06155 NTAPI 06156 IsThisASanyo( 06157 IN PDEVICE_OBJECT DeviceObject, 06158 IN UCHAR PathId, 06159 IN UCHAR TargetId 06160 ) 06161 06162 /*++ 06163 06164 Routine Description: 06165 06166 This routine is called by DriverEntry to determine whether a Sanyo 3-CD 06167 changer device is present. 06168 06169 Arguments: 06170 06171 DeviceObject - Supplies the device object for the 'real' device. 06172 06173 PathId - 06174 06175 Return Value: 06176 06177 TRUE - if an Atapi changer device is found. 06178 06179 --*/ 06180 06181 { 06182 KEVENT event; 06183 PIRP irp; 06184 PCHAR inquiryBuffer; 06185 IO_STATUS_BLOCK ioStatus; 06186 NTSTATUS status; 06187 PSCSI_ADAPTER_BUS_INFO adapterInfo; 06188 ULONG scsiBus; 06189 PINQUIRYDATA inquiryData; 06190 PSCSI_INQUIRY_DATA lunInfo; 06191 06192 inquiryBuffer = ExAllocatePool(NonPagedPool, 2048); 06193 KeInitializeEvent(&event, NotificationEvent, FALSE); 06194 irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_INQUIRY_DATA, 06195 DeviceObject, 06196 NULL, 06197 0, 06198 inquiryBuffer, 06199 2048, 06200 FALSE, 06201 &event, 06202 &ioStatus); 06203 if (!irp) { 06204 return FALSE; 06205 } 06206 06207 status = IoCallDriver(DeviceObject, irp); 06208 06209 if (status == STATUS_PENDING) { 06210 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); 06211 status = ioStatus.Status; 06212 } 06213 06214 if (!NT_SUCCESS(status)) { 06215 return FALSE; 06216 } 06217 06218 adapterInfo = (PVOID) inquiryBuffer; 06219 06220 for (scsiBus=0; scsiBus < (ULONG)adapterInfo->NumberOfBuses; scsiBus++) { 06221 06222 // 06223 // Get the SCSI bus scan data for this bus. 06224 // 06225 06226 lunInfo = (PVOID) (inquiryBuffer + adapterInfo->BusData[scsiBus].InquiryDataOffset); 06227 06228 for (;;) { 06229 06230 if (lunInfo->PathId == PathId && lunInfo->TargetId == TargetId) { 06231 06232 inquiryData = (PVOID) lunInfo->InquiryData; 06233 06234 if (RtlCompareMemory(inquiryData->VendorId, "TORiSAN CD-ROM CDR-C", 20) == 20) { 06235 ExFreePool(inquiryBuffer); 06236 return TRUE; 06237 } 06238 06239 ExFreePool(inquiryBuffer); 06240 return FALSE; 06241 } 06242 06243 if (!lunInfo->NextInquiryDataOffset) { 06244 break; 06245 } 06246 06247 lunInfo = (PVOID) (inquiryBuffer + lunInfo->NextInquiryDataOffset); 06248 } 06249 } 06250 06251 ExFreePool(inquiryBuffer); 06252 return FALSE; 06253 } 06254 06255 BOOLEAN 06256 NTAPI 06257 IsThisAnAtapiChanger( 06258 IN PDEVICE_OBJECT DeviceObject, 06259 OUT PULONG DiscsPresent 06260 ) 06261 06262 /*++ 06263 06264 Routine Description: 06265 06266 This routine is called by DriverEntry to determine whether an Atapi 06267 changer device is present. 06268 06269 Arguments: 06270 06271 DeviceObject - Supplies the device object for the 'real' device. 06272 06273 DiscsPresent - Supplies a pointer to the number of Discs supported by the changer. 06274 06275 Return Value: 06276 06277 TRUE - if an Atapi changer device is found. 06278 06279 --*/ 06280 06281 { 06282 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 06283 PMECHANICAL_STATUS_INFORMATION_HEADER mechanicalStatusBuffer; 06284 NTSTATUS status; 06285 SCSI_REQUEST_BLOCK srb; 06286 PCDB cdb = (PCDB) &srb.Cdb[0]; 06287 BOOLEAN retVal = FALSE; 06288 06289 *DiscsPresent = 0; 06290 06291 // 06292 // Some devices can't handle 12 byte CDB's gracefully 06293 // 06294 06295 if(deviceExtension->DeviceFlags & DEV_NO_12BYTE_CDB) { 06296 06297 return FALSE; 06298 06299 } 06300 06301 // 06302 // Build and issue the mechanical status command. 06303 // 06304 06305 mechanicalStatusBuffer = ExAllocatePool(NonPagedPoolCacheAligned, 06306 sizeof(MECHANICAL_STATUS_INFORMATION_HEADER)); 06307 06308 if (!mechanicalStatusBuffer) { 06309 retVal = FALSE; 06310 } else { 06311 06312 // 06313 // Build and send the Mechanism status CDB. 06314 // 06315 06316 RtlZeroMemory(&srb, sizeof(srb)); 06317 06318 srb.CdbLength = 12; 06319 srb.TimeOutValue = 20; 06320 06321 cdb->MECH_STATUS.OperationCode = SCSIOP_MECHANISM_STATUS; 06322 cdb->MECH_STATUS.AllocationLength[1] = sizeof(MECHANICAL_STATUS_INFORMATION_HEADER); 06323 06324 status = ScsiClassSendSrbSynchronous(DeviceObject, 06325 &srb, 06326 mechanicalStatusBuffer, 06327 sizeof(MECHANICAL_STATUS_INFORMATION_HEADER), 06328 FALSE); 06329 06330 06331 if (status == STATUS_SUCCESS) { 06332 06333 // 06334 // Indicate number of slots available 06335 // 06336 06337 *DiscsPresent = mechanicalStatusBuffer->NumberAvailableSlots; 06338 if (*DiscsPresent > 1) { 06339 retVal = TRUE; 06340 } else { 06341 06342 // 06343 // If only one disc, no need for this driver. 06344 // 06345 06346 retVal = FALSE; 06347 } 06348 } else { 06349 06350 // 06351 // Device doesn't support this command. 06352 // 06353 06354 retVal = FALSE; 06355 } 06356 06357 ExFreePool(mechanicalStatusBuffer); 06358 } 06359 06360 return retVal; 06361 } 06362 06363 BOOLEAN 06364 NTAPI 06365 IsThisAMultiLunDevice( 06366 IN PDEVICE_OBJECT DeviceObject, 06367 IN PDEVICE_OBJECT PortDeviceObject 06368 ) 06369 /*++ 06370 06371 Routine Description: 06372 06373 This routine is called to determine whether a multi-lun 06374 device is present. 06375 06376 Arguments: 06377 06378 DeviceObject - Supplies the device object for the 'real' device. 06379 06380 Return Value: 06381 06382 TRUE - if a Multi-lun device is found. 06383 06384 --*/ 06385 { 06386 PCHAR buffer; 06387 PSCSI_INQUIRY_DATA lunInfo; 06388 PSCSI_ADAPTER_BUS_INFO adapterInfo; 06389 PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension; 06390 PINQUIRYDATA inquiryData; 06391 ULONG scsiBus; 06392 NTSTATUS status; 06393 UCHAR lunCount = 0; 06394 06395 status = ScsiClassGetInquiryData(PortDeviceObject, (PSCSI_ADAPTER_BUS_INFO *) &buffer); 06396 06397 if (!NT_SUCCESS(status)) { 06398 DebugPrint((1,"IsThisAMultiLunDevice: ScsiClassGetInquiryData failed\n")); 06399 return FALSE; 06400 } 06401 06402 adapterInfo = (PVOID) buffer; 06403 06404 // 06405 // For each SCSI bus this adapter supports ... 06406 // 06407 06408 for (scsiBus=0; scsiBus < adapterInfo->NumberOfBuses; scsiBus++) { 06409 06410 // 06411 // Get the SCSI bus scan data for this bus. 06412 // 06413 06414 lunInfo = (PVOID) (buffer + adapterInfo->BusData[scsiBus].InquiryDataOffset); 06415 06416 while (adapterInfo->BusData[scsiBus].InquiryDataOffset) { 06417 06418 inquiryData = (PVOID)lunInfo->InquiryData; 06419 06420 if ((lunInfo->PathId == deviceExtension->PathId) && 06421 (lunInfo->TargetId == deviceExtension->TargetId) && 06422 (inquiryData->DeviceType == READ_ONLY_DIRECT_ACCESS_DEVICE)) { 06423 06424 DebugPrint((1,"IsThisAMultiLunDevice: Vendor string is %.24s\n", 06425 inquiryData->VendorId)); 06426 06427 // 06428 // If this device has more than one cdrom-type lun then we 06429 // won't support autoplay on it 06430 // 06431 06432 if (lunCount++) { 06433 ExFreePool(buffer); 06434 return TRUE; 06435 } 06436 } 06437 06438 // 06439 // Get next LunInfo. 06440 // 06441 06442 if (lunInfo->NextInquiryDataOffset == 0) { 06443 break; 06444 } 06445 06446 lunInfo = (PVOID) (buffer + lunInfo->NextInquiryDataOffset); 06447 } 06448 } 06449 06450 ExFreePool(buffer); 06451 return FALSE; 06452 06453 } 06454 06455 IO_COMPLETION_ROUTINE CdRomUpdateGeometryCompletion; 06456 NTSTATUS 06457 NTAPI 06458 CdRomUpdateGeometryCompletion( 06459 PDEVICE_OBJECT DeviceObject, 06460 PIRP Irp, 06461 PVOID Context 06462 ) 06463 06464 /*++ 06465 06466 Routine Description: 06467 06468 This routine andles the completion of the test unit ready irps 06469 used to determine if the media has changed. If the media has 06470 changed, this code signals the named event to wake up other 06471 system services that react to media change (aka AutoPlay). 06472 06473 Arguments: 06474 06475 DeviceObject - the object for the completion 06476 Irp - the IRP being completed 06477 Context - the SRB from the IRP 06478 06479 Return Value: 06480 06481 NTSTATUS 06482 06483 --*/ 06484 06485 { 06486 PSCSI_REQUEST_BLOCK srb = (PSCSI_REQUEST_BLOCK) Context; 06487 PREAD_CAPACITY_DATA readCapacityBuffer; 06488 PDEVICE_EXTENSION deviceExtension; 06489 PIO_STACK_LOCATION irpStack; 06490 NTSTATUS status; 06491 BOOLEAN retry; 06492 ULONG_PTR retryCount; 06493 ULONG lastSector; 06494 PIRP originalIrp; 06495 PCDROM_DATA cddata; 06496 06497 // 06498 // Get items saved in the private IRP stack location. 06499 // 06500 06501 irpStack = IoGetCurrentIrpStackLocation(Irp); 06502 retryCount = (ULONG_PTR) irpStack->Parameters.Others.Argument1; 06503 originalIrp = (PIRP) irpStack->Parameters.Others.Argument2; 06504 06505 if (!DeviceObject) { 06506 DeviceObject = irpStack->DeviceObject; 06507 } 06508 ASSERT(DeviceObject); 06509 06510 deviceExtension = DeviceObject->DeviceExtension; 06511 cddata = (PCDROM_DATA) (deviceExtension + 1); 06512 readCapacityBuffer = srb->DataBuffer; 06513 06514 if ((NT_SUCCESS(Irp->IoStatus.Status)) && (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_SUCCESS)) { 06515 PFOUR_BYTE from; 06516 PFOUR_BYTE to; 06517 06518 DebugPrint((2, "CdRomUpdateCapacityCompletion: [%lx] successful completion of buddy-irp %lx\n", originalIrp, Irp)); 06519 // 06520 // Copy sector size from read capacity buffer to device extension 06521 // in reverse byte order. 06522 // 06523 06524 from = (PFOUR_BYTE) &readCapacityBuffer->BytesPerBlock; 06525 to = (PFOUR_BYTE) &deviceExtension->DiskGeometry->Geometry.BytesPerSector; 06526 to->Byte0 = from->Byte3; 06527 to->Byte1 = from->Byte2; 06528 to->Byte2 = from->Byte1; 06529 to->Byte3 = from->Byte0; 06530 06531 // 06532 // Using the new BytesPerBlock, calculate and store the SectorShift. 06533 // 06534 06535 WHICH_BIT(deviceExtension->DiskGeometry->Geometry.BytesPerSector, deviceExtension->SectorShift); 06536 06537 // 06538 // Copy last sector in reverse byte order. 06539 // 06540 06541 from = (PFOUR_BYTE) &readCapacityBuffer->LogicalBlockAddress; 06542 to = (PFOUR_BYTE) &lastSector; 06543 to->Byte0 = from->Byte3; 06544 to->Byte1 = from->Byte2; 06545 to->Byte2 = from->Byte1; 06546 to->Byte3 = from->Byte0; 06547 deviceExtension->PartitionLength.QuadPart = (LONGLONG)(lastSector + 1); 06548 06549 // 06550 // Calculate number of cylinders. 06551 // 06552 06553 deviceExtension->DiskGeometry->Geometry.Cylinders.QuadPart = (LONGLONG)((lastSector + 1)/(32 * 64)); 06554 deviceExtension->PartitionLength.QuadPart = 06555 (deviceExtension->PartitionLength.QuadPart << deviceExtension->SectorShift); 06556 deviceExtension->DiskGeometry->Geometry.MediaType = RemovableMedia; 06557 06558 // 06559 // Assume sectors per track are 32; 06560 // 06561 06562 deviceExtension->DiskGeometry->Geometry.SectorsPerTrack = 32; 06563 06564 // 06565 // Assume tracks per cylinder (number of heads) is 64. 06566 // 06567 06568 deviceExtension->DiskGeometry->Geometry.TracksPerCylinder = 64; 06569 06570 } else { 06571 06572 DebugPrint((1, "CdRomUpdateCapacityCompletion: [%lx] unsuccessful completion of buddy-irp %lx (status - %lx)\n", originalIrp, Irp, Irp->IoStatus.Status)); 06573 06574 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) { 06575 ScsiClassReleaseQueue(DeviceObject); 06576 } 06577 06578 retry = ScsiClassInterpretSenseInfo(DeviceObject, 06579 srb, 06580 IRP_MJ_SCSI, 06581 0, 06582 retryCount, 06583 &status); 06584 if (retry) { 06585 retryCount--; 06586 if (retryCount) { 06587 PCDB cdb; 06588 06589 DebugPrint((1, "CdRomUpdateCapacityCompletion: [%lx] Retrying request %lx .. thread is %lx\n", originalIrp, Irp, Irp->Tail.Overlay.Thread)); 06590 // 06591 // set up a one shot timer to get this process started over 06592 // 06593 06594 irpStack->Parameters.Others.Argument1 = (PVOID) retryCount; 06595 irpStack->Parameters.Others.Argument2 = (PVOID) originalIrp; 06596 irpStack->Parameters.Others.Argument3 = (PVOID) 2; 06597 06598 // 06599 // Setup the IRP to be submitted again in the timer routine. 06600 // 06601 06602 irpStack = IoGetNextIrpStackLocation(Irp); 06603 irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; 06604 irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN; 06605 irpStack->Parameters.Scsi.Srb = srb; 06606 IoSetCompletionRoutine(Irp, 06607 CdRomUpdateGeometryCompletion, 06608 srb, 06609 TRUE, 06610 TRUE, 06611 TRUE); 06612 06613 // 06614 // Set up the SRB for read capacity. 06615 // 06616 06617 srb->CdbLength = 10; 06618 srb->TimeOutValue = deviceExtension->TimeOutValue; 06619 srb->SrbStatus = srb->ScsiStatus = 0; 06620 srb->NextSrb = 0; 06621 srb->Length = SCSI_REQUEST_BLOCK_SIZE; 06622 srb->PathId = deviceExtension->PathId; 06623 srb->TargetId = deviceExtension->TargetId; 06624 srb->Lun = deviceExtension->Lun; 06625 srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 06626 srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER; 06627 srb->DataTransferLength = sizeof(READ_CAPACITY_DATA); 06628 06629 // 06630 // Set up the CDB 06631 // 06632 06633 cdb = (PCDB) &srb->Cdb[0]; 06634 cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY; 06635 cdb->CDB10.LogicalUnitNumber = deviceExtension->Lun; 06636 06637 // 06638 // Requests queued onto this list will be sent to the 06639 // lower level driver during CdRomTickHandler 06640 // 06641 06642 ExInterlockedInsertHeadList(&cddata->TimerIrpList, 06643 &Irp->Tail.Overlay.ListEntry, 06644 &cddata->TimerIrpSpinLock); 06645 06646 return STATUS_MORE_PROCESSING_REQUIRED; 06647 } else { 06648 06649 // 06650 // This has been bounced for a number of times. Error the 06651 // original request. 06652 // 06653 06654 originalIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 06655 RtlZeroMemory(deviceExtension->DiskGeometry, sizeof(DISK_GEOMETRY_EX)); 06656 deviceExtension->DiskGeometry->Geometry.BytesPerSector = 2048; 06657 deviceExtension->SectorShift = 11; 06658 deviceExtension->PartitionLength.QuadPart = (LONGLONG)(0x7fffffff); 06659 deviceExtension->DiskGeometry->Geometry.MediaType = RemovableMedia; 06660 } 06661 } else { 06662 06663 // 06664 // Set up reasonable defaults 06665 // 06666 06667 RtlZeroMemory(deviceExtension->DiskGeometry, sizeof(DISK_GEOMETRY_EX)); 06668 deviceExtension->DiskGeometry->Geometry.BytesPerSector = 2048; 06669 deviceExtension->SectorShift = 11; 06670 deviceExtension->PartitionLength.QuadPart = (LONGLONG)(0x7fffffff); 06671 deviceExtension->DiskGeometry->Geometry.MediaType = RemovableMedia; 06672 } 06673 } 06674 06675 // 06676 // Free resources held. 06677 // 06678 06679 ExFreePool(srb->SenseInfoBuffer); 06680 ExFreePool(srb->DataBuffer); 06681 ExFreePool(srb); 06682 if (Irp->MdlAddress) { 06683 IoFreeMdl(Irp->MdlAddress); 06684 } 06685 IoFreeIrp(Irp); 06686 if (originalIrp->Tail.Overlay.Thread) { 06687 06688 DebugPrint((2, "CdRomUpdateCapacityCompletion: [%lx] completing original IRP\n", originalIrp)); 06689 IoCompleteRequest(originalIrp, IO_DISK_INCREMENT); 06690 06691 } else { 06692 DebugPrint((1, "CdRomUpdateCapacityCompletion: [%lx] original irp has " 06693 "no thread\n", 06694 originalIrp 06695 )); 06696 } 06697 06698 // 06699 // It's now safe to either start the next request or let the waiting ioctl 06700 // request continue along it's merry way 06701 // 06702 06703 IoStartNextPacket(DeviceObject, FALSE); 06704 06705 return STATUS_MORE_PROCESSING_REQUIRED; 06706 } 06707 06708 NTSTATUS 06709 NTAPI 06710 CdRomUpdateCapacity( 06711 IN PDEVICE_EXTENSION DeviceExtension, 06712 IN PIRP IrpToComplete, 06713 IN OPTIONAL PKEVENT IoctlEvent 06714 ) 06715 06716 /*++ 06717 06718 Routine Description: 06719 06720 This routine updates the capacity of the disk as recorded in the device extension. 06721 It also completes the IRP given with STATUS_VERIFY_REQUIRED. This routine is called 06722 when a media change has occurred and it is necessary to determine the capacity of the 06723 new media prior to the next access. 06724 06725 Arguments: 06726 06727 DeviceExtension - the device to update 06728 IrpToComplete - the request that needs to be completed when done. 06729 06730 Return Value: 06731 06732 NTSTATUS 06733 06734 --*/ 06735 06736 { 06737 PCDB cdb; 06738 PIRP irp; 06739 PSCSI_REQUEST_BLOCK srb; 06740 PREAD_CAPACITY_DATA capacityBuffer; 06741 PIO_STACK_LOCATION irpStack; 06742 PUCHAR senseBuffer; 06743 06744 irp = IoAllocateIrp((CCHAR)(DeviceExtension->DeviceObject->StackSize+1), 06745 FALSE); 06746 06747 if (irp) { 06748 06749 srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK)); 06750 if (srb) { 06751 capacityBuffer = ExAllocatePool(NonPagedPoolCacheAligned, 06752 sizeof(READ_CAPACITY_DATA)); 06753 06754 if (capacityBuffer) { 06755 06756 06757 senseBuffer = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE); 06758 06759 if (senseBuffer) { 06760 06761 irp->MdlAddress = IoAllocateMdl(capacityBuffer, 06762 sizeof(READ_CAPACITY_DATA), 06763 FALSE, 06764 FALSE, 06765 (PIRP) NULL); 06766 06767 if (irp->MdlAddress) { 06768 06769 // 06770 // Have all resources. Set up the IRP to send for the capacity. 06771 // 06772 06773 IoSetNextIrpStackLocation(irp); 06774 irp->IoStatus.Status = STATUS_SUCCESS; 06775 irp->IoStatus.Information = 0; 06776 irp->Flags = 0; 06777 irp->UserBuffer = NULL; 06778 06779 // 06780 // Save the device object and retry count in a private stack location. 06781 // 06782 06783 irpStack = IoGetCurrentIrpStackLocation(irp); 06784 irpStack->DeviceObject = DeviceExtension->DeviceObject; 06785 irpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES; 06786 irpStack->Parameters.Others.Argument2 = (PVOID) IrpToComplete; 06787 06788 // 06789 // Construct the IRP stack for the lower level driver. 06790 // 06791 06792 irpStack = IoGetNextIrpStackLocation(irp); 06793 irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; 06794 irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN; 06795 irpStack->Parameters.Scsi.Srb = srb; 06796 IoSetCompletionRoutine(irp, 06797 CdRomUpdateGeometryCompletion, 06798 srb, 06799 TRUE, 06800 TRUE, 06801 TRUE); 06802 // 06803 // Prepare the MDL 06804 // 06805 06806 MmBuildMdlForNonPagedPool(irp->MdlAddress); 06807 06808 06809 // 06810 // Set up the SRB for read capacity. 06811 // 06812 06813 RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK)); 06814 RtlZeroMemory(senseBuffer, SENSE_BUFFER_SIZE); 06815 srb->CdbLength = 10; 06816 srb->TimeOutValue = DeviceExtension->TimeOutValue; 06817 srb->SrbStatus = srb->ScsiStatus = 0; 06818 srb->NextSrb = 0; 06819 srb->Length = SCSI_REQUEST_BLOCK_SIZE; 06820 srb->PathId = DeviceExtension->PathId; 06821 srb->TargetId = DeviceExtension->TargetId; 06822 srb->Lun = DeviceExtension->Lun; 06823 srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 06824 srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER; 06825 srb->DataBuffer = capacityBuffer; 06826 srb->DataTransferLength = sizeof(READ_CAPACITY_DATA); 06827 srb->OriginalRequest = irp; 06828 srb->SenseInfoBuffer = senseBuffer; 06829 srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE; 06830 06831 // 06832 // Set up the CDB 06833 // 06834 06835 cdb = (PCDB) &srb->Cdb[0]; 06836 cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY; 06837 cdb->CDB10.LogicalUnitNumber = DeviceExtension->Lun; 06838 06839 // 06840 // Set the return value in the IRP that will be completed 06841 // upon completion of the read capacity. 06842 // 06843 06844 IrpToComplete->IoStatus.Status = STATUS_VERIFY_REQUIRED; 06845 IoMarkIrpPending(IrpToComplete); 06846 06847 IoCallDriver(DeviceExtension->PortDeviceObject, irp); 06848 06849 // 06850 // status is not checked because the completion routine for this 06851 // IRP will always get called and it will free the resources. 06852 // 06853 06854 return STATUS_PENDING; 06855 06856 } else { 06857 ExFreePool(senseBuffer); 06858 ExFreePool(capacityBuffer); 06859 ExFreePool(srb); 06860 IoFreeIrp(irp); 06861 } 06862 } else { 06863 ExFreePool(capacityBuffer); 06864 ExFreePool(srb); 06865 IoFreeIrp(irp); 06866 } 06867 } else { 06868 ExFreePool(srb); 06869 IoFreeIrp(irp); 06870 } 06871 } else { 06872 IoFreeIrp(irp); 06873 } 06874 } 06875 06876 return STATUS_INSUFFICIENT_RESOURCES; 06877 } 06878 06879 NTSTATUS 06880 NTAPI 06881 CdRomClassIoctlCompletion( 06882 IN PDEVICE_OBJECT DeviceObject, 06883 IN PIRP Irp, 06884 IN PVOID Context 06885 ) 06886 06887 /*++ 06888 06889 Routine Description: 06890 06891 This routine signals the event used by CdRomDeviceControl to synchronize 06892 class driver (and lower level driver) ioctls with cdrom's startio routine. 06893 The irp completion is short-circuited so that CdRomDeviceControl can 06894 reissue it once it wakes up. 06895 06896 Arguments: 06897 06898 DeviceObject - the device object 06899 Irp - the request we are synchronizing 06900 Context - a PKEVENT that we need to signal 06901 06902 Return Value: 06903 06904 NTSTATUS 06905 06906 --*/ 06907 06908 { 06909 PKEVENT syncEvent = (PKEVENT) Context; 06910 06911 DebugPrint((2, "CdRomClassIoctlCompletion: setting event for irp %#08lx\n", 06912 Irp 06913 )); 06914 06915 KeSetEvent(syncEvent, IO_DISK_INCREMENT, FALSE); 06916 06917 return STATUS_MORE_PROCESSING_REQUIRED; 06918 } Generated on Thu May 24 2012 04:28:45 for ReactOS by
1.7.6.1
|