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.9 2002/05/25 13:29:58 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)
28 /* INCLUDES *****************************************************************/
30 #include <ddk/ntddk.h>
32 #include "../include/scsi.h"
33 #include "../include/class2.h"
34 #include "../include/ntddscsi.h"
39 #define VERSION "0.0.1"
42 typedef struct _CDROM_DATA
45 } CDROM_DATA
, *PCDROM_DATA
;
50 CdromClassFindDevices(IN PDRIVER_OBJECT DriverObject
,
51 IN PUNICODE_STRING RegistryPath
,
52 IN PCLASS_INIT_DATA InitializationData
,
53 IN PDEVICE_OBJECT PortDeviceObject
,
57 CdromClassCheckDevice(IN PINQUIRYDATA InquiryData
);
60 CdromClassCheckReadWrite(IN PDEVICE_OBJECT DeviceObject
,
64 CdromClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject
,
65 IN PUNICODE_STRING RegistryPath
, /* what's this used for? */
66 IN PDEVICE_OBJECT PortDeviceObject
,
68 IN ULONG DeviceNumber
,
69 IN PIO_SCSI_CAPABILITIES Capabilities
,
70 IN PSCSI_INQUIRY_DATA InquiryData
,
71 IN PCLASS_INIT_DATA InitializationData
);
75 CdromClassDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
79 CdromClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject
,
83 /* FUNCTIONS ****************************************************************/
88 // This function initializes the driver, locates and claims
89 // hardware resources, and creates various NT objects needed
90 // to process I/O requests.
96 // IN PDRIVER_OBJECT DriverObject System allocated Driver Object
98 // IN PUNICODE_STRING RegistryPath Name of registry driver service
105 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
106 IN PUNICODE_STRING RegistryPath
)
108 CLASS_INIT_DATA InitData
;
110 DbgPrint("CD-ROM Class Driver %s\n",
112 DPRINT("RegistryPath '%wZ'\n",
115 InitData
.InitializationDataSize
= sizeof(CLASS_INIT_DATA
);
116 InitData
.DeviceExtensionSize
= sizeof(DEVICE_EXTENSION
) + sizeof(CDROM_DATA
);
117 InitData
.DeviceType
= FILE_DEVICE_CD_ROM
;
118 InitData
.DeviceCharacteristics
= FILE_REMOVABLE_MEDIA
| FILE_READ_ONLY_DEVICE
;
120 InitData
.ClassError
= NULL
; // CdromClassProcessError;
121 InitData
.ClassReadWriteVerification
= CdromClassCheckReadWrite
;
122 InitData
.ClassFindDeviceCallBack
= CdromClassCheckDevice
;
123 InitData
.ClassFindDevices
= CdromClassFindDevices
;
124 InitData
.ClassDeviceControl
= CdromClassDeviceControl
;
125 InitData
.ClassShutdownFlush
= CdromClassShutdownFlush
;
126 InitData
.ClassCreateClose
= NULL
;
127 InitData
.ClassStartIo
= NULL
;
129 return(ScsiClassInitialize(DriverObject
,
135 // CdromClassFindDevices
138 // This function searches for device that are attached to the given scsi port.
144 // IN PDRIVER_OBJECT DriverObject System allocated Driver Object for this driver
145 // IN PUNICODE_STRING RegistryPath Name of registry driver service key
146 // IN PCLASS_INIT_DATA InitializationData Pointer to the main initialization data
147 // IN PDEVICE_OBJECT PortDeviceObject Scsi port device object
148 // IN ULONG PortNumber Port number
151 // TRUE: At least one disk drive was found
152 // FALSE: No disk drive found
156 CdromClassFindDevices(IN PDRIVER_OBJECT DriverObject
,
157 IN PUNICODE_STRING RegistryPath
,
158 IN PCLASS_INIT_DATA InitializationData
,
159 IN PDEVICE_OBJECT PortDeviceObject
,
162 PCONFIGURATION_INFORMATION ConfigInfo
;
163 PIO_SCSI_CAPABILITIES PortCapabilities
;
164 PSCSI_ADAPTER_BUS_INFO AdapterBusInfo
;
165 PSCSI_INQUIRY_DATA UnitInfo
;
166 PINQUIRYDATA InquiryData
;
173 DPRINT("CdromClassFindDevices() called.\n");
175 /* Get port capabilities */
176 Status
= ScsiClassGetCapabilities(PortDeviceObject
,
178 if (!NT_SUCCESS(Status
))
180 DPRINT1("ScsiClassGetCapabilities() failed! (Status 0x%lX)\n", Status
);
184 DPRINT("MaximumTransferLength: %lu\n", PortCapabilities
->MaximumTransferLength
);
186 /* Get inquiry data */
187 Status
= ScsiClassGetInquiryData(PortDeviceObject
,
188 (PSCSI_ADAPTER_BUS_INFO
*)&Buffer
);
189 if (!NT_SUCCESS(Status
))
191 DPRINT1("ScsiClassGetInquiryData() failed! (Status 0x%lX)\n", Status
);
195 /* Check whether there are unclaimed devices */
196 AdapterBusInfo
= (PSCSI_ADAPTER_BUS_INFO
)Buffer
;
197 DeviceCount
= ScsiClassFindUnclaimedDevices(InitializationData
,
199 if (DeviceCount
== 0)
201 DPRINT1("No unclaimed devices!\n");
205 DPRINT("Found %lu unclaimed devices!\n", DeviceCount
);
207 ConfigInfo
= IoGetConfigurationInformation();
208 DPRINT("Number of SCSI ports: %lu\n", ConfigInfo
->ScsiPortCount
);
210 /* Search each bus of this adapter */
211 for (Bus
= 0; Bus
< (ULONG
)AdapterBusInfo
->NumberOfBuses
; Bus
++)
213 DPRINT("Searching bus %lu\n", Bus
);
215 UnitInfo
= (PSCSI_INQUIRY_DATA
)(Buffer
+ AdapterBusInfo
->BusData
[Bus
].InquiryDataOffset
);
217 while (AdapterBusInfo
->BusData
[Bus
].InquiryDataOffset
)
219 InquiryData
= (PINQUIRYDATA
)UnitInfo
->InquiryData
;
221 if ((InquiryData
->DeviceType
== READ_ONLY_DIRECT_ACCESS_DEVICE
) &&
222 (InquiryData
->DeviceTypeQualifier
== 0) &&
223 (UnitInfo
->DeviceClaimed
== FALSE
))
225 DPRINT("Vendor: '%.24s'\n",
226 InquiryData
->VendorId
);
228 /* Create device objects for disk */
229 Status
= CdromClassCreateDeviceObject(DriverObject
,
233 ConfigInfo
->CDRomCount
,
237 if (NT_SUCCESS(Status
))
239 ConfigInfo
->CDRomCount
++;
244 if (UnitInfo
->NextInquiryDataOffset
== 0)
247 UnitInfo
= (PSCSI_INQUIRY_DATA
)(Buffer
+ UnitInfo
->NextInquiryDataOffset
);
252 ExFreePool(PortCapabilities
);
254 DPRINT("CdromClassFindDevices() done\n");
260 /**********************************************************************
262 * CdromClassCheckDevice
265 * This function checks the InquiryData for the correct device
266 * type and qualifier.
273 * Pointer to the inquiry data for the device in question.
276 * TRUE: A disk device was found.
281 CdromClassCheckDevice(IN PINQUIRYDATA InquiryData
)
283 return((InquiryData
->DeviceType
== READ_ONLY_DIRECT_ACCESS_DEVICE
) &&
284 (InquiryData
->DeviceTypeQualifier
== 0));
288 /**********************************************************************
290 * CdromClassCheckReadWrite
293 * This function checks the given IRP for correct data.
300 * Pointer to the device.
306 * STATUS_SUCCESS: The IRP matches the requirements of the given device.
311 CdromClassCheckReadWrite(IN PDEVICE_OBJECT DeviceObject
,
314 DPRINT("CdromClassCheckReadWrite() called\n");
316 return(STATUS_SUCCESS
);
320 // CdromClassCreateDeviceObject
323 // Create the raw device and any partition devices on this drive
329 // IN PDRIVER_OBJECT DriverObject The system created driver object
330 // IN PCONTROLLER_OBJECT ControllerObject
331 // IN PIDE_CONTROLLER_EXTENSION ControllerExtension
332 // The IDE controller extension for
334 // IN int DriveIdx The index of the drive on this
336 // IN int HarddiskIdx The NT device number for this
340 // TRUE Drive exists and devices were created
341 // FALSE no devices were created for this device
345 CdromClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject
,
346 IN PUNICODE_STRING RegistryPath
, /* what's this used for? */
347 IN PDEVICE_OBJECT PortDeviceObject
,
349 IN ULONG DeviceNumber
,
350 IN PIO_SCSI_CAPABILITIES Capabilities
,
351 IN PSCSI_INQUIRY_DATA InquiryData
,
352 IN PCLASS_INIT_DATA InitializationData
)
354 OBJECT_ATTRIBUTES ObjectAttributes
;
355 UNICODE_STRING UnicodeDeviceDirName
;
357 PDEVICE_OBJECT DiskDeviceObject
;
358 PDEVICE_EXTENSION DiskDeviceExtension
; /* defined in class2.h */
360 PCDROM_DATA CdromData
;
363 DPRINT("CdromClassCreateDeviceObject() called\n");
365 /* Claim the cdrom device */
366 Status
= ScsiClassClaimDevice(PortDeviceObject
,
370 if (!NT_SUCCESS(Status
))
372 DbgPrint("Could not claim cdrom device\n");
376 /* Create cdrom device */
378 "\\Device\\CdRom%lu",
381 Status
= ScsiClassCreateDeviceObject(DriverObject
,
386 if (!NT_SUCCESS(Status
))
388 DPRINT1("ScsiClassCreateDeviceObject() failed (Status %x)\n", Status
);
390 /* Release (unclaim) the disk */
391 ScsiClassClaimDevice(PortDeviceObject
,
399 DiskDeviceObject
->Flags
|= DO_DIRECT_IO
;
400 DiskDeviceObject
->Characteristics
|= FILE_REMOVABLE_MEDIA
;
401 DiskDeviceObject
->StackSize
= (CCHAR
)PortDeviceObject
->StackSize
+ 1;
403 if (PortDeviceObject
->AlignmentRequirement
> DiskDeviceObject
->AlignmentRequirement
)
405 DiskDeviceObject
->AlignmentRequirement
= PortDeviceObject
->AlignmentRequirement
;
408 DiskDeviceExtension
= DiskDeviceObject
->DeviceExtension
;
409 DiskDeviceExtension
->LockCount
= 0;
410 DiskDeviceExtension
->DeviceNumber
= DeviceNumber
;
411 DiskDeviceExtension
->PortDeviceObject
= PortDeviceObject
;
412 DiskDeviceExtension
->PhysicalDevice
= DiskDeviceObject
;
414 /* FIXME: Not yet! Will cause pointer corruption! */
415 // DiskDeviceExtension->PortCapabilities = PortCapabilities;
417 DiskDeviceExtension
->StartingOffset
.QuadPart
= 0;
418 DiskDeviceExtension
->PortNumber
= (UCHAR
)PortNumber
;
419 DiskDeviceExtension
->PathId
= InquiryData
->PathId
;
420 DiskDeviceExtension
->TargetId
= InquiryData
->TargetId
;
421 DiskDeviceExtension
->Lun
= InquiryData
->Lun
;
423 /* zero-out disk data */
424 CdromData
= (PCDROM_DATA
)(DiskDeviceExtension
+ 1);
425 RtlZeroMemory(CdromData
,
428 DiskDeviceExtension
->SenseData
= ExAllocatePool(NonPagedPool
,
430 if (DiskDeviceExtension
->SenseData
== NULL
)
432 DPRINT1("Failed to allocate sense data buffer!\n");
434 IoDeleteDevice(DiskDeviceObject
);
436 /* Release (unclaim) the disk */
437 ScsiClassClaimDevice(PortDeviceObject
,
442 return(STATUS_INSUFFICIENT_RESOURCES
);
445 /* Get disk geometry */
446 DiskDeviceExtension
->DiskGeometry
= ExAllocatePool(NonPagedPool
,
447 sizeof(DISK_GEOMETRY
));
448 if (DiskDeviceExtension
->DiskGeometry
== NULL
)
450 DPRINT1("Failed to allocate geometry buffer!\n");
452 IoDeleteDevice(DiskDeviceObject
);
454 /* Release (unclaim) the disk */
455 ScsiClassClaimDevice(PortDeviceObject
,
460 return(STATUS_INSUFFICIENT_RESOURCES
);
463 /* Read the drive's capacity */
464 Status
= ScsiClassReadDriveCapacity(DiskDeviceObject
);
465 if (!NT_SUCCESS(Status
) ||
466 DiskDeviceExtension
->DiskGeometry
->BytesPerSector
== 0)
468 /* Set ISO9660 defaults */
469 DiskDeviceExtension
->DiskGeometry
->BytesPerSector
= 2048;
470 DiskDeviceExtension
->DiskGeometry
->MediaType
= RemovableMedia
;
471 DiskDeviceExtension
->SectorShift
= 11;
472 DiskDeviceExtension
->PartitionLength
.QuadPart
= (ULONGLONG
)0x7fffffff;
476 /* Make sure the BytesPerSector value is a power of 2 */
477 // DiskDeviceExtension->DiskGeometry->BytesPerSector = 2048;
480 DPRINT("SectorSize: %lu\n", DiskDeviceExtension
->DiskGeometry
->BytesPerSector
);
482 /* FIXME: initialize media change support */
484 DPRINT("CdromClassCreateDeviceObjects() done\n");
486 return(STATUS_SUCCESS
);
491 // CdromClassDeviceControl
494 // Answer requests for device control calls
500 // Standard dispatch arguments
507 CdromClassDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
510 PDEVICE_EXTENSION DeviceExtension
;
511 PIO_STACK_LOCATION IrpStack
;
512 ULONG ControlCode
, InputLength
, OutputLength
;
513 PCDROM_DATA CdromData
;
517 DPRINT("CdromClassDeviceControl() called!\n");
519 Status
= STATUS_INVALID_DEVICE_REQUEST
;
521 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
522 ControlCode
= IrpStack
->Parameters
.DeviceIoControl
.IoControlCode
;
523 InputLength
= IrpStack
->Parameters
.DeviceIoControl
.InputBufferLength
;
524 OutputLength
= IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
525 DeviceExtension
= (PDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
526 CdromData
= (PCDROM_DATA
)(DeviceExtension
+ 1);
530 case IOCTL_CDROM_GET_DRIVE_GEOMETRY
:
531 DPRINT1("IOCTL_CDROM_GET_DRIVE_GEOMETRY\n");
532 if (IrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(DISK_GEOMETRY
))
534 Status
= STATUS_INVALID_PARAMETER
;
536 else if (DeviceExtension
->DiskGeometry
== NULL
)
538 DPRINT1("No cdrom geometry available!\n");
539 Status
= STATUS_NO_SUCH_DEVICE
;
543 PDISK_GEOMETRY Geometry
;
545 Geometry
= (PDISK_GEOMETRY
) Irp
->AssociatedIrp
.SystemBuffer
;
546 RtlMoveMemory(Geometry
,
547 DeviceExtension
->DiskGeometry
,
548 sizeof(DISK_GEOMETRY
));
550 Status
= STATUS_SUCCESS
;
551 Information
= sizeof(DISK_GEOMETRY
);
556 /* Call the common device control function */
557 return(ScsiClassDeviceControl(DeviceObject
, Irp
));
561 Irp
->IoStatus
.Status
= Status
;
562 Irp
->IoStatus
.Information
= Information
;
563 IoCompleteRequest(Irp
,
566 return(STATUS_SUCCESS
);
570 // CdromClassShutdownFlush
573 // Answer requests for shutdown and flush calls
579 // Standard dispatch arguments
586 CdromClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject
,
589 DPRINT("CdromClassShutdownFlush() called!\n");
591 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
592 Irp
->IoStatus
.Information
= 0;
593 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
595 return(STATUS_SUCCESS
);