Added default disk geometry.
[reactos.git] / reactos / drivers / storage / cdrom / cdrom.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2001, 2002 ReactOS Team
4 *
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.
9 *
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.
14 *
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.
18 */
19 /* $Id: cdrom.c,v 1.5 2002/03/22 20:32:36 ekohl Exp $
20 *
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)
26 */
27
28 /* INCLUDES *****************************************************************/
29
30 #include <ddk/ntddk.h>
31
32 #include "../include/scsi.h"
33 #include "../include/class2.h"
34 #include "../include/ntddscsi.h"
35
36 //#define NDEBUG
37 #include <debug.h>
38
39 #define VERSION "0.0.1"
40
41
42 typedef struct _CDROM_DATA
43 {
44 ULONG Dummy;
45 } CDROM_DATA, *PCDROM_DATA;
46
47
48
49 BOOLEAN STDCALL
50 CdromClassFindDevices(IN PDRIVER_OBJECT DriverObject,
51 IN PUNICODE_STRING RegistryPath,
52 IN PCLASS_INIT_DATA InitializationData,
53 IN PDEVICE_OBJECT PortDeviceObject,
54 IN ULONG PortNumber);
55
56 BOOLEAN STDCALL
57 CdromClassCheckDevice(IN PINQUIRYDATA InquiryData);
58
59 NTSTATUS STDCALL
60 CdromClassCheckReadWrite(IN PDEVICE_OBJECT DeviceObject,
61 IN PIRP Irp);
62
63 static NTSTATUS
64 CdromClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
65 IN PUNICODE_STRING RegistryPath, /* what's this used for? */
66 IN PDEVICE_OBJECT PortDeviceObject,
67 IN ULONG PortNumber,
68 IN ULONG DeviceNumber,
69 IN PIO_SCSI_CAPABILITIES Capabilities,
70 IN PSCSI_INQUIRY_DATA InquiryData,
71 IN PCLASS_INIT_DATA InitializationData);
72
73
74 NTSTATUS STDCALL
75 CdromClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
76 IN PIRP Irp);
77
78 NTSTATUS STDCALL
79 CdromClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject,
80 IN PIRP Irp);
81
82
83 /* FUNCTIONS ****************************************************************/
84
85 // DriverEntry
86 //
87 // DESCRIPTION:
88 // This function initializes the driver, locates and claims
89 // hardware resources, and creates various NT objects needed
90 // to process I/O requests.
91 //
92 // RUN LEVEL:
93 // PASSIVE_LEVEL
94 //
95 // ARGUMENTS:
96 // IN PDRIVER_OBJECT DriverObject System allocated Driver Object
97 // for this driver
98 // IN PUNICODE_STRING RegistryPath Name of registry driver service
99 // key
100 //
101 // RETURNS:
102 // NTSTATUS
103
104 NTSTATUS STDCALL
105 DriverEntry(IN PDRIVER_OBJECT DriverObject,
106 IN PUNICODE_STRING RegistryPath)
107 {
108 CLASS_INIT_DATA InitData;
109
110 DbgPrint("CD-ROM Class Driver %s\n",
111 VERSION);
112 DPRINT("RegistryPath '%wZ'\n",
113 RegistryPath);
114
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;
119
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;
128
129 return(ScsiClassInitialize(DriverObject,
130 RegistryPath,
131 &InitData));
132 }
133
134
135 // CdromClassFindDevices
136 //
137 // DESCRIPTION:
138 // This function searches for device that are attached to the given scsi port.
139 //
140 // RUN LEVEL:
141 // PASSIVE_LEVEL
142 //
143 // ARGUMENTS:
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
149 //
150 // RETURNS:
151 // TRUE: At least one disk drive was found
152 // FALSE: No disk drive found
153 //
154
155 BOOLEAN STDCALL
156 CdromClassFindDevices(IN PDRIVER_OBJECT DriverObject,
157 IN PUNICODE_STRING RegistryPath,
158 IN PCLASS_INIT_DATA InitializationData,
159 IN PDEVICE_OBJECT PortDeviceObject,
160 IN ULONG PortNumber)
161 {
162 PCONFIGURATION_INFORMATION ConfigInfo;
163 PIO_SCSI_CAPABILITIES PortCapabilities;
164 PSCSI_ADAPTER_BUS_INFO AdapterBusInfo;
165 PSCSI_INQUIRY_DATA UnitInfo;
166 PINQUIRYDATA InquiryData;
167 PCHAR Buffer;
168 ULONG Bus;
169 ULONG DeviceCount;
170 BOOLEAN FoundDevice;
171 NTSTATUS Status;
172
173 DPRINT("CdromClassFindDevices() called.\n");
174
175 /* Get port capabilities */
176 Status = ScsiClassGetCapabilities(PortDeviceObject,
177 &PortCapabilities);
178 if (!NT_SUCCESS(Status))
179 {
180 DPRINT1("ScsiClassGetCapabilities() failed! (Status 0x%lX)\n", Status);
181 return(FALSE);
182 }
183
184 DPRINT("MaximumTransferLength: %lu\n", PortCapabilities->MaximumTransferLength);
185
186 /* Get inquiry data */
187 Status = ScsiClassGetInquiryData(PortDeviceObject,
188 (PSCSI_ADAPTER_BUS_INFO *)&Buffer);
189 if (!NT_SUCCESS(Status))
190 {
191 DPRINT1("ScsiClassGetInquiryData() failed! (Status 0x%lX)\n", Status);
192 return(FALSE);
193 }
194
195 /* Check whether there are unclaimed devices */
196 AdapterBusInfo = (PSCSI_ADAPTER_BUS_INFO)Buffer;
197 DeviceCount = ScsiClassFindUnclaimedDevices(InitializationData,
198 AdapterBusInfo);
199 if (DeviceCount == 0)
200 {
201 DPRINT1("No unclaimed devices!\n");
202 return(FALSE);
203 }
204
205 DPRINT("Found %lu unclaimed devices!\n", DeviceCount);
206
207 ConfigInfo = IoGetConfigurationInformation();
208 DPRINT("Number of SCSI ports: %lu\n", ConfigInfo->ScsiPortCount);
209
210 /* Search each bus of this adapter */
211 for (Bus = 0; Bus < (ULONG)AdapterBusInfo->NumberOfBuses; Bus++)
212 {
213 DPRINT("Searching bus %lu\n", Bus);
214
215 UnitInfo = (PSCSI_INQUIRY_DATA)(Buffer + AdapterBusInfo->BusData[Bus].InquiryDataOffset);
216
217 while (AdapterBusInfo->BusData[Bus].InquiryDataOffset)
218 {
219 InquiryData = (PINQUIRYDATA)UnitInfo->InquiryData;
220
221 if ((InquiryData->DeviceType == READ_ONLY_DIRECT_ACCESS_DEVICE) &&
222 (InquiryData->DeviceTypeQualifier == 0) &&
223 (UnitInfo->DeviceClaimed == FALSE))
224 {
225 DPRINT("Vendor: '%.24s'\n",
226 InquiryData->VendorId);
227
228 /* Create device objects for disk */
229 Status = CdromClassCreateDeviceObject(DriverObject,
230 RegistryPath,
231 PortDeviceObject,
232 PortNumber,
233 ConfigInfo->CDRomCount,
234 PortCapabilities,
235 UnitInfo,
236 InitializationData);
237 if (NT_SUCCESS(Status))
238 {
239 ConfigInfo->CDRomCount++;
240 FoundDevice = TRUE;
241 }
242 }
243
244 if (UnitInfo->NextInquiryDataOffset == 0)
245 break;
246
247 UnitInfo = (PSCSI_INQUIRY_DATA)(Buffer + UnitInfo->NextInquiryDataOffset);
248 }
249 }
250
251 ExFreePool(Buffer);
252 ExFreePool(PortCapabilities);
253
254 DPRINT("CdromClassFindDevices() done\n");
255
256 return(TRUE);
257 }
258
259
260 /**********************************************************************
261 * NAME EXPORTED
262 * CdromClassCheckDevice
263 *
264 * DESCRIPTION
265 * This function checks the InquiryData for the correct device
266 * type and qualifier.
267 *
268 * RUN LEVEL
269 * PASSIVE_LEVEL
270 *
271 * ARGUMENTS
272 * InquiryData
273 * Pointer to the inquiry data for the device in question.
274 *
275 * RETURN VALUE
276 * TRUE: A disk device was found.
277 * FALSE: Otherwise.
278 */
279
280 BOOLEAN STDCALL
281 CdromClassCheckDevice(IN PINQUIRYDATA InquiryData)
282 {
283 return((InquiryData->DeviceType == READ_ONLY_DIRECT_ACCESS_DEVICE) &&
284 (InquiryData->DeviceTypeQualifier == 0));
285 }
286
287
288 /**********************************************************************
289 * NAME EXPORTED
290 * CdromClassCheckReadWrite
291 *
292 * DESCRIPTION
293 * This function checks the given IRP for correct data.
294 *
295 * RUN LEVEL
296 * PASSIVE_LEVEL
297 *
298 * ARGUMENTS
299 * DeviceObject
300 * Pointer to the device.
301 *
302 * Irp
303 * Irp to check.
304 *
305 * RETURN VALUE
306 * STATUS_SUCCESS: The IRP matches the requirements of the given device.
307 * Others: Failure.
308 */
309
310 NTSTATUS STDCALL
311 CdromClassCheckReadWrite(IN PDEVICE_OBJECT DeviceObject,
312 IN PIRP Irp)
313 {
314 DPRINT("CdromClassCheckReadWrite() called\n");
315
316 return(STATUS_SUCCESS);
317 }
318
319
320 // CdromClassCreateDeviceObject
321 //
322 // DESCRIPTION:
323 // Create the raw device and any partition devices on this drive
324 //
325 // RUN LEVEL:
326 // PASSIVE_LEVEL
327 //
328 // ARGUMENTS:
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
333 // this device
334 // IN int DriveIdx The index of the drive on this
335 // controller
336 // IN int HarddiskIdx The NT device number for this
337 // drive
338 //
339 // RETURNS:
340 // TRUE Drive exists and devices were created
341 // FALSE no devices were created for this device
342 //
343
344 static NTSTATUS
345 CdromClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
346 IN PUNICODE_STRING RegistryPath, /* what's this used for? */
347 IN PDEVICE_OBJECT PortDeviceObject,
348 IN ULONG PortNumber,
349 IN ULONG DeviceNumber,
350 IN PIO_SCSI_CAPABILITIES Capabilities,
351 IN PSCSI_INQUIRY_DATA InquiryData,
352 IN PCLASS_INIT_DATA InitializationData)
353 {
354 OBJECT_ATTRIBUTES ObjectAttributes;
355 UNICODE_STRING UnicodeDeviceDirName;
356 CHAR NameBuffer[80];
357 PDEVICE_OBJECT DiskDeviceObject;
358 PDEVICE_EXTENSION DiskDeviceExtension; /* defined in class2.h */
359 HANDLE Handle;
360 PCDROM_DATA CdromData;
361 NTSTATUS Status;
362
363 DPRINT("CdromClassCreateDeviceObject() called\n");
364
365 /* Claim the cdrom device */
366 Status = ScsiClassClaimDevice(PortDeviceObject,
367 InquiryData,
368 FALSE,
369 &PortDeviceObject);
370 if (!NT_SUCCESS(Status))
371 {
372 DbgPrint("Could not claim cdrom device\n");
373 return(Status);
374 }
375
376 /* Create cdrom device */
377 sprintf(NameBuffer,
378 "\\Device\\CdRom%lu",
379 DeviceNumber);
380
381 Status = ScsiClassCreateDeviceObject(DriverObject,
382 NameBuffer,
383 NULL,
384 &DiskDeviceObject,
385 InitializationData);
386 if (!NT_SUCCESS(Status))
387 {
388 DPRINT1("ScsiClassCreateDeviceObject() failed (Status %x)\n", Status);
389
390 /* Release (unclaim) the disk */
391 ScsiClassClaimDevice(PortDeviceObject,
392 InquiryData,
393 TRUE,
394 NULL);
395
396 return(Status);
397 }
398
399 DiskDeviceObject->Flags |= DO_DIRECT_IO;
400 DiskDeviceObject->Characteristics |= FILE_REMOVABLE_MEDIA;
401 DiskDeviceObject->StackSize = (CCHAR)PortDeviceObject->StackSize + 1;
402
403 if (PortDeviceObject->AlignmentRequirement > DiskDeviceObject->AlignmentRequirement)
404 {
405 DiskDeviceObject->AlignmentRequirement = PortDeviceObject->AlignmentRequirement;
406 }
407
408 DiskDeviceExtension = DiskDeviceObject->DeviceExtension;
409 DiskDeviceExtension->LockCount = 0;
410 DiskDeviceExtension->DeviceNumber = DeviceNumber;
411 DiskDeviceExtension->PortDeviceObject = PortDeviceObject;
412 DiskDeviceExtension->PhysicalDevice = DiskDeviceObject;
413
414 /* FIXME: Not yet! Will cause pointer corruption! */
415 // DiskDeviceExtension->PortCapabilities = PortCapabilities;
416
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;
422
423 /* zero-out disk data */
424 CdromData = (PCDROM_DATA)(DiskDeviceExtension + 1);
425 RtlZeroMemory(CdromData,
426 sizeof(CDROM_DATA));
427
428 /* Get disk geometry */
429 DiskDeviceExtension->DiskGeometry = ExAllocatePool(NonPagedPool,
430 sizeof(DISK_GEOMETRY));
431 if (DiskDeviceExtension->DiskGeometry == NULL)
432 {
433 DPRINT1("Failed to allocate geometry buffer!\n");
434
435 IoDeleteDevice(DiskDeviceObject);
436
437 /* Release (unclaim) the disk */
438 ScsiClassClaimDevice(PortDeviceObject,
439 InquiryData,
440 TRUE,
441 NULL);
442
443 return(STATUS_INSUFFICIENT_RESOURCES);
444 }
445
446 /* Read the drive's capacity */
447 Status = ScsiClassReadDriveCapacity(DiskDeviceObject);
448 if (!NT_SUCCESS(Status) ||
449 DiskDeviceExtension->DiskGeometry->BytesPerSector == 0)
450 {
451 /* Set ISO9660 defaults */
452 DiskDeviceExtension->DiskGeometry->BytesPerSector = 2048;
453 DiskDeviceExtension->SectorShift = 11;
454 DiskDeviceExtension->PartitionLength.QuadPart = (ULONGLONG)0x7fffffff;
455 }
456 else
457 {
458 /* Make sure the BytesPerSector value is a power of 2 */
459 // DiskDeviceExtension->DiskGeometry->BytesPerSector = 2048;
460 }
461
462 DPRINT("SectorSize: %lu\n", DiskDeviceExtension->DiskGeometry->BytesPerSector);
463
464 /* FIXME: initialize media change support */
465
466 DPRINT("CdromClassCreateDeviceObjects() done\n");
467
468 return(STATUS_SUCCESS);
469 }
470
471
472
473 // CdromClassDeviceControl
474 //
475 // DESCRIPTION:
476 // Answer requests for device control calls
477 //
478 // RUN LEVEL:
479 // PASSIVE_LEVEL
480 //
481 // ARGUMENTS:
482 // Standard dispatch arguments
483 //
484 // RETURNS:
485 // NTSTATUS
486 //
487
488 NTSTATUS STDCALL
489 CdromClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
490 IN PIRP Irp)
491 {
492 PDEVICE_EXTENSION DeviceExtension;
493 PIO_STACK_LOCATION IrpStack;
494 ULONG ControlCode, InputLength, OutputLength;
495 PCDROM_DATA CdromData;
496 ULONG Information;
497 NTSTATUS Status;
498
499 DPRINT("CdromClassDeviceControl() called!\n");
500
501 Status = STATUS_INVALID_DEVICE_REQUEST;
502 Information = 0;
503 IrpStack = IoGetCurrentIrpStackLocation(Irp);
504 ControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;
505 InputLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
506 OutputLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
507 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
508 CdromData = (PCDROM_DATA)(DeviceExtension + 1);
509
510 switch (ControlCode)
511 {
512 default:
513 DPRINT1("Unhandled control code: %lx\n", ControlCode);
514 Status = STATUS_INVALID_DEVICE_REQUEST;
515 Information = 0;
516 break;
517 }
518
519
520 Irp->IoStatus.Status = Status;
521 Irp->IoStatus.Information = Information;
522 IoCompleteRequest(Irp,
523 IO_NO_INCREMENT);
524
525 return(STATUS_SUCCESS);
526 }
527
528
529 // CdromClassShutdownFlush
530 //
531 // DESCRIPTION:
532 // Answer requests for shutdown and flush calls
533 //
534 // RUN LEVEL:
535 // PASSIVE_LEVEL
536 //
537 // ARGUMENTS:
538 // Standard dispatch arguments
539 //
540 // RETURNS:
541 // NTSTATUS
542 //
543
544 NTSTATUS STDCALL
545 CdromClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject,
546 IN PIRP Irp)
547 {
548 DPRINT("CdromClassShutdownFlush() called!\n");
549
550 Irp->IoStatus.Status = STATUS_SUCCESS;
551 Irp->IoStatus.Information = 0;
552 IoCompleteRequest(Irp, IO_NO_INCREMENT);
553
554 return(STATUS_SUCCESS);
555 }
556
557
558 /* EOF */