3 * Copyright (C) 2001, 2002 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 /* $Id: cdrom.c,v 1.25 2003/11/10 18:09:54 ekohl Exp $
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * FILE: services/storage/cdrom/cdrom.c
24 * PURPOSE: cdrom class driver
25 * PROGRAMMER: Eric Kohl (ekohl@rz-online.de)
30 * - Add io timer routine for autorun support.
31 * - Add cdaudio support (cd player).
34 /* INCLUDES *****************************************************************/
36 #include <ddk/ntddk.h>
38 #include <ddk/class2.h>
39 #include <ddk/ntddscsi.h>
44 #define VERSION "0.0.1"
47 #define SCSI_CDROM_TIMEOUT 10 /* Default timeout: 10 seconds */
50 typedef struct _ERROR_RECOVERY_DATA6
52 MODE_PARAMETER_HEADER Header
;
53 MODE_PARAMETER_BLOCK BlockDescriptor
;
54 MODE_READ_RECOVERY_PAGE ReadRecoveryPage
;
55 } ERROR_RECOVERY_DATA6
, *PERROR_RECOVERY_DATA6
;
58 typedef struct _ERROR_RECOVERY_DATA10
60 MODE_PARAMETER_HEADER10 Header
;
61 MODE_PARAMETER_BLOCK BlockDescriptor
;
62 MODE_READ_RECOVERY_PAGE ReadRecoveryPage
;
63 } ERROR_RECOVERY_DATA10
, *PERROR_RECOVERY_DATA10
;
66 typedef struct _CDROM_DATA
74 ERROR_RECOVERY_DATA6 Data6
;
75 ERROR_RECOVERY_DATA10 Data10
;
78 } CDROM_DATA
, *PCDROM_DATA
;
80 /* CDROM_DATA.XaFlags */
81 #define XA_USE_6_BYTE 0x0001
82 #define XA_USE_10_BYTE 0x0002
83 #define XA_USE_READ_CD 0x0004
84 #define XA_NOT_SUPPORTED 0x0008
88 CdromClassFindDevices(IN PDRIVER_OBJECT DriverObject
,
89 IN PUNICODE_STRING RegistryPath
,
90 IN PCLASS_INIT_DATA InitializationData
,
91 IN PDEVICE_OBJECT PortDeviceObject
,
95 CdromClassCheckDevice(IN PINQUIRYDATA InquiryData
);
98 CdromClassCheckReadWrite(IN PDEVICE_OBJECT DeviceObject
,
102 CdromClassCreateMediaChangeEvent(IN PDEVICE_EXTENSION DeviceExtension
,
103 IN ULONG DeviceNumber
);
106 CdromClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject
,
107 IN PUNICODE_STRING RegistryPath
,
108 IN PDEVICE_OBJECT PortDeviceObject
,
110 IN ULONG DeviceNumber
,
111 IN PIO_SCSI_CAPABILITIES Capabilities
,
112 IN PSCSI_INQUIRY_DATA InquiryData
,
113 IN PCLASS_INIT_DATA InitializationData
);
117 CdromClassDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
121 CdromClassStartIo (IN PDEVICE_OBJECT DeviceObject
,
125 CdromDeviceControlCompletion (IN PDEVICE_OBJECT DeviceObject
,
130 CdromTimerRoutine(IN PDEVICE_OBJECT DeviceObject
,
134 /* FUNCTIONS ****************************************************************/
136 /**********************************************************************
141 * This function initializes the driver, locates and claims
142 * hardware resources, and creates various NT objects needed
143 * to process I/O requests.
150 * System allocated Driver Object for this driver
152 * Name of registry driver service key
159 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
160 IN PUNICODE_STRING RegistryPath
)
162 CLASS_INIT_DATA InitData
;
164 DPRINT("CD-ROM Class Driver %s\n",
166 DPRINT("RegistryPath '%wZ'\n",
169 InitData
.InitializationDataSize
= sizeof(CLASS_INIT_DATA
);
170 InitData
.DeviceExtensionSize
= sizeof(DEVICE_EXTENSION
) + sizeof(CDROM_DATA
);
171 InitData
.DeviceType
= FILE_DEVICE_CD_ROM
;
172 InitData
.DeviceCharacteristics
= FILE_REMOVABLE_MEDIA
| FILE_READ_ONLY_DEVICE
;
174 InitData
.ClassError
= NULL
;
175 InitData
.ClassReadWriteVerification
= CdromClassCheckReadWrite
;
176 InitData
.ClassFindDeviceCallBack
= CdromClassCheckDevice
;
177 InitData
.ClassFindDevices
= CdromClassFindDevices
;
178 InitData
.ClassDeviceControl
= CdromClassDeviceControl
;
179 InitData
.ClassShutdownFlush
= NULL
;
180 InitData
.ClassCreateClose
= NULL
;
181 InitData
.ClassStartIo
= CdromClassStartIo
;
183 return(ScsiClassInitialize(DriverObject
,
189 /**********************************************************************
191 * CdromClassFindDevices
194 * This function searches for device that are attached to the
202 * System allocated Driver Object for this driver
204 * Name of registry driver service key.
206 * Pointer to the main initialization data
208 * Scsi port device object
213 * TRUE: At least one disk drive was found
214 * FALSE: No disk drive found
218 CdromClassFindDevices(IN PDRIVER_OBJECT DriverObject
,
219 IN PUNICODE_STRING RegistryPath
,
220 IN PCLASS_INIT_DATA InitializationData
,
221 IN PDEVICE_OBJECT PortDeviceObject
,
224 PCONFIGURATION_INFORMATION ConfigInfo
;
225 PIO_SCSI_CAPABILITIES PortCapabilities
;
226 PSCSI_ADAPTER_BUS_INFO AdapterBusInfo
;
227 PSCSI_INQUIRY_DATA UnitInfo
;
228 PINQUIRYDATA InquiryData
;
235 DPRINT("CdromClassFindDevices() called.\n");
237 /* Get port capabilities */
238 Status
= ScsiClassGetCapabilities(PortDeviceObject
,
240 if (!NT_SUCCESS(Status
))
242 DPRINT1("ScsiClassGetCapabilities() failed! (Status 0x%lX)\n", Status
);
246 DPRINT("PortCapabilities: %p\n", PortCapabilities
);
247 DPRINT("MaximumTransferLength: %lu\n", PortCapabilities
->MaximumTransferLength
);
248 DPRINT("MaximumPhysicalPages: %lu\n", PortCapabilities
->MaximumPhysicalPages
);
250 /* Get inquiry data */
251 Status
= ScsiClassGetInquiryData(PortDeviceObject
,
252 (PSCSI_ADAPTER_BUS_INFO
*)&Buffer
);
253 if (!NT_SUCCESS(Status
))
255 DPRINT1("ScsiClassGetInquiryData() failed! (Status 0x%lX)\n", Status
);
259 /* Check whether there are unclaimed devices */
260 AdapterBusInfo
= (PSCSI_ADAPTER_BUS_INFO
)Buffer
;
261 DeviceCount
= ScsiClassFindUnclaimedDevices(InitializationData
,
263 if (DeviceCount
== 0)
265 DPRINT("No unclaimed devices!\n");
269 DPRINT("Found %lu unclaimed devices!\n", DeviceCount
);
271 ConfigInfo
= IoGetConfigurationInformation();
272 DPRINT("Number of SCSI ports: %lu\n", ConfigInfo
->ScsiPortCount
);
274 /* Search each bus of this adapter */
275 for (Bus
= 0; Bus
< (ULONG
)AdapterBusInfo
->NumberOfBuses
; Bus
++)
277 DPRINT("Searching bus %lu\n", Bus
);
279 UnitInfo
= (PSCSI_INQUIRY_DATA
)(Buffer
+ AdapterBusInfo
->BusData
[Bus
].InquiryDataOffset
);
281 while (AdapterBusInfo
->BusData
[Bus
].InquiryDataOffset
)
283 InquiryData
= (PINQUIRYDATA
)UnitInfo
->InquiryData
;
285 if ((InquiryData
->DeviceType
== READ_ONLY_DIRECT_ACCESS_DEVICE
) &&
286 (InquiryData
->DeviceTypeQualifier
== 0) &&
287 (UnitInfo
->DeviceClaimed
== FALSE
))
289 DPRINT("Vendor: '%.24s'\n",
290 InquiryData
->VendorId
);
292 /* Create device objects for disk */
293 Status
= CdromClassCreateDeviceObject(DriverObject
,
297 ConfigInfo
->CdRomCount
,
301 if (NT_SUCCESS(Status
))
303 ConfigInfo
->CdRomCount
++;
308 if (UnitInfo
->NextInquiryDataOffset
== 0)
311 UnitInfo
= (PSCSI_INQUIRY_DATA
)(Buffer
+ UnitInfo
->NextInquiryDataOffset
);
317 DPRINT("CdromClassFindDevices() done\n");
323 /**********************************************************************
325 * CdromClassCheckDevice
328 * This function checks the InquiryData for the correct device
329 * type and qualifier.
336 * Pointer to the inquiry data for the device in question.
339 * TRUE: A disk device was found.
344 CdromClassCheckDevice(IN PINQUIRYDATA InquiryData
)
346 return((InquiryData
->DeviceType
== READ_ONLY_DIRECT_ACCESS_DEVICE
) &&
347 (InquiryData
->DeviceTypeQualifier
== 0));
351 /**********************************************************************
353 * CdromClassCheckReadWrite
356 * This function checks the given IRP for correct data.
363 * Pointer to the device.
368 * STATUS_SUCCESS: The IRP matches the requirements of the given device.
373 CdromClassCheckReadWrite(IN PDEVICE_OBJECT DeviceObject
,
376 DPRINT("CdromClassCheckReadWrite() called\n");
378 return(STATUS_SUCCESS
);
383 CdromClassCreateMediaChangeEvent(IN PDEVICE_EXTENSION DeviceExtension
,
384 IN ULONG DeviceNumber
)
386 WCHAR NameBuffer
[MAX_PATH
];
389 swprintf (NameBuffer
,
390 L
"\\Device\\MediaChangeEvent%lu",
392 RtlInitUnicodeString (&Name
,
395 DeviceExtension
->MediaChangeEvent
=
396 IoCreateSynchronizationEvent (&Name
,
397 &DeviceExtension
->MediaChangeEventHandle
);
399 KeClearEvent (DeviceExtension
->MediaChangeEvent
);
403 /**********************************************************************
405 * CdromClassCreateDeviceObject
408 * Create the raw device and any partition devices on this drive
415 * System allocated Driver Object for this driver.
417 * Name of registry driver service key.
430 CdromClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject
,
431 IN PUNICODE_STRING RegistryPath
,
432 IN PDEVICE_OBJECT PortDeviceObject
,
434 IN ULONG DeviceNumber
,
435 IN PIO_SCSI_CAPABILITIES Capabilities
,
436 IN PSCSI_INQUIRY_DATA InquiryData
,
437 IN PCLASS_INIT_DATA InitializationData
)
439 PDEVICE_EXTENSION DiskDeviceExtension
; /* defined in class2.h */
440 OBJECT_ATTRIBUTES ObjectAttributes
;
441 UNICODE_STRING UnicodeDeviceDirName
;
442 PDEVICE_OBJECT DiskDeviceObject
;
443 SCSI_REQUEST_BLOCK Srb
;
444 PCDROM_DATA CdromData
;
452 DPRINT("CdromClassCreateDeviceObject() called\n");
454 /* Claim the cdrom device */
455 Status
= ScsiClassClaimDevice(PortDeviceObject
,
459 if (!NT_SUCCESS(Status
))
461 DbgPrint("Could not claim cdrom device\n");
465 /* Create cdrom device */
467 "\\Device\\CdRom%lu",
470 Status
= ScsiClassCreateDeviceObject(DriverObject
,
475 if (!NT_SUCCESS(Status
))
477 DPRINT1("ScsiClassCreateDeviceObject() failed (Status %x)\n", Status
);
479 /* Release (unclaim) the disk */
480 ScsiClassClaimDevice(PortDeviceObject
,
488 DiskDeviceObject
->Flags
|= DO_DIRECT_IO
;
489 DiskDeviceObject
->Characteristics
|= FILE_REMOVABLE_MEDIA
;
490 DiskDeviceObject
->StackSize
= (CCHAR
)PortDeviceObject
->StackSize
+ 1;
492 if (PortDeviceObject
->AlignmentRequirement
> DiskDeviceObject
->AlignmentRequirement
)
494 DiskDeviceObject
->AlignmentRequirement
= PortDeviceObject
->AlignmentRequirement
;
497 DiskDeviceExtension
= DiskDeviceObject
->DeviceExtension
;
498 DiskDeviceExtension
->LockCount
= 0;
499 DiskDeviceExtension
->DeviceNumber
= DeviceNumber
;
500 DiskDeviceExtension
->DeviceObject
= DiskDeviceObject
;
501 DiskDeviceExtension
->PortDeviceObject
= PortDeviceObject
;
502 DiskDeviceExtension
->PhysicalDevice
= DiskDeviceObject
;
503 DiskDeviceExtension
->PortCapabilities
= Capabilities
;
504 DiskDeviceExtension
->StartingOffset
.QuadPart
= 0;
505 DiskDeviceExtension
->PortNumber
= (UCHAR
)PortNumber
;
506 DiskDeviceExtension
->PathId
= InquiryData
->PathId
;
507 DiskDeviceExtension
->TargetId
= InquiryData
->TargetId
;
508 DiskDeviceExtension
->Lun
= InquiryData
->Lun
;
510 /* zero-out disk data */
511 CdromData
= (PCDROM_DATA
)(DiskDeviceExtension
+ 1);
512 RtlZeroMemory(CdromData
,
515 DiskDeviceExtension
->SenseData
= ExAllocatePool(NonPagedPool
,
517 if (DiskDeviceExtension
->SenseData
== NULL
)
519 DPRINT1("Failed to allocate sense data buffer!\n");
521 IoDeleteDevice(DiskDeviceObject
);
523 /* Release (unclaim) the disk */
524 ScsiClassClaimDevice(PortDeviceObject
,
529 return(STATUS_INSUFFICIENT_RESOURCES
);
532 /* Get timeout value */
533 DiskDeviceExtension
->TimeOutValue
=
534 ScsiClassQueryTimeOutRegistryValue(RegistryPath
);
535 if (DiskDeviceExtension
->TimeOutValue
== 0)
536 DiskDeviceExtension
->TimeOutValue
= SCSI_CDROM_TIMEOUT
;
538 /* Initialize lookaside list for SRBs */
539 ScsiClassInitializeSrbLookasideList(DiskDeviceExtension
,
542 /* Get disk geometry */
543 DiskDeviceExtension
->DiskGeometry
= ExAllocatePool(NonPagedPool
,
544 sizeof(DISK_GEOMETRY
));
545 if (DiskDeviceExtension
->DiskGeometry
== NULL
)
547 DPRINT1("Failed to allocate geometry buffer!\n");
549 ExDeleteNPagedLookasideList(&DiskDeviceExtension
->SrbLookasideListHead
);
551 IoDeleteDevice(DiskDeviceObject
);
553 /* Release (unclaim) the disk */
554 ScsiClassClaimDevice(PortDeviceObject
,
559 return(STATUS_INSUFFICIENT_RESOURCES
);
562 /* Read the drive's capacity */
563 Status
= ScsiClassReadDriveCapacity(DiskDeviceObject
);
564 if (!NT_SUCCESS(Status
) ||
565 DiskDeviceExtension
->DiskGeometry
->BytesPerSector
== 0)
567 /* Set ISO9660 defaults */
568 DiskDeviceExtension
->DiskGeometry
->BytesPerSector
= 2048;
569 DiskDeviceExtension
->DiskGeometry
->MediaType
= RemovableMedia
;
570 DiskDeviceExtension
->SectorShift
= 11;
571 DiskDeviceExtension
->PartitionLength
.QuadPart
= (ULONGLONG
)0x7fffffff;
575 /* Make sure the BytesPerSector value is a power of 2 */
576 // DiskDeviceExtension->DiskGeometry->BytesPerSector = 2048;
579 DPRINT("SectorSize: %lu\n", DiskDeviceExtension
->DiskGeometry
->BytesPerSector
);
581 /* Initialize media change support */
582 CdromClassCreateMediaChangeEvent (DiskDeviceExtension
,
584 if (DiskDeviceExtension
->MediaChangeEvent
!= NULL
)
586 DPRINT("Allocated media change event!\n");
588 /* FIXME: Allocate media change IRP and SRB */
591 /* Use 6 byte xa commands by default */
592 CdromData
->XaFlags
|= XA_USE_6_BYTE
;
594 /* Read 'error recovery page' to get additional drive capabilities */
596 Length
= sizeof(MODE_READ_RECOVERY_PAGE
) +
597 MODE_BLOCK_DESC_LENGTH
+
601 sizeof(SCSI_REQUEST_BLOCK
));
603 Srb
.TimeOutValue
= DiskDeviceExtension
->TimeOutValue
;
606 Cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
607 Cdb
->MODE_SENSE
.PageCode
= 0x01;
608 Cdb
->MODE_SENSE
.AllocationLength
= (UCHAR
)Length
;
610 Buffer
= ExAllocatePool (NonPagedPool
,
611 sizeof(MODE_READ_RECOVERY_PAGE
) +
612 MODE_BLOCK_DESC_LENGTH
+ MODE_HEADER_LENGTH10
);
615 DPRINT1("Allocating recovery page buffer failed!\n");
616 return STATUS_INSUFFICIENT_RESOURCES
;
619 Status
= ScsiClassSendSrbSynchronous (DiskDeviceObject
,
624 if (!NT_SUCCESS (Status
))
626 DPRINT("MODE_SENSE(6) failed\n");
628 /* Try the 10 byte version */
629 Length
= sizeof(MODE_READ_RECOVERY_PAGE
) +
630 MODE_BLOCK_DESC_LENGTH
+
631 MODE_HEADER_LENGTH10
;
634 sizeof(SCSI_REQUEST_BLOCK
));
636 Srb
.TimeOutValue
= DiskDeviceExtension
->TimeOutValue
;
639 Cdb
->MODE_SENSE10
.OperationCode
= SCSIOP_MODE_SENSE10
;
640 Cdb
->MODE_SENSE10
.PageCode
= 0x01;
641 Cdb
->MODE_SENSE10
.AllocationLength
[0] = (UCHAR
)(Length
>> 8);
642 Cdb
->MODE_SENSE10
.AllocationLength
[1] = (UCHAR
)(Length
&& 0xFF);
644 Status
= ScsiClassSendSrbSynchronous (DiskDeviceObject
,
649 if (Status
== STATUS_DATA_OVERRUN
)
651 DPRINT1("Data overrun\n");
655 else if (NT_SUCCESS (Status
))
657 DPRINT("Use 10 byte commands\n");
658 RtlCopyMemory (&CdromData
->RecoveryData
.Data10
.Header
,
660 sizeof (ERROR_RECOVERY_DATA10
));
661 CdromData
->RecoveryData
.Data10
.Header
.ModeDataLength
[0] = 0;
662 CdromData
->RecoveryData
.Data10
.Header
.ModeDataLength
[1] = 0;
664 CdromData
->XaFlags
&= XA_USE_6_BYTE
;
665 CdromData
->XaFlags
|= XA_USE_10_BYTE
;
669 DPRINT("XA not supported\n");
670 CdromData
->XaFlags
|= XA_NOT_SUPPORTED
;
675 DPRINT("Use 6 byte commands\n");
676 RtlCopyMemory (&CdromData
->RecoveryData
.Data6
.Header
,
678 sizeof (ERROR_RECOVERY_DATA6
));
679 CdromData
->RecoveryData
.Data6
.Header
.ModeDataLength
= 0;
684 /* Initialize device timer */
685 IoInitializeTimer(DiskDeviceObject
,
688 IoStartTimer(DiskDeviceObject
);
690 DPRINT("CdromClassCreateDeviceObjects() done\n");
692 return(STATUS_SUCCESS
);
696 /**********************************************************************
698 * CdromClassReadTocEntry
710 CdromClassReadTocEntry (PDEVICE_OBJECT DeviceObject
,
715 PDEVICE_EXTENSION DeviceExtension
;
716 SCSI_REQUEST_BLOCK Srb
;
719 DeviceExtension
= (PDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
721 RtlZeroMemory(&Srb
, sizeof(SCSI_REQUEST_BLOCK
));
723 Srb
.TimeOutValue
= DeviceExtension
->TimeOutValue
;
726 Cdb
->READ_TOC
.OperationCode
= SCSIOP_READ_TOC
;
727 Cdb
->READ_TOC
.StartingTrack
= TrackNo
;
728 Cdb
->READ_TOC
.Format
= 0;
729 Cdb
->READ_TOC
.AllocationLength
[0] = Length
>> 8;
730 Cdb
->READ_TOC
.AllocationLength
[1] = Length
& 0xff;
731 Cdb
->READ_TOC
.Msf
= 1;
733 return(ScsiClassSendSrbSynchronous(DeviceObject
,
742 CdromClassReadLastSession (PDEVICE_OBJECT DeviceObject
,
747 PDEVICE_EXTENSION DeviceExtension
;
748 SCSI_REQUEST_BLOCK Srb
;
751 DeviceExtension
= (PDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
753 RtlZeroMemory(&Srb
, sizeof(SCSI_REQUEST_BLOCK
));
755 Srb
.TimeOutValue
= DeviceExtension
->TimeOutValue
;
758 Cdb
->READ_TOC
.OperationCode
= SCSIOP_READ_TOC
;
759 Cdb
->READ_TOC
.StartingTrack
= TrackNo
;
760 Cdb
->READ_TOC
.Format
= 1;
761 Cdb
->READ_TOC
.AllocationLength
[0] = Length
>> 8;
762 Cdb
->READ_TOC
.AllocationLength
[1] = Length
& 0xff;
763 Cdb
->READ_TOC
.Msf
= 0;
765 return(ScsiClassSendSrbSynchronous(DeviceObject
,
773 /**********************************************************************
775 * CdromClassDeviceControl
778 * Answer requests for device control calls
786 * Standard dispatch arguments
793 CdromClassDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
796 PDEVICE_EXTENSION DeviceExtension
;
797 PIO_STACK_LOCATION IrpStack
;
798 ULONG ControlCode
, InputLength
, OutputLength
;
799 PCDROM_DATA CdromData
;
803 DPRINT("CdromClassDeviceControl() called!\n");
805 Status
= STATUS_INVALID_DEVICE_REQUEST
;
807 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
808 ControlCode
= IrpStack
->Parameters
.DeviceIoControl
.IoControlCode
;
809 InputLength
= IrpStack
->Parameters
.DeviceIoControl
.InputBufferLength
;
810 OutputLength
= IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
811 DeviceExtension
= (PDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
812 CdromData
= (PCDROM_DATA
)(DeviceExtension
+ 1);
816 case IOCTL_CDROM_GET_DRIVE_GEOMETRY
:
817 DPRINT ("CdromClassDeviceControl: IOCTL_CDROM_GET_DRIVE_GEOMETRY\n");
818 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(DISK_GEOMETRY
))
820 Status
= STATUS_INFO_LENGTH_MISMATCH
;
823 IoMarkIrpPending (Irp
);
824 IoStartPacket (DeviceObject
,
828 return STATUS_PENDING
;
830 case IOCTL_CDROM_CHECK_VERIFY
:
831 DPRINT ("CdromClassDeviceControl: IOCTL_CDROM_CHECK_VERIFY\n");
832 if (OutputLength
!= 0 && OutputLength
< sizeof (ULONG
))
834 DPRINT1("Buffer too small\n");
835 Status
= STATUS_BUFFER_TOO_SMALL
;
838 IoMarkIrpPending (Irp
);
839 IoStartPacket (DeviceObject
,
843 return STATUS_PENDING
;
845 case IOCTL_CDROM_READ_TOC
:
846 DPRINT("IOCTL_CDROM_READ_TOC\n");
847 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(CDROM_TOC
))
849 Status
= STATUS_INFO_LENGTH_MISMATCH
;
853 PCDROM_TOC TocBuffer
;
856 TocBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
858 /* First read the lead out */
859 Length
= 4 + sizeof(TRACK_DATA
);
860 Status
= CdromClassReadTocEntry(DeviceObject
,
864 if (NT_SUCCESS(Status
))
866 if (TocBuffer
->FirstTrack
== 0xaa)
868 /* there is an empty cd */
869 Information
= Length
;
874 Length
= 4 + sizeof(TRACK_DATA
) * (TocBuffer
->LastTrack
- TocBuffer
->FirstTrack
+ 2);
875 Status
= CdromClassReadTocEntry(DeviceObject
,
876 TocBuffer
->FirstTrack
,
878 if (NT_SUCCESS(Status
))
880 Information
= Length
;
887 case IOCTL_CDROM_GET_LAST_SESSION
:
888 DPRINT("IOCTL_CDROM_GET_LAST_SESSION\n");
889 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< 4 + sizeof(TRACK_DATA
))
891 Status
= STATUS_INFO_LENGTH_MISMATCH
;
895 PCDROM_TOC TocBuffer
;
898 TocBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
899 Length
= 4 + sizeof(TRACK_DATA
);
900 Status
= CdromClassReadLastSession(DeviceObject
,
904 if (NT_SUCCESS(Status
))
906 Information
= Length
;
912 /* Call the common device control function */
913 return(ScsiClassDeviceControl(DeviceObject
, Irp
));
916 /* Verify the device if the user caused the error */
917 if (!NT_SUCCESS(Status
) && IoIsErrorUserInduced(Status
))
919 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
922 Irp
->IoStatus
.Status
= Status
;
923 Irp
->IoStatus
.Information
= Information
;
924 IoCompleteRequest(Irp
,
931 /**********************************************************************
936 * Starts IRP processing.
944 * Standard dispatch arguments
950 CdromClassStartIo (IN PDEVICE_OBJECT DeviceObject
,
953 PDEVICE_EXTENSION DeviceExtension
;
954 PIO_STACK_LOCATION IrpStack
;
955 PIO_STACK_LOCATION SubIrpStack
;
956 ULONG MaximumTransferLength
;
958 PSCSI_REQUEST_BLOCK Srb
;
964 DPRINT("CdromClassStartIo() called!\n");
966 IoMarkIrpPending (Irp
);
968 DeviceExtension
= (PDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
969 IrpStack
= IoGetCurrentIrpStackLocation (Irp
);
971 MaximumTransferLength
= DeviceExtension
->PortCapabilities
->MaximumTransferLength
;
973 if (DeviceObject
->Flags
& DO_VERIFY_VOLUME
)
975 if (!(IrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
))
977 DPRINT1 ("Verify required\n");
979 if (Irp
->Tail
.Overlay
.Thread
)
981 IoSetHardErrorOrVerifyDevice (Irp
,
984 Irp
->IoStatus
.Status
= STATUS_VERIFY_REQUIRED
;
986 /* FIXME: Update drive capacity */
992 if (IrpStack
->MajorFunction
== IRP_MJ_READ
)
994 DPRINT ("CdromClassStartIo: IRP_MJ_READ\n");
997 ADDRESS_AND_SIZE_TO_SPAN_PAGES (MmGetMdlVirtualAddress(Irp
->MdlAddress
),
998 IrpStack
->Parameters
.Read
.Length
);
1000 /* Check transfer size */
1001 if ((IrpStack
->Parameters
.Read
.Length
> MaximumTransferLength
) ||
1002 (TransferPages
> DeviceExtension
->PortCapabilities
->MaximumPhysicalPages
))
1004 /* Transfer size is too large - split it */
1006 DeviceExtension
->PortCapabilities
->MaximumPhysicalPages
- 1;
1008 /* Adjust transfer size */
1009 if (MaximumTransferLength
> TransferPages
* PAGE_SIZE
)
1010 MaximumTransferLength
= TransferPages
* PAGE_SIZE
;
1012 if (MaximumTransferLength
== 0)
1013 MaximumTransferLength
= PAGE_SIZE
;
1015 /* Split the transfer */
1016 ScsiClassSplitRequest (DeviceObject
,
1018 MaximumTransferLength
);
1024 ScsiClassBuildRequest (DeviceObject
,
1028 else if (IrpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
)
1030 DPRINT ("CdromClassStartIo: IRP_MJ_IRP_MJ_DEVICE_CONTROL\n");
1032 /* Allocate an IRP for sending requests to the port driver */
1033 SubIrp
= IoAllocateIrp ((CCHAR
)(DeviceObject
->StackSize
+ 1),
1037 Irp
->IoStatus
.Information
= 0;
1038 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1039 IoCompleteRequest (Irp
,
1041 IoStartNextPacket (DeviceObject
,
1046 /* Allocate an SRB */
1047 Srb
= ExAllocatePool (NonPagedPool
,
1048 sizeof (SCSI_REQUEST_BLOCK
));
1052 Irp
->IoStatus
.Information
= 0;
1053 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1054 IoCompleteRequest (Irp
,
1056 IoStartNextPacket (DeviceObject
,
1061 /* Allocte a sense buffer */
1062 SenseBuffer
= ExAllocatePool (NonPagedPoolCacheAligned
,
1064 if (SenseBuffer
== NULL
)
1068 Irp
->IoStatus
.Information
= 0;
1069 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1070 IoCompleteRequest (Irp
,
1072 IoStartNextPacket (DeviceObject
,
1077 /* Initialize the IRP */
1078 IoSetNextIrpStackLocation (SubIrp
);
1079 SubIrp
->IoStatus
.Information
= 0;
1080 SubIrp
->IoStatus
.Status
= STATUS_SUCCESS
;
1082 SubIrp
->UserBuffer
= NULL
;
1084 SubIrpStack
= IoGetCurrentIrpStackLocation (SubIrp
);
1085 SubIrpStack
->DeviceObject
= DeviceExtension
->DeviceObject
;
1086 SubIrpStack
->Parameters
.Others
.Argument2
= (PVOID
)Irp
;
1088 /* Initialize next stack location */
1089 SubIrpStack
= IoGetNextIrpStackLocation (SubIrp
);
1090 SubIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
1091 SubIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
1092 SubIrpStack
->Parameters
.Scsi
.Srb
= Srb
;
1094 /* Initialize the SRB */
1096 sizeof (SCSI_REQUEST_BLOCK
));
1097 Srb
->Length
= sizeof (SCSI_REQUEST_BLOCK
);
1098 Srb
->PathId
= DeviceExtension
->PathId
;
1099 Srb
->TargetId
= DeviceExtension
->TargetId
;
1100 Srb
->Lun
= DeviceExtension
->Lun
;
1101 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1102 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
1103 Srb
->ScsiStatus
= 0;
1105 Srb
->OriginalRequest
= SubIrp
;
1106 Srb
->SenseInfoBuffer
= SenseBuffer
;
1107 Srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
1109 /* Initialize the CDB */
1110 Cdb
= (PCDB
)Srb
->Cdb
;
1112 /* Set the completion routine */
1113 IoSetCompletionRoutine (SubIrp
,
1114 CdromDeviceControlCompletion
,
1120 switch (IrpStack
->Parameters
.DeviceIoControl
.IoControlCode
)
1122 case IOCTL_CDROM_GET_DRIVE_GEOMETRY
:
1123 DPRINT ("CdromClassStartIo: IOCTL_CDROM_GET_DRIVE_GEOMETRY\n");
1124 Srb
->DataTransferLength
= sizeof(READ_CAPACITY_DATA
);
1125 Srb
->CdbLength
= 10;
1126 Srb
->TimeOutValue
= DeviceExtension
->TimeOutValue
;
1127 Srb
->SrbFlags
= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
;
1128 Cdb
->CDB10
.OperationCode
= SCSIOP_READ_CAPACITY
;
1130 /* Allocate data buffer */
1131 DataBuffer
= ExAllocatePool (NonPagedPoolCacheAligned
,
1132 sizeof(READ_CAPACITY_DATA
));
1133 if (DataBuffer
== NULL
)
1135 Irp
->IoStatus
.Information
= 0;
1136 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1137 IoCompleteRequest (Irp
,
1139 ExFreePool (SenseBuffer
);
1142 IoStartNextPacket (DeviceObject
,
1147 /* Allocate an MDL for the data buffer */
1148 SubIrp
->MdlAddress
= IoAllocateMdl (DataBuffer
,
1149 sizeof(READ_CAPACITY_DATA
),
1153 if (SubIrp
->MdlAddress
== NULL
)
1155 Irp
->IoStatus
.Information
= 0;
1156 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1157 IoCompleteRequest (Irp
,
1159 ExFreePool (DataBuffer
);
1160 ExFreePool (SenseBuffer
);
1163 IoStartNextPacket (DeviceObject
,
1168 MmBuildMdlForNonPagedPool (SubIrp
->MdlAddress
);
1169 Srb
->DataBuffer
= DataBuffer
;
1171 IoCallDriver (DeviceExtension
->PortDeviceObject
,
1175 case IOCTL_CDROM_CHECK_VERIFY
:
1176 DPRINT ("CdromClassStartIo: IOCTL_CDROM_CHECK_VERIFY\n");
1178 Srb
->TimeOutValue
= DeviceExtension
->TimeOutValue
* 2;
1179 Srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
;
1180 Cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_TEST_UNIT_READY
;
1182 IoCallDriver (DeviceExtension
->PortDeviceObject
,
1187 IoCompleteRequest (Irp
,
1193 /* Call the SCSI port driver */
1194 IoCallDriver (DeviceExtension
->PortDeviceObject
,
1200 CdromDeviceControlCompletion (IN PDEVICE_OBJECT DeviceObject
,
1204 PDEVICE_EXTENSION DeviceExtension
;
1205 PDEVICE_EXTENSION PhysicalExtension
;
1206 PIO_STACK_LOCATION IrpStack
;
1207 PIO_STACK_LOCATION OrigCurrentIrpStack
;
1208 PIO_STACK_LOCATION OrigNextIrpStack
;
1209 PSCSI_REQUEST_BLOCK Srb
;
1214 DPRINT ("CdromDeviceControlCompletion() called\n");
1216 DeviceExtension
= (PDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
1217 PhysicalExtension
= (PDEVICE_EXTENSION
)DeviceExtension
->PhysicalDevice
->DeviceExtension
;
1218 Srb
= (PSCSI_REQUEST_BLOCK
) Context
;
1220 IrpStack
= IoGetCurrentIrpStackLocation (Irp
);
1222 /* Get the original IRP */
1223 OrigIrp
= (PIRP
)IrpStack
->Parameters
.Others
.Argument2
;
1224 OrigCurrentIrpStack
= IoGetCurrentIrpStackLocation (OrigIrp
);
1225 OrigNextIrpStack
= IoGetNextIrpStackLocation (OrigIrp
);
1227 if (SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_SUCCESS
)
1229 Status
= STATUS_SUCCESS
;
1233 DPRINT ("SrbStatus %lx\n", Srb
->SrbStatus
);
1235 /* Interpret sense info */
1236 Retry
= ScsiClassInterpretSenseInfo (DeviceObject
,
1238 IrpStack
->MajorFunction
,
1239 IrpStack
->Parameters
.DeviceIoControl
.IoControlCode
,
1240 MAXIMUM_RETRIES
- (ULONG
)OrigNextIrpStack
->Parameters
.Others
.Argument1
,
1242 DPRINT ("Retry %u\n", Retry
);
1244 if (Retry
== TRUE
&&
1245 (ULONG
)OrigNextIrpStack
->Parameters
.Others
.Argument1
> 0)
1247 DPRINT1 ("Try again (Retry count %lu)\n",
1248 (ULONG
)OrigNextIrpStack
->Parameters
.Others
.Argument1
);
1250 (ULONG
)OrigNextIrpStack
->Parameters
.Others
.Argument1
--;
1252 /* Release 'old' buffers */
1253 ExFreePool (Srb
->SenseInfoBuffer
);
1254 if (Srb
->DataBuffer
)
1255 ExFreePool(Srb
->DataBuffer
);
1258 if (Irp
->MdlAddress
!= NULL
)
1259 IoFreeMdl(Irp
->MdlAddress
);
1263 /* Call the StartIo routine again */
1264 CdromClassStartIo (DeviceObject
,
1267 return STATUS_MORE_PROCESSING_REQUIRED
;
1270 DPRINT ("Status %lx\n", Status
);
1273 if (NT_SUCCESS (Status
))
1275 switch (OrigCurrentIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
)
1277 case IOCTL_CDROM_GET_DRIVE_GEOMETRY
:
1279 PREAD_CAPACITY_DATA CapacityBuffer
;
1283 DPRINT ("CdromClassControlCompletion: IOCTL_CDROM_GET_DRIVE_GEOMETRY\n");
1285 CapacityBuffer
= (PREAD_CAPACITY_DATA
)Srb
->DataBuffer
;
1286 SectorSize
= (((PUCHAR
)&CapacityBuffer
->BytesPerBlock
)[0] << 24) |
1287 (((PUCHAR
)&CapacityBuffer
->BytesPerBlock
)[1] << 16) |
1288 (((PUCHAR
)&CapacityBuffer
->BytesPerBlock
)[2] << 8) |
1289 ((PUCHAR
)&CapacityBuffer
->BytesPerBlock
)[3];
1291 LastSector
= (((PUCHAR
)&CapacityBuffer
->LogicalBlockAddress
)[0] << 24) |
1292 (((PUCHAR
)&CapacityBuffer
->LogicalBlockAddress
)[1] << 16) |
1293 (((PUCHAR
)&CapacityBuffer
->LogicalBlockAddress
)[2] << 8) |
1294 ((PUCHAR
)&CapacityBuffer
->LogicalBlockAddress
)[3];
1296 if (SectorSize
== 0)
1298 DeviceExtension
->DiskGeometry
->BytesPerSector
= SectorSize
;
1300 DeviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(LastSector
+ 1);
1301 WHICH_BIT(DeviceExtension
->DiskGeometry
->BytesPerSector
,
1302 DeviceExtension
->SectorShift
);
1303 DeviceExtension
->PartitionLength
.QuadPart
=
1304 (DeviceExtension
->PartitionLength
.QuadPart
<< DeviceExtension
->SectorShift
);
1306 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)
1308 DeviceExtension
->DiskGeometry
->MediaType
= RemovableMedia
;
1312 DeviceExtension
->DiskGeometry
->MediaType
= FixedMedia
;
1314 DeviceExtension
->DiskGeometry
->Cylinders
.QuadPart
=
1315 (LONGLONG
)((LastSector
+ 1)/(32 * 64));
1316 DeviceExtension
->DiskGeometry
->SectorsPerTrack
= 32;
1317 DeviceExtension
->DiskGeometry
->TracksPerCylinder
= 64;
1319 RtlCopyMemory (OrigIrp
->AssociatedIrp
.SystemBuffer
,
1320 DeviceExtension
->DiskGeometry
,
1321 sizeof(DISK_GEOMETRY
));
1322 OrigIrp
->IoStatus
.Information
= sizeof(DISK_GEOMETRY
);
1326 case IOCTL_CDROM_CHECK_VERIFY
:
1327 DPRINT ("CdromDeviceControlCompletion: IOCTL_CDROM_CHECK_VERIFY\n");
1328 if (OrigCurrentIrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
!= 0)
1330 /* Return the media change counter */
1331 *((PULONG
)(OrigIrp
->AssociatedIrp
.SystemBuffer
)) =
1332 PhysicalExtension
->MediaChangeCount
;
1333 OrigIrp
->IoStatus
.Information
= sizeof(ULONG
);
1337 OrigIrp
->IoStatus
.Information
= 0;
1342 OrigIrp
->IoStatus
.Information
= 0;
1343 Status
= STATUS_INVALID_DEVICE_REQUEST
;
1348 /* Release the SRB and associated buffers */
1351 DPRINT("Srb %p\n", Srb
);
1353 if (Srb
->DataBuffer
!= NULL
)
1354 ExFreePool (Srb
->DataBuffer
);
1356 if (Srb
->SenseInfoBuffer
!= NULL
)
1357 ExFreePool (Srb
->SenseInfoBuffer
);
1362 if (OrigIrp
->PendingReturned
)
1364 IoMarkIrpPending (OrigIrp
);
1367 /* Release the MDL */
1368 if (Irp
->MdlAddress
!= NULL
)
1370 IoFreeMdl (Irp
->MdlAddress
);
1373 /* Release the sub irp */
1376 /* Set io status information */
1377 OrigIrp
->IoStatus
.Status
= Status
;
1378 if (!NT_SUCCESS(Status
) && IoIsErrorUserInduced (Status
))
1380 IoSetHardErrorOrVerifyDevice (OrigIrp
,
1382 OrigIrp
->IoStatus
.Information
= 0;
1385 /* Complete the original IRP */
1386 IoCompleteRequest (OrigIrp
,
1388 IoStartNextPacket (DeviceObject
,
1391 DPRINT ("CdromDeviceControlCompletion() done\n");
1393 return STATUS_MORE_PROCESSING_REQUIRED
;
1398 CdromTimerRoutine(PDEVICE_OBJECT DeviceObject
,
1401 DPRINT ("CdromTimerRoutine() called\n");