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.24 2003/11/07 17:14:22 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
711 CdromClassReadTocEntry (PDEVICE_OBJECT DeviceObject
,
716 PDEVICE_EXTENSION DeviceExtension
;
717 SCSI_REQUEST_BLOCK Srb
;
720 DeviceExtension
= (PDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
722 RtlZeroMemory(&Srb
, sizeof(SCSI_REQUEST_BLOCK
));
724 Srb
.TimeOutValue
= DeviceExtension
->TimeOutValue
;
727 Cdb
->READ_TOC
.OperationCode
= SCSIOP_READ_TOC
;
728 Cdb
->READ_TOC
.StartingTrack
= TrackNo
;
729 Cdb
->READ_TOC
.Format
= 0;
730 Cdb
->READ_TOC
.AllocationLength
[0] = Length
>> 8;
731 Cdb
->READ_TOC
.AllocationLength
[1] = Length
& 0xff;
732 Cdb
->READ_TOC
.Msf
= 1;
734 return(ScsiClassSendSrbSynchronous(DeviceObject
,
743 CdromClassReadLastSession (PDEVICE_OBJECT DeviceObject
,
748 PDEVICE_EXTENSION DeviceExtension
;
749 SCSI_REQUEST_BLOCK Srb
;
752 DeviceExtension
= (PDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
754 RtlZeroMemory(&Srb
, sizeof(SCSI_REQUEST_BLOCK
));
756 Srb
.TimeOutValue
= DeviceExtension
->TimeOutValue
;
759 Cdb
->READ_TOC
.OperationCode
= SCSIOP_READ_TOC
;
760 Cdb
->READ_TOC
.StartingTrack
= TrackNo
;
761 Cdb
->READ_TOC
.Format
= 1;
762 Cdb
->READ_TOC
.AllocationLength
[0] = Length
>> 8;
763 Cdb
->READ_TOC
.AllocationLength
[1] = Length
& 0xff;
764 Cdb
->READ_TOC
.Msf
= 0;
766 return(ScsiClassSendSrbSynchronous(DeviceObject
,
774 /**********************************************************************
776 * CdromClassDeviceControl
779 * Answer requests for device control calls
787 * Standard dispatch arguments
794 CdromClassDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
797 PDEVICE_EXTENSION DeviceExtension
;
798 PIO_STACK_LOCATION IrpStack
;
799 ULONG ControlCode
, InputLength
, OutputLength
;
800 PCDROM_DATA CdromData
;
804 DPRINT("CdromClassDeviceControl() called!\n");
806 Status
= STATUS_INVALID_DEVICE_REQUEST
;
808 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
809 ControlCode
= IrpStack
->Parameters
.DeviceIoControl
.IoControlCode
;
810 InputLength
= IrpStack
->Parameters
.DeviceIoControl
.InputBufferLength
;
811 OutputLength
= IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
812 DeviceExtension
= (PDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
813 CdromData
= (PCDROM_DATA
)(DeviceExtension
+ 1);
817 case IOCTL_CDROM_GET_DRIVE_GEOMETRY
:
818 DPRINT("IOCTL_CDROM_GET_DRIVE_GEOMETRY\n");
819 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(DISK_GEOMETRY
))
821 Status
= STATUS_INFO_LENGTH_MISMATCH
;
824 IoMarkIrpPending (Irp
);
825 IoStartPacket (DeviceObject
,
829 return STATUS_PENDING
;
831 case IOCTL_CDROM_CHECK_VERIFY
:
832 DPRINT ("IOCTL_CDROM_CHECK_VERIFY\n");
833 if (OutputLength
!= 0 && OutputLength
< sizeof (ULONG
))
835 DPRINT1("Buffer too small\n");
836 Status
= STATUS_BUFFER_TOO_SMALL
;
839 IoMarkIrpPending (Irp
);
840 IoStartPacket (DeviceObject
,
844 return STATUS_PENDING
;
846 case IOCTL_CDROM_READ_TOC
:
847 DPRINT("IOCTL_CDROM_READ_TOC\n");
848 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(CDROM_TOC
))
850 Status
= STATUS_INFO_LENGTH_MISMATCH
;
854 PCDROM_TOC TocBuffer
;
857 TocBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
859 /* First read the lead out */
860 Length
= 4 + sizeof(TRACK_DATA
);
861 Status
= CdromClassReadTocEntry(DeviceObject
,
865 if (NT_SUCCESS(Status
))
867 if (TocBuffer
->FirstTrack
== 0xaa)
869 /* there is an empty cd */
870 Information
= Length
;
875 Length
= 4 + sizeof(TRACK_DATA
) * (TocBuffer
->LastTrack
- TocBuffer
->FirstTrack
+ 2);
876 Status
= CdromClassReadTocEntry(DeviceObject
,
877 TocBuffer
->FirstTrack
,
879 if (NT_SUCCESS(Status
))
881 Information
= Length
;
888 case IOCTL_CDROM_GET_LAST_SESSION
:
889 DPRINT("IOCTL_CDROM_GET_LAST_SESSION\n");
890 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< 4 + sizeof(TRACK_DATA
))
892 Status
= STATUS_INFO_LENGTH_MISMATCH
;
896 PCDROM_TOC TocBuffer
;
899 TocBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
900 Length
= 4 + sizeof(TRACK_DATA
);
901 Status
= CdromClassReadLastSession(DeviceObject
,
905 if (NT_SUCCESS(Status
))
907 Information
= Length
;
913 /* Call the common device control function */
914 return(ScsiClassDeviceControl(DeviceObject
, Irp
));
917 /* Verify the device if the user caused the error */
918 if (!NT_SUCCESS(Status
) && IoIsErrorUserInduced(Status
))
920 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
923 Irp
->IoStatus
.Status
= Status
;
924 Irp
->IoStatus
.Information
= Information
;
925 IoCompleteRequest(Irp
,
932 /**********************************************************************
937 * Starts IRP processing.
945 * Standard dispatch arguments
951 CdromClassStartIo (IN PDEVICE_OBJECT DeviceObject
,
954 PDEVICE_EXTENSION DeviceExtension
;
955 PIO_STACK_LOCATION IrpStack
;
956 PIO_STACK_LOCATION SubIrpStack
;
957 ULONG MaximumTransferLength
;
959 PSCSI_REQUEST_BLOCK Srb
;
965 DPRINT("CdromClassStartIo() called!\n");
967 DeviceExtension
= (PDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
968 IrpStack
= IoGetCurrentIrpStackLocation (Irp
);
970 MaximumTransferLength
= DeviceExtension
->PortCapabilities
->MaximumTransferLength
;
972 if (IrpStack
->MajorFunction
== IRP_MJ_READ
)
974 DPRINT ("CdromClassStartIo: IRP_MJ_READ\n");
977 ADDRESS_AND_SIZE_TO_SPAN_PAGES (MmGetMdlVirtualAddress(Irp
->MdlAddress
),
978 IrpStack
->Parameters
.Read
.Length
);
980 /* Check transfer size */
981 if ((IrpStack
->Parameters
.Read
.Length
> MaximumTransferLength
) ||
982 (TransferPages
> DeviceExtension
->PortCapabilities
->MaximumPhysicalPages
))
984 /* Transfer size is too large - split it */
986 DeviceExtension
->PortCapabilities
->MaximumPhysicalPages
- 1;
988 /* Adjust transfer size */
989 if (MaximumTransferLength
> TransferPages
* PAGE_SIZE
)
990 MaximumTransferLength
= TransferPages
* PAGE_SIZE
;
992 if (MaximumTransferLength
== 0)
993 MaximumTransferLength
= PAGE_SIZE
;
995 /* Split the transfer */
996 ScsiClassSplitRequest (DeviceObject
,
998 MaximumTransferLength
);
1004 ScsiClassBuildRequest (DeviceObject
,
1008 else if (IrpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
)
1010 DPRINT ("CdromClassStartIo: IRP_MJ_IRP_MJ_DEVICE_CONTROL\n");
1012 /* Allocate an IRP for sending requests to the port driver */
1013 SubIrp
= IoAllocateIrp ((CCHAR
)(DeviceObject
->StackSize
+ 1),
1017 Irp
->IoStatus
.Information
= 0;
1018 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1019 IoCompleteRequest (Irp
,
1021 IoStartNextPacket (DeviceObject
,
1026 /* Allocate an SRB */
1027 Srb
= ExAllocatePool (NonPagedPool
,
1028 sizeof (SCSI_REQUEST_BLOCK
));
1032 Irp
->IoStatus
.Information
= 0;
1033 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1034 IoCompleteRequest (Irp
,
1036 IoStartNextPacket (DeviceObject
,
1041 /* Allocte a sense buffer */
1042 SenseBuffer
= ExAllocatePool (NonPagedPoolCacheAligned
,
1044 if (SenseBuffer
== NULL
)
1048 Irp
->IoStatus
.Information
= 0;
1049 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1050 IoCompleteRequest (Irp
,
1052 IoStartNextPacket (DeviceObject
,
1057 /* Initialize the IRP */
1058 IoSetNextIrpStackLocation (SubIrp
);
1059 SubIrp
->IoStatus
.Information
= 0;
1060 SubIrp
->IoStatus
.Status
= STATUS_SUCCESS
;
1062 SubIrp
->UserBuffer
= NULL
;
1064 SubIrpStack
= IoGetCurrentIrpStackLocation (SubIrp
);
1065 SubIrpStack
->DeviceObject
= DeviceExtension
->DeviceObject
;
1066 SubIrpStack
->Parameters
.Others
.Argument2
= (PVOID
)Irp
;
1068 /* Initialize next stack location */
1069 SubIrpStack
= IoGetNextIrpStackLocation (SubIrp
);
1070 SubIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
1071 SubIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
1072 SubIrpStack
->Parameters
.Scsi
.Srb
= Srb
;
1074 /* Initialize the SRB */
1076 sizeof (SCSI_REQUEST_BLOCK
));
1077 Srb
->Length
= sizeof (SCSI_REQUEST_BLOCK
);
1078 Srb
->PathId
= DeviceExtension
->PathId
;
1079 Srb
->TargetId
= DeviceExtension
->TargetId
;
1080 Srb
->Lun
= DeviceExtension
->Lun
;
1081 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1082 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
1083 Srb
->ScsiStatus
= 0;
1085 Srb
->OriginalRequest
= SubIrp
;
1086 Srb
->SenseInfoBuffer
= SenseBuffer
;
1087 Srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
1089 /* Initialize the CDB */
1090 Cdb
= (PCDB
)Srb
->Cdb
;
1092 /* Set the completion routine */
1093 IoSetCompletionRoutine (SubIrp
,
1094 CdromDeviceControlCompletion
,
1100 switch (IrpStack
->Parameters
.DeviceIoControl
.IoControlCode
)
1102 case IOCTL_CDROM_GET_DRIVE_GEOMETRY
:
1103 DPRINT1 ("CdromClassStartIo: IOCTL_CDROM_GET_DRIVE_GEOMETRY\n");
1104 Srb
->DataTransferLength
= sizeof(READ_CAPACITY_DATA
);
1105 Srb
->CdbLength
= 10;
1106 Srb
->TimeOutValue
= DeviceExtension
->TimeOutValue
;
1107 Srb
->SrbFlags
= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
;
1109 /* Allocate data buffer */
1110 DataBuffer
= ExAllocatePool (NonPagedPoolCacheAligned
,
1111 sizeof(READ_CAPACITY_DATA
));
1112 if (DataBuffer
== NULL
)
1114 Irp
->IoStatus
.Information
= 0;
1115 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1116 IoCompleteRequest (Irp
,
1118 ExFreePool (SenseBuffer
);
1121 IoStartNextPacket (DeviceObject
,
1126 /* Allocate an MDL for the data buffer */
1127 SubIrp
->MdlAddress
= IoAllocateMdl (DataBuffer
,
1128 sizeof(READ_CAPACITY_DATA
),
1132 if (SubIrp
->MdlAddress
== NULL
)
1134 Irp
->IoStatus
.Information
= 0;
1135 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1136 IoCompleteRequest (Irp
,
1138 ExFreePool (DataBuffer
);
1139 ExFreePool (SenseBuffer
);
1142 IoStartNextPacket (DeviceObject
,
1147 MmBuildMdlForNonPagedPool (SubIrp
->MdlAddress
);
1148 Srb
->DataBuffer
= DataBuffer
;
1149 Cdb
->CDB10
.OperationCode
= SCSIOP_READ_CAPACITY
;
1151 IoCallDriver (DeviceExtension
->PortDeviceObject
,
1155 case IOCTL_CDROM_CHECK_VERIFY
:
1156 DPRINT ("CdromClassStartIo: IOCTL_CDROM_CHECK_VERIFY\n");
1158 Srb
->TimeOutValue
= DeviceExtension
->TimeOutValue
* 2;
1159 Srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
;
1160 Cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_TEST_UNIT_READY
;
1162 IoCallDriver (DeviceExtension
->PortDeviceObject
,
1167 IoCompleteRequest (Irp
,
1173 /* Call the SCSI port driver */
1174 IoCallDriver (DeviceExtension
->PortDeviceObject
,
1180 CdromDeviceControlCompletion (IN PDEVICE_OBJECT DeviceObject
,
1184 PDEVICE_EXTENSION DeviceExtension
;
1185 PDEVICE_EXTENSION PhysicalExtension
;
1186 PIO_STACK_LOCATION IrpStack
;
1187 PIO_STACK_LOCATION OrigCurrentIrpStack
;
1188 PIO_STACK_LOCATION OrigNextIrpStack
;
1189 PSCSI_REQUEST_BLOCK Srb
;
1194 DPRINT ("CdromDeviceControlCompletion() called\n");
1196 DeviceExtension
= (PDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
1197 PhysicalExtension
= (PDEVICE_EXTENSION
)DeviceExtension
->PhysicalDevice
->DeviceExtension
;
1198 Srb
= (PSCSI_REQUEST_BLOCK
) Context
;
1200 IrpStack
= IoGetCurrentIrpStackLocation (Irp
);
1202 /* Get the original IRP */
1203 OrigIrp
= (PIRP
)IrpStack
->Parameters
.Others
.Argument2
;
1204 OrigCurrentIrpStack
= IoGetCurrentIrpStackLocation (OrigIrp
);
1205 OrigNextIrpStack
= IoGetNextIrpStackLocation (OrigIrp
);
1207 if (SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_SUCCESS
)
1209 Status
= STATUS_SUCCESS
;
1213 DPRINT ("SrbStatus %lx\n", Srb
->SrbStatus
);
1215 /* Interpret sense info */
1216 Retry
= ScsiClassInterpretSenseInfo (DeviceObject
,
1218 IrpStack
->MajorFunction
,
1219 IrpStack
->Parameters
.DeviceIoControl
.IoControlCode
,
1220 MAXIMUM_RETRIES
- (ULONG
)OrigNextIrpStack
->Parameters
.Others
.Argument1
,
1222 DPRINT ("Retry %u\n", Retry
);
1225 DPRINT ("Status %lx\n", Status
);
1228 if (NT_SUCCESS (Status
))
1230 switch (OrigCurrentIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
)
1232 case IOCTL_CDROM_GET_DRIVE_GEOMETRY
:
1234 PREAD_CAPACITY_DATA CapacityBuffer
;
1238 DPRINT1 ("CdromClassControlCompletion: IOCTL_CDROM_GET_DRIVE_GEOMETRY\n");
1240 CapacityBuffer
= (PREAD_CAPACITY_DATA
)Srb
->DataBuffer
;
1241 SectorSize
= (((PUCHAR
)&CapacityBuffer
->BytesPerBlock
)[0] << 24) |
1242 (((PUCHAR
)&CapacityBuffer
->BytesPerBlock
)[1] << 16) |
1243 (((PUCHAR
)&CapacityBuffer
->BytesPerBlock
)[2] << 8) |
1244 ((PUCHAR
)&CapacityBuffer
->BytesPerBlock
)[3];
1246 LastSector
= (((PUCHAR
)&CapacityBuffer
->LogicalBlockAddress
)[0] << 24) |
1247 (((PUCHAR
)&CapacityBuffer
->LogicalBlockAddress
)[1] << 16) |
1248 (((PUCHAR
)&CapacityBuffer
->LogicalBlockAddress
)[2] << 8) |
1249 ((PUCHAR
)&CapacityBuffer
->LogicalBlockAddress
)[3];
1251 if (SectorSize
== 0)
1253 DeviceExtension
->DiskGeometry
->BytesPerSector
= SectorSize
;
1255 DeviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(LastSector
+ 1);
1256 WHICH_BIT(DeviceExtension
->DiskGeometry
->BytesPerSector
,
1257 DeviceExtension
->SectorShift
);
1258 DeviceExtension
->PartitionLength
.QuadPart
=
1259 (DeviceExtension
->PartitionLength
.QuadPart
<< DeviceExtension
->SectorShift
);
1261 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)
1263 DeviceExtension
->DiskGeometry
->MediaType
= RemovableMedia
;
1267 DeviceExtension
->DiskGeometry
->MediaType
= FixedMedia
;
1269 DeviceExtension
->DiskGeometry
->Cylinders
.QuadPart
=
1270 (LONGLONG
)((LastSector
+ 1)/(32 * 64));
1271 DeviceExtension
->DiskGeometry
->SectorsPerTrack
= 32;
1272 DeviceExtension
->DiskGeometry
->TracksPerCylinder
= 64;
1274 RtlCopyMemory (OrigIrp
->AssociatedIrp
.SystemBuffer
,
1275 DeviceExtension
->DiskGeometry
,
1276 sizeof(DISK_GEOMETRY
));
1277 OrigIrp
->IoStatus
.Information
= sizeof(DISK_GEOMETRY
);
1281 case IOCTL_CDROM_CHECK_VERIFY
:
1282 DPRINT ("CdromDeviceControlCompletion: IOCTL_CDROM_CHECK_VERIFY\n");
1283 if (OrigCurrentIrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
!= 0)
1285 /* Return the media change counter */
1286 *((PULONG
)(OrigIrp
->AssociatedIrp
.SystemBuffer
)) =
1287 PhysicalExtension
->MediaChangeCount
;
1288 OrigIrp
->IoStatus
.Information
= sizeof(ULONG
);
1292 OrigIrp
->IoStatus
.Information
= 0;
1298 OrigIrp
->IoStatus
.Information
= 0;
1299 Status
= STATUS_INVALID_DEVICE_REQUEST
;
1304 /* Release the SRB and associated buffers */
1307 DPRINT("Srb %p\n", Srb
);
1309 if (Srb
->DataBuffer
!= NULL
)
1310 ExFreePool (Srb
->DataBuffer
);
1312 if (Srb
->SenseInfoBuffer
!= NULL
)
1313 ExFreePool (Srb
->SenseInfoBuffer
);
1318 if (OrigIrp
->PendingReturned
)
1320 IoMarkIrpPending (OrigIrp
);
1323 /* Release the MDL */
1324 if (Irp
->MdlAddress
!= NULL
)
1326 IoFreeMdl (Irp
->MdlAddress
);
1329 /* Release the sub irp */
1332 /* Set io status information */
1333 OrigIrp
->IoStatus
.Status
= Status
;
1334 if (!NT_SUCCESS(Status
) && IoIsErrorUserInduced (Status
))
1336 IoSetHardErrorOrVerifyDevice (OrigIrp
,
1338 OrigIrp
->IoStatus
.Information
= 0;
1341 /* Complete the original IRP */
1342 IoCompleteRequest (OrigIrp
,
1344 IoStartNextPacket (DeviceObject
,
1347 DPRINT ("CdromDeviceControlCompletion() done\n");
1349 return STATUS_MORE_PROCESSING_REQUIRED
;
1354 CdromTimerRoutine(PDEVICE_OBJECT DeviceObject
,
1357 DPRINT ("CdromTimerRoutine() called\n");