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.
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 *****************************************************************/
41 #include <include/class2.h>
47 #define VERSION "0.0.1"
50 #define SCSI_CDROM_TIMEOUT 10 /* Default timeout: 10 seconds */
53 typedef struct _ERROR_RECOVERY_DATA6
55 MODE_PARAMETER_HEADER Header
;
56 MODE_READ_RECOVERY_PAGE ReadRecoveryPage
;
57 } ERROR_RECOVERY_DATA6
, *PERROR_RECOVERY_DATA6
;
60 typedef struct _ERROR_RECOVERY_DATA10
62 MODE_PARAMETER_HEADER10 Header
;
63 MODE_READ_RECOVERY_PAGE ReadRecoveryPage
;
64 } ERROR_RECOVERY_DATA10
, *PERROR_RECOVERY_DATA10
;
66 typedef struct _MODE_CAPABILITIES_PAGE2
73 UCHAR Capabilities
[4];
74 UCHAR MaximumSpeedSupported
[2];
76 UCHAR NumberVolumeLevels
;
78 UCHAR CurrentSpeed
[2];
81 UCHAR DigitalOutput
:4;
84 } MODE_CAPABILITIES_PAGE2
, *PMODE_CAPABILITIES_PAGE2
;
86 typedef struct _MODE_CAPABILITIES_DATA6
88 MODE_PARAMETER_HEADER Header
;
89 MODE_CAPABILITIES_PAGE2 CababilitiesPage
;
90 } MODE_CAPABILITIES_DATA6
, *PMODE_CAPABILITIES_DATA6
;
92 typedef struct _MODE_CAPABILITIES_DATA10
94 MODE_PARAMETER_HEADER10 Header
;
95 MODE_CAPABILITIES_PAGE2 CababilitiesPage
;
96 } MODE_CAPABILITIES_DATA10
, *PMODE_CAPABILITIES_DATA10
;
98 typedef struct _CDROM_DATA
104 } CDROM_DATA
, *PCDROM_DATA
;
106 /* CDROM_DATA.XaFlags */
107 #define XA_USE_6_BYTE 0x0001
108 #define XA_USE_10_BYTE 0x0002
109 #define XA_USE_READ_CD 0x0004
110 #define XA_NOT_SUPPORTED 0x0008
114 CdromClassFindDevices(IN PDRIVER_OBJECT DriverObject
,
115 IN PUNICODE_STRING RegistryPath
,
116 IN PCLASS_INIT_DATA InitializationData
,
117 IN PDEVICE_OBJECT PortDeviceObject
,
118 IN ULONG PortNumber
);
121 CdromClassCheckDevice(IN PINQUIRYDATA InquiryData
);
124 CdromClassCheckReadWrite(IN PDEVICE_OBJECT DeviceObject
,
128 CdromClassCreateMediaChangeEvent(IN PDEVICE_EXTENSION DeviceExtension
,
129 IN ULONG DeviceNumber
);
132 CdromClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject
,
133 IN PUNICODE_STRING RegistryPath
,
134 IN PDEVICE_OBJECT PortDeviceObject
,
136 IN ULONG DeviceNumber
,
137 IN PIO_SCSI_CAPABILITIES Capabilities
,
138 IN PSCSI_INQUIRY_DATA InquiryData
,
139 IN PCLASS_INIT_DATA InitializationData
);
143 CdromClassDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
147 CdromClassStartIo (IN PDEVICE_OBJECT DeviceObject
,
151 CdromDeviceControlCompletion (IN PDEVICE_OBJECT DeviceObject
,
156 CdromTimerRoutine(IN PDEVICE_OBJECT DeviceObject
,
160 CdromWorkItem(IN PDEVICE_OBJECT DeviceObject
,
164 /* FUNCTIONS ****************************************************************/
166 /**********************************************************************
171 * This function initializes the driver, locates and claims
172 * hardware resources, and creates various NT objects needed
173 * to process I/O requests.
180 * System allocated Driver Object for this driver
182 * Name of registry driver service key
189 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
190 IN PUNICODE_STRING RegistryPath
)
192 CLASS_INIT_DATA InitData
;
194 DPRINT("CD-ROM Class Driver %s\n",
196 DPRINT("RegistryPath '%wZ'\n",
199 InitData
.InitializationDataSize
= sizeof(CLASS_INIT_DATA
);
200 InitData
.DeviceExtensionSize
= sizeof(DEVICE_EXTENSION
) + sizeof(CDROM_DATA
);
201 InitData
.DeviceType
= FILE_DEVICE_CD_ROM
;
202 InitData
.DeviceCharacteristics
= FILE_REMOVABLE_MEDIA
| FILE_READ_ONLY_DEVICE
;
204 InitData
.ClassError
= NULL
;
205 InitData
.ClassReadWriteVerification
= CdromClassCheckReadWrite
;
206 InitData
.ClassFindDeviceCallBack
= CdromClassCheckDevice
;
207 InitData
.ClassFindDevices
= CdromClassFindDevices
;
208 InitData
.ClassDeviceControl
= CdromClassDeviceControl
;
209 InitData
.ClassShutdownFlush
= NULL
;
210 InitData
.ClassCreateClose
= NULL
;
211 InitData
.ClassStartIo
= CdromClassStartIo
;
213 return(ScsiClassInitialize(DriverObject
,
219 /**********************************************************************
221 * CdromClassFindDevices
224 * This function searches for device that are attached to the
232 * System allocated Driver Object for this driver
234 * Name of registry driver service key.
236 * Pointer to the main initialization data
238 * Scsi port device object
243 * TRUE: At least one disk drive was found
244 * FALSE: No disk drive found
248 CdromClassFindDevices(IN PDRIVER_OBJECT DriverObject
,
249 IN PUNICODE_STRING RegistryPath
,
250 IN PCLASS_INIT_DATA InitializationData
,
251 IN PDEVICE_OBJECT PortDeviceObject
,
254 PCONFIGURATION_INFORMATION ConfigInfo
;
255 PIO_SCSI_CAPABILITIES PortCapabilities
;
256 PSCSI_ADAPTER_BUS_INFO AdapterBusInfo
;
257 PSCSI_INQUIRY_DATA UnitInfo
;
258 PINQUIRYDATA InquiryData
;
262 BOOLEAN FoundDevice
= FALSE
;
265 DPRINT("CdromClassFindDevices() called.\n");
267 /* Get port capabilities */
268 Status
= ScsiClassGetCapabilities(PortDeviceObject
,
270 if (!NT_SUCCESS(Status
))
272 DPRINT1("ScsiClassGetCapabilities() failed! (Status 0x%lX)\n", Status
);
276 DPRINT("PortCapabilities: %p\n", PortCapabilities
);
277 DPRINT("MaximumTransferLength: %lu\n", PortCapabilities
->MaximumTransferLength
);
278 DPRINT("MaximumPhysicalPages: %lu\n", PortCapabilities
->MaximumPhysicalPages
);
280 /* Get inquiry data */
281 Status
= ScsiClassGetInquiryData(PortDeviceObject
,
282 (PSCSI_ADAPTER_BUS_INFO
*)&Buffer
);
283 if (!NT_SUCCESS(Status
))
285 DPRINT1("ScsiClassGetInquiryData() failed! (Status 0x%lX)\n", Status
);
289 /* Check whether there are unclaimed devices */
290 AdapterBusInfo
= (PSCSI_ADAPTER_BUS_INFO
)Buffer
;
291 DeviceCount
= ScsiClassFindUnclaimedDevices(InitializationData
,
293 if (DeviceCount
== 0)
295 DPRINT("No unclaimed devices!\n");
299 DPRINT("Found %lu unclaimed devices!\n", DeviceCount
);
301 ConfigInfo
= IoGetConfigurationInformation();
302 DPRINT("Number of SCSI ports: %lu\n", ConfigInfo
->ScsiPortCount
);
304 /* Search each bus of this adapter */
305 for (Bus
= 0; Bus
< (ULONG
)AdapterBusInfo
->NumberOfBuses
; Bus
++)
307 DPRINT("Searching bus %lu\n", Bus
);
309 UnitInfo
= (PSCSI_INQUIRY_DATA
)(Buffer
+ AdapterBusInfo
->BusData
[Bus
].InquiryDataOffset
);
311 while (AdapterBusInfo
->BusData
[Bus
].InquiryDataOffset
)
313 InquiryData
= (PINQUIRYDATA
)UnitInfo
->InquiryData
;
315 if ((InquiryData
->DeviceType
== READ_ONLY_DIRECT_ACCESS_DEVICE
) &&
316 (InquiryData
->DeviceTypeQualifier
== 0) &&
317 (UnitInfo
->DeviceClaimed
== FALSE
))
319 DPRINT("Vendor: '%.24s'\n",
320 InquiryData
->VendorId
);
322 /* Create device objects for disk */
323 Status
= CdromClassCreateDeviceObject(DriverObject
,
327 ConfigInfo
->CdRomCount
,
331 if (NT_SUCCESS(Status
))
333 ConfigInfo
->CdRomCount
++;
338 if (UnitInfo
->NextInquiryDataOffset
== 0)
341 UnitInfo
= (PSCSI_INQUIRY_DATA
)(Buffer
+ UnitInfo
->NextInquiryDataOffset
);
347 DPRINT("CdromClassFindDevices() done\n");
353 /**********************************************************************
355 * CdromClassCheckDevice
358 * This function checks the InquiryData for the correct device
359 * type and qualifier.
366 * Pointer to the inquiry data for the device in question.
369 * TRUE: A disk device was found.
374 CdromClassCheckDevice(IN PINQUIRYDATA InquiryData
)
376 return((InquiryData
->DeviceType
== READ_ONLY_DIRECT_ACCESS_DEVICE
) &&
377 (InquiryData
->DeviceTypeQualifier
== 0));
381 /**********************************************************************
383 * CdromClassCheckReadWrite
386 * This function checks the given IRP for correct data.
393 * Pointer to the device.
398 * STATUS_SUCCESS: The IRP matches the requirements of the given device.
403 CdromClassCheckReadWrite(IN PDEVICE_OBJECT DeviceObject
,
406 DPRINT("CdromClassCheckReadWrite() called\n");
408 return(STATUS_SUCCESS
);
413 CdromClassCreateMediaChangeEvent(IN PDEVICE_EXTENSION DeviceExtension
,
414 IN ULONG DeviceNumber
)
418 DeviceExtension
->MediaChangeEvent
=
419 IoCreateSynchronizationEvent (NULL
,
420 &DeviceExtension
->MediaChangeEventHandle
);
422 KeClearEvent (DeviceExtension
->MediaChangeEvent
);
426 /**********************************************************************
428 * CdromClassCreateDeviceObject
431 * Create the raw device and any partition devices on this drive
438 * System allocated Driver Object for this driver.
440 * Name of registry driver service key.
453 CdromClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject
,
454 IN PUNICODE_STRING RegistryPath
,
455 IN PDEVICE_OBJECT PortDeviceObject
,
457 IN ULONG DeviceNumber
,
458 IN PIO_SCSI_CAPABILITIES Capabilities
,
459 IN PSCSI_INQUIRY_DATA InquiryData
,
460 IN PCLASS_INIT_DATA InitializationData
)
462 PDEVICE_EXTENSION DiskDeviceExtension
; /* defined in class2.h */
463 PDEVICE_OBJECT DiskDeviceObject
;
464 PCDROM_DATA CdromData
;
466 SCSI_REQUEST_BLOCK Srb
;
472 DPRINT("CdromClassCreateDeviceObject() called\n");
474 /* Claim the cdrom device */
475 Status
= ScsiClassClaimDevice(PortDeviceObject
,
479 if (!NT_SUCCESS(Status
))
481 DbgPrint("Could not claim cdrom device\n");
485 /* Create cdrom device */
487 "\\Device\\CdRom%lu",
490 Status
= ScsiClassCreateDeviceObject(DriverObject
,
495 if (!NT_SUCCESS(Status
))
497 DPRINT1("ScsiClassCreateDeviceObject() failed (Status %x)\n", Status
);
499 /* Release (unclaim) the disk */
500 ScsiClassClaimDevice(PortDeviceObject
,
508 DiskDeviceObject
->Flags
|= DO_DIRECT_IO
;
509 DiskDeviceObject
->Characteristics
|= FILE_REMOVABLE_MEDIA
;
510 DiskDeviceObject
->StackSize
= (CCHAR
)PortDeviceObject
->StackSize
+ 1;
512 if (PortDeviceObject
->AlignmentRequirement
> DiskDeviceObject
->AlignmentRequirement
)
514 DiskDeviceObject
->AlignmentRequirement
= PortDeviceObject
->AlignmentRequirement
;
517 DiskDeviceExtension
= DiskDeviceObject
->DeviceExtension
;
518 DiskDeviceExtension
->LockCount
= 0;
519 DiskDeviceExtension
->DeviceNumber
= DeviceNumber
;
520 DiskDeviceExtension
->DeviceObject
= DiskDeviceObject
;
521 DiskDeviceExtension
->PortDeviceObject
= PortDeviceObject
;
522 DiskDeviceExtension
->PhysicalDevice
= DiskDeviceObject
;
523 DiskDeviceExtension
->PortCapabilities
= Capabilities
;
524 DiskDeviceExtension
->StartingOffset
.QuadPart
= 0;
525 DiskDeviceExtension
->PortNumber
= (UCHAR
)PortNumber
;
526 DiskDeviceExtension
->PathId
= InquiryData
->PathId
;
527 DiskDeviceExtension
->TargetId
= InquiryData
->TargetId
;
528 DiskDeviceExtension
->Lun
= InquiryData
->Lun
;
530 /* zero-out disk data */
531 CdromData
= (PCDROM_DATA
)(DiskDeviceExtension
+ 1);
532 RtlZeroMemory(CdromData
,
535 DiskDeviceExtension
->SenseData
= ExAllocatePool(NonPagedPool
,
537 if (DiskDeviceExtension
->SenseData
== NULL
)
539 DPRINT1("Failed to allocate sense data buffer!\n");
541 IoDeleteDevice(DiskDeviceObject
);
543 /* Release (unclaim) the disk */
544 ScsiClassClaimDevice(PortDeviceObject
,
549 return(STATUS_INSUFFICIENT_RESOURCES
);
552 /* Get timeout value */
553 DiskDeviceExtension
->TimeOutValue
=
554 ScsiClassQueryTimeOutRegistryValue(RegistryPath
);
555 if (DiskDeviceExtension
->TimeOutValue
== 0)
556 DiskDeviceExtension
->TimeOutValue
= SCSI_CDROM_TIMEOUT
;
558 /* Initialize lookaside list for SRBs */
559 ScsiClassInitializeSrbLookasideList(DiskDeviceExtension
,
562 /* Get disk geometry */
563 DiskDeviceExtension
->DiskGeometry
= ExAllocatePool(NonPagedPool
,
564 sizeof(DISK_GEOMETRY
));
565 if (DiskDeviceExtension
->DiskGeometry
== NULL
)
567 DPRINT1("Failed to allocate geometry buffer!\n");
569 ExDeleteNPagedLookasideList(&DiskDeviceExtension
->SrbLookasideListHead
);
571 IoDeleteDevice(DiskDeviceObject
);
573 /* Release (unclaim) the disk */
574 ScsiClassClaimDevice(PortDeviceObject
,
579 return(STATUS_INSUFFICIENT_RESOURCES
);
582 /* Read the drive's capacity */
583 Status
= ScsiClassReadDriveCapacity(DiskDeviceObject
);
584 if (!NT_SUCCESS(Status
) ||
585 DiskDeviceExtension
->DiskGeometry
->BytesPerSector
== 0)
587 /* Set ISO9660 defaults */
588 DiskDeviceExtension
->DiskGeometry
->BytesPerSector
= 2048;
589 DiskDeviceExtension
->DiskGeometry
->MediaType
= RemovableMedia
;
590 DiskDeviceExtension
->SectorShift
= 11;
591 DiskDeviceExtension
->PartitionLength
.QuadPart
= (ULONGLONG
)0x7fffffff;
595 /* Make sure the BytesPerSector value is a power of 2 */
596 // DiskDeviceExtension->DiskGeometry->BytesPerSector = 2048;
599 DPRINT("SectorSize: %lu\n", DiskDeviceExtension
->DiskGeometry
->BytesPerSector
);
601 /* Initialize media change support */
602 CdromClassCreateMediaChangeEvent (DiskDeviceExtension
,
604 if (DiskDeviceExtension
->MediaChangeEvent
!= NULL
)
606 DPRINT("Allocated media change event!\n");
608 /* FIXME: Allocate media change IRP and SRB */
611 /* Use 6 byte xa commands by default */
612 CdromData
->XaFlags
|= XA_USE_6_BYTE
;
614 /* Read 'error recovery page' to get additional drive capabilities */
615 Length
= sizeof(MODE_READ_RECOVERY_PAGE
) + MODE_HEADER_LENGTH
;
618 sizeof(SCSI_REQUEST_BLOCK
));
620 Srb
.TimeOutValue
= DiskDeviceExtension
->TimeOutValue
;
623 Cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
624 Cdb
->MODE_SENSE
.PageCode
= 0x01;
625 Cdb
->MODE_SENSE
.AllocationLength
= (UCHAR
)Length
;
627 Buffer
= ExAllocatePool (NonPagedPool
,
628 max(sizeof(ERROR_RECOVERY_DATA6
),
629 max(sizeof(ERROR_RECOVERY_DATA10
),
630 max(sizeof(MODE_CAPABILITIES_DATA6
),
631 sizeof(MODE_CAPABILITIES_DATA10
)))));
634 DPRINT1("Allocating recovery page buffer failed!\n");
635 return STATUS_INSUFFICIENT_RESOURCES
;
638 Status
= ScsiClassSendSrbSynchronous (DiskDeviceObject
,
644 if (!NT_SUCCESS (Status
))
646 DPRINT("MODE_SENSE(6) failed\n");
648 /* Try the 10 byte version */
649 Length
= sizeof(MODE_READ_RECOVERY_PAGE
) + MODE_HEADER_LENGTH10
;
652 sizeof(SCSI_REQUEST_BLOCK
));
654 Srb
.TimeOutValue
= DiskDeviceExtension
->TimeOutValue
;
657 Cdb
->MODE_SENSE10
.OperationCode
= SCSIOP_MODE_SENSE10
;
658 Cdb
->MODE_SENSE10
.PageCode
= 0x01;
659 Cdb
->MODE_SENSE10
.AllocationLength
[0] = (UCHAR
)(Length
>> 8);
660 Cdb
->MODE_SENSE10
.AllocationLength
[1] = (UCHAR
)(Length
& 0xFF);
662 Status
= ScsiClassSendSrbSynchronous (DiskDeviceObject
,
668 if (Status
== STATUS_DATA_OVERRUN
)
670 DPRINT1("Data overrun\n");
674 else if (NT_SUCCESS (Status
))
676 DPRINT("Use 10 byte commands\n");
677 CdromData
->XaFlags
&= XA_USE_6_BYTE
;
678 CdromData
->XaFlags
|= XA_USE_10_BYTE
;
682 DPRINT("XA not supported\n");
683 CdromData
->XaFlags
|= XA_NOT_SUPPORTED
;
688 DPRINT("Use 6 byte commands\n");
691 /* Read 'capabilities & mechanical status page' to get additional drive capabilities */
692 Length
= sizeof(MODE_READ_RECOVERY_PAGE
) + MODE_HEADER_LENGTH
;
694 if (!(CdromData
->XaFlags
& XA_NOT_SUPPORTED
))
696 RtlZeroMemory (&Srb
, sizeof(SCSI_REQUEST_BLOCK
));
697 Srb
.TimeOutValue
= DiskDeviceExtension
->TimeOutValue
;
700 if (CdromData
->XaFlags
& XA_USE_10_BYTE
)
702 /* Try the 10 byte version */
703 Length
= sizeof(MODE_CAPABILITIES_PAGE2
) + MODE_HEADER_LENGTH10
;
706 Cdb
->MODE_SENSE10
.OperationCode
= SCSIOP_MODE_SENSE10
;
707 Cdb
->MODE_SENSE10
.PageCode
= 0x2a;
708 Cdb
->MODE_SENSE10
.AllocationLength
[0] = (UCHAR
)(Length
>> 8);
709 Cdb
->MODE_SENSE10
.AllocationLength
[1] = (UCHAR
)(Length
& 0xFF);
713 Length
= sizeof(MODE_CAPABILITIES_PAGE2
) + MODE_HEADER_LENGTH
;
716 Cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
717 Cdb
->MODE_SENSE
.PageCode
= 0x2a;
718 Cdb
->MODE_SENSE
.AllocationLength
= (UCHAR
)Length
;
720 Status
= ScsiClassSendSrbSynchronous (DiskDeviceObject
,
725 if (NT_SUCCESS (Status
))
728 PMODE_CAPABILITIES_PAGE2 CapabilitiesData
;
729 if (CdromData
->XaFlags
& XA_USE_10_BYTE
)
731 CapabilitiesData
= (PMODE_CAPABILITIES_PAGE2
)(Buffer
+ sizeof(MODE_PARAMETER_HEADER10
));
735 CapabilitiesData
= (PMODE_CAPABILITIES_PAGE2
)(Buffer
+ sizeof(MODE_PARAMETER_HEADER
));
738 DbgPrint("Capabilities for '%s':\n", NameBuffer
);
739 if (CapabilitiesData
->Reserved2
[0] & 0x20)
741 DbgPrint(" Drive supports reading of DVD-RAM discs\n");
743 if (CapabilitiesData
->Reserved2
[0] & 0x10)
745 DbgPrint(" Drive supports reading of DVD-R discs\n");
747 if (CapabilitiesData
->Reserved2
[0] & 0x08)
749 DbgPrint(" Drive supports reading of DVD-ROM discs\n");
751 if (CapabilitiesData
->Reserved2
[0] & 0x04)
753 DbgPrint(" Drive supports reading CD-R discs with addressing method 2\n");
755 if (CapabilitiesData
->Reserved2
[0] & 0x02)
757 DbgPrint(" Drive can read from CD-R/W (CD-E) discs (orange book, part III)\n");
759 if (CapabilitiesData
->Reserved2
[0] & 0x01)
761 DbgPrint(" Drive supports read from CD-R discs (orange book, part II)\n");
763 DPRINT("CapabilitiesData.Reserved2[1] %x\n", CapabilitiesData
->Reserved2
[1]);
764 if (CapabilitiesData
->Reserved2
[1] & 0x01)
766 DbgPrint(" Drive can write to CD-R discs (orange book, part II)\n");
768 if (CapabilitiesData
->Reserved2
[1] & 0x02)
770 DbgPrint(" Drive can write to CD-R/W (CD-E) discs (orange book, part III)\n");
772 if (CapabilitiesData
->Reserved2
[1] & 0x04)
774 DbgPrint(" Drive can fake writes\n");
776 if (CapabilitiesData
->Reserved2
[1] & 0x10)
778 DbgPrint(" Drive can write DVD-R discs\n");
780 if (CapabilitiesData
->Reserved2
[1] & 0x20)
782 DbgPrint(" Drive can write DVD-RAM discs\n");
784 DPRINT("CapabilitiesData.Capabilities[0] %x\n", CapabilitiesData
->Capabilities
[0]);
785 if (CapabilitiesData
->Capabilities
[0] & 0x01)
787 DbgPrint(" Drive supports audio play operations\n");
789 if (CapabilitiesData
->Capabilities
[0] & 0x02)
791 DbgPrint(" Drive can deliver a composite audio/video data stream\n");
793 if (CapabilitiesData
->Capabilities
[0] & 0x04)
795 DbgPrint(" Drive supports digital output on port 1\n");
797 if (CapabilitiesData
->Capabilities
[0] & 0x08)
799 DbgPrint(" Drive supports digital output on port 2\n");
801 if (CapabilitiesData
->Capabilities
[0] & 0x10)
803 DbgPrint(" Drive can read mode 2, form 1 (XA) data\n");
805 if (CapabilitiesData
->Capabilities
[0] & 0x20)
807 DbgPrint(" Drive can read mode 2, form 2 data\n");
809 if (CapabilitiesData
->Capabilities
[0] & 0x40)
811 DbgPrint(" Drive can read multisession discs\n");
813 DPRINT("CapabilitiesData.Capabilities[1] %x\n", CapabilitiesData
->Capabilities
[1]);
814 if (CapabilitiesData
->Capabilities
[1] & 0x01)
816 DbgPrint(" Drive can read Red Book audio data\n");
818 if (CapabilitiesData
->Capabilities
[1] & 0x02)
820 DbgPrint(" Drive can continue a read cdda operation from a loss of streaming\n");
822 if (CapabilitiesData
->Capabilities
[1] & 0x04)
824 DbgPrint(" Subchannel reads can return combined R-W information\n");
826 if (CapabilitiesData
->Capabilities
[1] & 0x08)
828 DbgPrint(" R-W data will be returned deinterleaved and error corrected\n");
830 if (CapabilitiesData
->Capabilities
[1] & 0x10)
832 DbgPrint(" Drive supports C2 error pointers\n");
834 if (CapabilitiesData
->Capabilities
[1] & 0x20)
836 DbgPrint(" Drive can return International Standard Recording Code info\n");
838 if (CapabilitiesData
->Capabilities
[1] & 0x40)
840 DbgPrint(" Drive can return Media Catalog Number (UPC) info\n");
842 DPRINT("CapabilitiesData.Capabilities[2] %x\n", CapabilitiesData
->Capabilities
[2]);
843 if (CapabilitiesData
->Capabilities
[2] & 0x01)
845 DbgPrint(" Drive can lock the door\n");
847 if (CapabilitiesData
->Capabilities
[2] & 0x02)
849 DbgPrint(" The door is locked\n");
851 if (CapabilitiesData
->Capabilities
[2] & 0x04)
854 if (CapabilitiesData
->Capabilities
[2] & 0x08)
856 DbgPrint(" Drive can eject a disc or changer cartridge\n");
858 if (CapabilitiesData
->Capabilities
[2] & 0x10)
860 DbgPrint(" Drive supports C2 error pointers\n");
862 switch (CapabilitiesData
->Capabilities
[2] >> 5)
865 DbgPrint(" Drive use a caddy type loading mechanism\n");
868 DbgPrint(" Drive use a tray type loading mechanism\n");
871 DbgPrint(" Drive use a pop-up type loading mechanism\n");
874 DbgPrint(" Drive is a changer with individually changeable discs\n");
877 DbgPrint(" Drive is a changer with cartridge mechanism\n");
880 DPRINT("CapabilitiesData.Capabilities[3] %x\n", CapabilitiesData
->Capabilities
[3]);
881 if (CapabilitiesData
->Capabilities
[3] & 0x01)
883 DbgPrint(" Audio level for each channel can be controlled independently\n");
885 if (CapabilitiesData
->Capabilities
[3] & 0x02)
887 DbgPrint(" Audio for each channel can be muted independently\n");
889 if (CapabilitiesData
->Capabilities
[3] & 0x04)
891 DbgPrint(" Changer can report exact contents of slots\n");
893 if (CapabilitiesData
->Capabilities
[3] & 0x08)
895 DbgPrint(" Drive supports software slot selection\n");
897 DbgPrint(" Maximum speed is %d kB/s\n",
898 (CapabilitiesData
->MaximumSpeedSupported
[0] << 8)
899 | CapabilitiesData
->MaximumSpeedSupported
[1]);
900 DbgPrint(" Current speed is %d kB/s\n",
901 (CapabilitiesData
->CurrentSpeed
[0] << 8)
902 | CapabilitiesData
->CurrentSpeed
[1]);
903 DbgPrint(" Number of discrete volume levels is %d\n",
904 (CapabilitiesData
->Reserved3
<< 8)
905 | CapabilitiesData
->NumberVolumeLevels
);
906 DbgPrint(" Buffer size is %d kB\n",
907 (CapabilitiesData
->BufferSize
[0] << 8)
908 | CapabilitiesData
->BufferSize
[1]);
913 DPRINT("XA not supported\n");
914 CdromData
->XaFlags
|= XA_NOT_SUPPORTED
;
922 /* Initialize device timer */
923 IoInitializeTimer(DiskDeviceObject
,
926 IoStartTimer(DiskDeviceObject
);
928 DPRINT("CdromClassCreateDeviceObjects() done\n");
930 return(STATUS_SUCCESS
);
934 /**********************************************************************
936 * CdromClassReadTocEntry
948 CdromClassReadTocEntry (PDEVICE_OBJECT DeviceObject
,
953 PDEVICE_EXTENSION DeviceExtension
;
954 SCSI_REQUEST_BLOCK Srb
;
957 DeviceExtension
= (PDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
959 RtlZeroMemory(&Srb
, sizeof(SCSI_REQUEST_BLOCK
));
961 Srb
.TimeOutValue
= DeviceExtension
->TimeOutValue
;
964 Cdb
->READ_TOC
.OperationCode
= SCSIOP_READ_TOC
;
965 Cdb
->READ_TOC
.StartingTrack
= TrackNo
;
966 Cdb
->READ_TOC
.Format
= 0;
967 Cdb
->READ_TOC
.AllocationLength
[0] = Length
>> 8;
968 Cdb
->READ_TOC
.AllocationLength
[1] = Length
& 0xff;
969 Cdb
->READ_TOC
.Msf
= 1;
971 return(ScsiClassSendSrbSynchronous(DeviceObject
,
980 CdromClassReadLastSession (PDEVICE_OBJECT DeviceObject
,
985 PDEVICE_EXTENSION DeviceExtension
;
986 SCSI_REQUEST_BLOCK Srb
;
989 DeviceExtension
= (PDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
991 RtlZeroMemory(&Srb
, sizeof(SCSI_REQUEST_BLOCK
));
993 Srb
.TimeOutValue
= DeviceExtension
->TimeOutValue
;
996 Cdb
->READ_TOC
.OperationCode
= SCSIOP_READ_TOC
;
997 Cdb
->READ_TOC
.StartingTrack
= TrackNo
;
998 Cdb
->READ_TOC
.Format
= 1;
999 Cdb
->READ_TOC
.AllocationLength
[0] = Length
>> 8;
1000 Cdb
->READ_TOC
.AllocationLength
[1] = Length
& 0xff;
1001 Cdb
->READ_TOC
.Msf
= 0;
1003 return(ScsiClassSendSrbSynchronous(DeviceObject
,
1011 /**********************************************************************
1013 * CdromClassDeviceControl
1016 * Answer requests for device control calls
1024 * Standard dispatch arguments
1031 CdromClassDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
1034 PDEVICE_EXTENSION DeviceExtension
;
1035 PIO_STACK_LOCATION IrpStack
;
1036 ULONG ControlCode
, InputLength
, OutputLength
;
1037 PCDROM_DATA CdromData
;
1041 DPRINT("CdromClassDeviceControl() called!\n");
1043 Status
= STATUS_INVALID_DEVICE_REQUEST
;
1045 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1046 ControlCode
= IrpStack
->Parameters
.DeviceIoControl
.IoControlCode
;
1047 InputLength
= IrpStack
->Parameters
.DeviceIoControl
.InputBufferLength
;
1048 OutputLength
= IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
1049 DeviceExtension
= (PDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
1050 CdromData
= (PCDROM_DATA
)(DeviceExtension
+ 1);
1052 switch (ControlCode
)
1054 case IOCTL_CDROM_GET_DRIVE_GEOMETRY
:
1055 DPRINT ("CdromClassDeviceControl: IOCTL_CDROM_GET_DRIVE_GEOMETRY\n");
1056 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(DISK_GEOMETRY
))
1058 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1061 IoMarkIrpPending (Irp
);
1062 IoStartPacket (DeviceObject
,
1066 return STATUS_PENDING
;
1068 case IOCTL_CDROM_CHECK_VERIFY
:
1069 DPRINT ("CdromClassDeviceControl: IOCTL_CDROM_CHECK_VERIFY\n");
1070 if (OutputLength
!= 0 && OutputLength
< sizeof (ULONG
))
1072 DPRINT1("Buffer too small\n");
1073 Status
= STATUS_BUFFER_TOO_SMALL
;
1076 IoMarkIrpPending (Irp
);
1077 IoStartPacket (DeviceObject
,
1081 return STATUS_PENDING
;
1083 case IOCTL_CDROM_READ_TOC
:
1084 DPRINT("IOCTL_CDROM_READ_TOC\n");
1085 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(CDROM_TOC
))
1087 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1091 PCDROM_TOC TocBuffer
;
1094 TocBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
1096 /* First read the lead out */
1097 Length
= 4 + sizeof(TRACK_DATA
);
1098 Status
= CdromClassReadTocEntry(DeviceObject
,
1102 if (NT_SUCCESS(Status
))
1104 if (TocBuffer
->FirstTrack
== 0xaa)
1106 /* there is an empty cd */
1107 Information
= Length
;
1112 Length
= 4 + sizeof(TRACK_DATA
) * (TocBuffer
->LastTrack
- TocBuffer
->FirstTrack
+ 2);
1113 Status
= CdromClassReadTocEntry(DeviceObject
,
1114 TocBuffer
->FirstTrack
,
1116 if (NT_SUCCESS(Status
))
1118 Information
= Length
;
1125 case IOCTL_CDROM_GET_LAST_SESSION
:
1126 DPRINT("IOCTL_CDROM_GET_LAST_SESSION\n");
1127 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< 4 + sizeof(TRACK_DATA
))
1129 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1133 PCDROM_TOC TocBuffer
;
1136 TocBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
1137 Length
= 4 + sizeof(TRACK_DATA
);
1138 Status
= CdromClassReadLastSession(DeviceObject
,
1142 if (NT_SUCCESS(Status
))
1144 Information
= Length
;
1150 /* Call the common device control function */
1151 return(ScsiClassDeviceControl(DeviceObject
, Irp
));
1154 /* Verify the device if the user caused the error */
1155 if (!NT_SUCCESS(Status
) && IoIsErrorUserInduced(Status
))
1157 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
1160 Irp
->IoStatus
.Status
= Status
;
1161 Irp
->IoStatus
.Information
= Information
;
1162 IoCompleteRequest(Irp
,
1169 /**********************************************************************
1174 * Starts IRP processing.
1182 * Standard dispatch arguments
1188 CdromClassStartIo (IN PDEVICE_OBJECT DeviceObject
,
1191 PDEVICE_EXTENSION DeviceExtension
;
1192 PIO_STACK_LOCATION IrpStack
;
1193 PIO_STACK_LOCATION SubIrpStack
;
1194 ULONG MaximumTransferLength
;
1195 ULONG TransferPages
;
1196 PSCSI_REQUEST_BLOCK Srb
;
1202 DPRINT("CdromClassStartIo() called!\n");
1204 IoMarkIrpPending (Irp
);
1206 DeviceExtension
= (PDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
1207 IrpStack
= IoGetCurrentIrpStackLocation (Irp
);
1209 MaximumTransferLength
= DeviceExtension
->PortCapabilities
->MaximumTransferLength
;
1211 if (DeviceObject
->Flags
& DO_VERIFY_VOLUME
)
1213 if (!(IrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
))
1215 DPRINT1 ("Verify required\n");
1217 if (Irp
->Tail
.Overlay
.Thread
)
1219 IoSetHardErrorOrVerifyDevice (Irp
,
1222 Irp
->IoStatus
.Status
= STATUS_VERIFY_REQUIRED
;
1224 /* FIXME: Update drive capacity */
1225 IoCompleteRequest (Irp
,
1227 IoStartNextPacket (DeviceObject
,
1233 if (IrpStack
->MajorFunction
== IRP_MJ_READ
)
1235 DPRINT ("CdromClassStartIo: IRP_MJ_READ\n");
1238 ADDRESS_AND_SIZE_TO_SPAN_PAGES (MmGetMdlVirtualAddress(Irp
->MdlAddress
),
1239 IrpStack
->Parameters
.Read
.Length
);
1241 /* Check transfer size */
1242 if ((IrpStack
->Parameters
.Read
.Length
> MaximumTransferLength
) ||
1243 (TransferPages
> DeviceExtension
->PortCapabilities
->MaximumPhysicalPages
))
1245 /* Transfer size is too large - split it */
1247 DeviceExtension
->PortCapabilities
->MaximumPhysicalPages
- 1;
1249 /* Adjust transfer size */
1250 if (MaximumTransferLength
> TransferPages
* PAGE_SIZE
)
1251 MaximumTransferLength
= TransferPages
* PAGE_SIZE
;
1253 if (MaximumTransferLength
== 0)
1254 MaximumTransferLength
= PAGE_SIZE
;
1256 /* Split the transfer */
1257 ScsiClassSplitRequest (DeviceObject
,
1259 MaximumTransferLength
);
1265 ScsiClassBuildRequest (DeviceObject
,
1269 else if (IrpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
)
1271 DPRINT ("CdromClassStartIo: IRP_MJ_IRP_MJ_DEVICE_CONTROL\n");
1273 /* Allocate an IRP for sending requests to the port driver */
1274 SubIrp
= IoAllocateIrp ((CCHAR
)(DeviceObject
->StackSize
+ 1),
1278 Irp
->IoStatus
.Information
= 0;
1279 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1280 IoCompleteRequest (Irp
,
1282 IoStartNextPacket (DeviceObject
,
1287 /* Allocate an SRB */
1288 Srb
= ExAllocatePool (NonPagedPool
,
1289 sizeof (SCSI_REQUEST_BLOCK
));
1293 Irp
->IoStatus
.Information
= 0;
1294 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1295 IoCompleteRequest (Irp
,
1297 IoStartNextPacket (DeviceObject
,
1302 /* Allocte a sense buffer */
1303 SenseBuffer
= ExAllocatePool (NonPagedPoolCacheAligned
,
1305 if (SenseBuffer
== NULL
)
1309 Irp
->IoStatus
.Information
= 0;
1310 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1311 IoCompleteRequest (Irp
,
1313 IoStartNextPacket (DeviceObject
,
1318 /* Initialize the IRP */
1319 IoSetNextIrpStackLocation (SubIrp
);
1320 SubIrp
->IoStatus
.Information
= 0;
1321 SubIrp
->IoStatus
.Status
= STATUS_SUCCESS
;
1323 SubIrp
->UserBuffer
= NULL
;
1325 SubIrpStack
= IoGetCurrentIrpStackLocation (SubIrp
);
1326 SubIrpStack
->DeviceObject
= DeviceExtension
->DeviceObject
;
1327 SubIrpStack
->Parameters
.Others
.Argument2
= (PVOID
)Irp
;
1329 /* Initialize next stack location */
1330 SubIrpStack
= IoGetNextIrpStackLocation (SubIrp
);
1331 SubIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
1332 SubIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
1333 SubIrpStack
->Parameters
.Scsi
.Srb
= Srb
;
1335 /* Initialize the SRB */
1337 sizeof (SCSI_REQUEST_BLOCK
));
1338 Srb
->Length
= sizeof (SCSI_REQUEST_BLOCK
);
1339 Srb
->PathId
= DeviceExtension
->PathId
;
1340 Srb
->TargetId
= DeviceExtension
->TargetId
;
1341 Srb
->Lun
= DeviceExtension
->Lun
;
1342 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1343 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
1344 Srb
->ScsiStatus
= 0;
1346 Srb
->OriginalRequest
= SubIrp
;
1347 Srb
->SenseInfoBuffer
= SenseBuffer
;
1348 Srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
1350 /* Initialize the CDB */
1351 Cdb
= (PCDB
)Srb
->Cdb
;
1353 /* Set the completion routine */
1354 IoSetCompletionRoutine (SubIrp
,
1355 CdromDeviceControlCompletion
,
1361 switch (IrpStack
->Parameters
.DeviceIoControl
.IoControlCode
)
1363 case IOCTL_CDROM_GET_DRIVE_GEOMETRY
:
1364 DPRINT ("CdromClassStartIo: IOCTL_CDROM_GET_DRIVE_GEOMETRY\n");
1365 Srb
->DataTransferLength
= sizeof(READ_CAPACITY_DATA
);
1366 Srb
->CdbLength
= 10;
1367 Srb
->TimeOutValue
= DeviceExtension
->TimeOutValue
;
1368 Srb
->SrbFlags
= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
| SRB_FLAGS_DATA_IN
;
1369 Cdb
->CDB10
.OperationCode
= SCSIOP_READ_CAPACITY
;
1371 /* Allocate data buffer */
1372 DataBuffer
= ExAllocatePool (NonPagedPoolCacheAligned
,
1373 sizeof(READ_CAPACITY_DATA
));
1374 if (DataBuffer
== NULL
)
1376 Irp
->IoStatus
.Information
= 0;
1377 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1378 IoCompleteRequest (Irp
,
1380 ExFreePool (SenseBuffer
);
1383 IoStartNextPacket (DeviceObject
,
1388 /* Allocate an MDL for the data buffer */
1389 SubIrp
->MdlAddress
= IoAllocateMdl (DataBuffer
,
1390 sizeof(READ_CAPACITY_DATA
),
1394 if (SubIrp
->MdlAddress
== NULL
)
1396 Irp
->IoStatus
.Information
= 0;
1397 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1398 IoCompleteRequest (Irp
,
1400 ExFreePool (DataBuffer
);
1401 ExFreePool (SenseBuffer
);
1404 IoStartNextPacket (DeviceObject
,
1409 MmBuildMdlForNonPagedPool (SubIrp
->MdlAddress
);
1410 Srb
->DataBuffer
= DataBuffer
;
1412 IoCallDriver (DeviceExtension
->PortDeviceObject
,
1416 case IOCTL_CDROM_CHECK_VERIFY
:
1417 DPRINT ("CdromClassStartIo: IOCTL_CDROM_CHECK_VERIFY\n");
1419 Srb
->TimeOutValue
= DeviceExtension
->TimeOutValue
* 2;
1420 Srb
->SrbFlags
= SRB_FLAGS_NO_DATA_TRANSFER
;
1421 Cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_TEST_UNIT_READY
;
1423 IoCallDriver (DeviceExtension
->PortDeviceObject
,
1428 IoCompleteRequest (Irp
,
1434 /* Call the SCSI port driver */
1435 IoCallDriver (DeviceExtension
->PortDeviceObject
,
1441 CdromDeviceControlCompletion (IN PDEVICE_OBJECT DeviceObject
,
1445 PDEVICE_EXTENSION DeviceExtension
;
1446 PDEVICE_EXTENSION PhysicalExtension
;
1447 PIO_STACK_LOCATION IrpStack
;
1448 PIO_STACK_LOCATION OrigCurrentIrpStack
;
1449 PIO_STACK_LOCATION OrigNextIrpStack
;
1450 PSCSI_REQUEST_BLOCK Srb
;
1455 DPRINT ("CdromDeviceControlCompletion() called\n");
1457 DeviceExtension
= (PDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
1458 PhysicalExtension
= (PDEVICE_EXTENSION
)DeviceExtension
->PhysicalDevice
->DeviceExtension
;
1459 Srb
= (PSCSI_REQUEST_BLOCK
) Context
;
1461 IrpStack
= IoGetCurrentIrpStackLocation (Irp
);
1463 /* Get the original IRP */
1464 OrigIrp
= (PIRP
)IrpStack
->Parameters
.Others
.Argument2
;
1465 OrigCurrentIrpStack
= IoGetCurrentIrpStackLocation (OrigIrp
);
1466 OrigNextIrpStack
= IoGetNextIrpStackLocation (OrigIrp
);
1468 if (SRB_STATUS(Srb
->SrbStatus
) == SRB_STATUS_SUCCESS
)
1470 Status
= STATUS_SUCCESS
;
1474 DPRINT ("SrbStatus %lx\n", Srb
->SrbStatus
);
1476 /* Interpret sense info */
1477 Retry
= ScsiClassInterpretSenseInfo (DeviceObject
,
1479 IrpStack
->MajorFunction
,
1480 IrpStack
->Parameters
.DeviceIoControl
.IoControlCode
,
1481 MAXIMUM_RETRIES
- (ULONG
)OrigNextIrpStack
->Parameters
.Others
.Argument1
,
1483 DPRINT ("Retry %u\n", Retry
);
1485 if (Retry
== TRUE
&&
1486 (ULONG
)OrigNextIrpStack
->Parameters
.Others
.Argument1
> 0)
1488 DPRINT1 ("Try again (Retry count 0x%p)\n",
1489 (ULONG
)OrigNextIrpStack
->Parameters
.Others
.Argument1
);
1491 OrigNextIrpStack
->Parameters
.Others
.Argument1
= (PVOID
)((ULONG_PTR
)OrigNextIrpStack
->Parameters
.Others
.Argument1
- 1);
1493 /* Release 'old' buffers */
1494 ExFreePool (Srb
->SenseInfoBuffer
);
1495 if (Srb
->DataBuffer
)
1496 ExFreePool(Srb
->DataBuffer
);
1499 if (Irp
->MdlAddress
!= NULL
)
1500 IoFreeMdl(Irp
->MdlAddress
);
1504 /* Call the StartIo routine again */
1505 CdromClassStartIo (DeviceObject
,
1508 return STATUS_MORE_PROCESSING_REQUIRED
;
1511 DPRINT ("Status %lx\n", Status
);
1514 if (NT_SUCCESS (Status
))
1516 switch (OrigCurrentIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
)
1518 case IOCTL_CDROM_GET_DRIVE_GEOMETRY
:
1520 PREAD_CAPACITY_DATA CapacityBuffer
;
1524 DPRINT ("CdromClassControlCompletion: IOCTL_CDROM_GET_DRIVE_GEOMETRY\n");
1526 CapacityBuffer
= (PREAD_CAPACITY_DATA
)Srb
->DataBuffer
;
1527 SectorSize
= (((PUCHAR
)&CapacityBuffer
->BytesPerBlock
)[0] << 24) |
1528 (((PUCHAR
)&CapacityBuffer
->BytesPerBlock
)[1] << 16) |
1529 (((PUCHAR
)&CapacityBuffer
->BytesPerBlock
)[2] << 8) |
1530 ((PUCHAR
)&CapacityBuffer
->BytesPerBlock
)[3];
1532 LastSector
= (((PUCHAR
)&CapacityBuffer
->LogicalBlockAddress
)[0] << 24) |
1533 (((PUCHAR
)&CapacityBuffer
->LogicalBlockAddress
)[1] << 16) |
1534 (((PUCHAR
)&CapacityBuffer
->LogicalBlockAddress
)[2] << 8) |
1535 ((PUCHAR
)&CapacityBuffer
->LogicalBlockAddress
)[3];
1537 if (SectorSize
== 0)
1539 DeviceExtension
->DiskGeometry
->BytesPerSector
= SectorSize
;
1541 DeviceExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(LastSector
+ 1);
1542 WHICH_BIT(DeviceExtension
->DiskGeometry
->BytesPerSector
,
1543 DeviceExtension
->SectorShift
);
1544 DeviceExtension
->PartitionLength
.QuadPart
=
1545 (DeviceExtension
->PartitionLength
.QuadPart
<< DeviceExtension
->SectorShift
);
1547 if (DeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)
1549 DeviceExtension
->DiskGeometry
->MediaType
= RemovableMedia
;
1553 DeviceExtension
->DiskGeometry
->MediaType
= FixedMedia
;
1555 DeviceExtension
->DiskGeometry
->Cylinders
.QuadPart
=
1556 (LONGLONG
)((LastSector
+ 1)/(32 * 64));
1557 DeviceExtension
->DiskGeometry
->SectorsPerTrack
= 32;
1558 DeviceExtension
->DiskGeometry
->TracksPerCylinder
= 64;
1560 RtlCopyMemory (OrigIrp
->AssociatedIrp
.SystemBuffer
,
1561 DeviceExtension
->DiskGeometry
,
1562 sizeof(DISK_GEOMETRY
));
1563 OrigIrp
->IoStatus
.Information
= sizeof(DISK_GEOMETRY
);
1567 case IOCTL_CDROM_CHECK_VERIFY
:
1568 DPRINT ("CdromDeviceControlCompletion: IOCTL_CDROM_CHECK_VERIFY\n");
1569 if (OrigCurrentIrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
!= 0)
1571 /* Return the media change counter */
1572 *((PULONG
)(OrigIrp
->AssociatedIrp
.SystemBuffer
)) =
1573 PhysicalExtension
->MediaChangeCount
;
1574 OrigIrp
->IoStatus
.Information
= sizeof(ULONG
);
1578 OrigIrp
->IoStatus
.Information
= 0;
1583 OrigIrp
->IoStatus
.Information
= 0;
1584 Status
= STATUS_INVALID_DEVICE_REQUEST
;
1589 /* Release the SRB and associated buffers */
1592 DPRINT("Srb %p\n", Srb
);
1594 if (Srb
->DataBuffer
!= NULL
)
1595 ExFreePool (Srb
->DataBuffer
);
1597 if (Srb
->SenseInfoBuffer
!= NULL
)
1598 ExFreePool (Srb
->SenseInfoBuffer
);
1603 if (OrigIrp
->PendingReturned
)
1605 IoMarkIrpPending (OrigIrp
);
1608 /* Release the MDL */
1609 if (Irp
->MdlAddress
!= NULL
)
1611 IoFreeMdl (Irp
->MdlAddress
);
1614 /* Release the sub irp */
1617 /* Set io status information */
1618 OrigIrp
->IoStatus
.Status
= Status
;
1619 if (!NT_SUCCESS(Status
) && IoIsErrorUserInduced (Status
))
1621 IoSetHardErrorOrVerifyDevice (OrigIrp
,
1623 OrigIrp
->IoStatus
.Information
= 0;
1626 /* Complete the original IRP */
1627 IoCompleteRequest (OrigIrp
,
1629 IoStartNextPacket (DeviceObject
,
1632 DPRINT ("CdromDeviceControlCompletion() done\n");
1634 return STATUS_MORE_PROCESSING_REQUIRED
;
1639 CdromTimerRoutine(IN PDEVICE_OBJECT DeviceObject
,
1642 PIO_WORKITEM WorkItem
;
1644 DPRINT ("CdromTimerRoutine() called\n");
1645 WorkItem
= IoAllocateWorkItem(DeviceObject
);
1651 IoQueueWorkItem(WorkItem
,
1659 CdromWorkItem(IN PDEVICE_OBJECT DeviceObject
,
1664 IO_STATUS_BLOCK IoStatus
;
1667 DPRINT("CdromWorkItem() called\n");
1669 IoFreeWorkItem((PIO_WORKITEM
) Context
);
1671 KeInitializeEvent(&Event
,
1675 Irp
= IoBuildDeviceIoControlRequest(IOCTL_CDROM_CHECK_VERIFY
,
1686 DPRINT("IoBuildDeviceIoControlRequest failed\n");
1690 Status
= IoCallDriver(DeviceObject
, Irp
);
1691 DPRINT("Status: %x\n", Status
);
1693 if (Status
== STATUS_PENDING
)
1695 KeWaitForSingleObject(&Event
,