Process IOCTL_CDROM_GET_DRIVE_GEOMETRY asynchronously.
[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.24 2003/11/07 17:14:22 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 /*
29 * TODO:
30 * - Add io timer routine for autorun support.
31 * - Add cdaudio support (cd player).
32 */
33
34 /* INCLUDES *****************************************************************/
35
36 #include <ddk/ntddk.h>
37 #include <ddk/scsi.h>
38 #include <ddk/class2.h>
39 #include <ddk/ntddscsi.h>
40
41 #define NDEBUG
42 #include <debug.h>
43
44 #define VERSION "0.0.1"
45
46
47 #define SCSI_CDROM_TIMEOUT 10 /* Default timeout: 10 seconds */
48
49
50 typedef struct _ERROR_RECOVERY_DATA6
51 {
52 MODE_PARAMETER_HEADER Header;
53 MODE_PARAMETER_BLOCK BlockDescriptor;
54 MODE_READ_RECOVERY_PAGE ReadRecoveryPage;
55 } ERROR_RECOVERY_DATA6, *PERROR_RECOVERY_DATA6;
56
57
58 typedef struct _ERROR_RECOVERY_DATA10
59 {
60 MODE_PARAMETER_HEADER10 Header;
61 MODE_PARAMETER_BLOCK BlockDescriptor;
62 MODE_READ_RECOVERY_PAGE ReadRecoveryPage;
63 } ERROR_RECOVERY_DATA10, *PERROR_RECOVERY_DATA10;
64
65
66 typedef struct _CDROM_DATA
67 {
68 BOOLEAN PlayActive;
69 BOOLEAN RawAccess;
70 USHORT XaFlags;
71
72 union
73 {
74 ERROR_RECOVERY_DATA6 Data6;
75 ERROR_RECOVERY_DATA10 Data10;
76 } RecoveryData;
77
78 } CDROM_DATA, *PCDROM_DATA;
79
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
85
86
87 BOOLEAN STDCALL
88 CdromClassFindDevices(IN PDRIVER_OBJECT DriverObject,
89 IN PUNICODE_STRING RegistryPath,
90 IN PCLASS_INIT_DATA InitializationData,
91 IN PDEVICE_OBJECT PortDeviceObject,
92 IN ULONG PortNumber);
93
94 BOOLEAN STDCALL
95 CdromClassCheckDevice(IN PINQUIRYDATA InquiryData);
96
97 NTSTATUS STDCALL
98 CdromClassCheckReadWrite(IN PDEVICE_OBJECT DeviceObject,
99 IN PIRP Irp);
100
101 static VOID
102 CdromClassCreateMediaChangeEvent(IN PDEVICE_EXTENSION DeviceExtension,
103 IN ULONG DeviceNumber);
104
105 static NTSTATUS
106 CdromClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
107 IN PUNICODE_STRING RegistryPath,
108 IN PDEVICE_OBJECT PortDeviceObject,
109 IN ULONG PortNumber,
110 IN ULONG DeviceNumber,
111 IN PIO_SCSI_CAPABILITIES Capabilities,
112 IN PSCSI_INQUIRY_DATA InquiryData,
113 IN PCLASS_INIT_DATA InitializationData);
114
115
116 NTSTATUS STDCALL
117 CdromClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
118 IN PIRP Irp);
119
120 VOID STDCALL
121 CdromClassStartIo (IN PDEVICE_OBJECT DeviceObject,
122 IN PIRP Irp);
123
124 NTSTATUS STDCALL
125 CdromDeviceControlCompletion (IN PDEVICE_OBJECT DeviceObject,
126 IN PIRP Irp,
127 IN PVOID Context);
128
129 VOID STDCALL
130 CdromTimerRoutine(IN PDEVICE_OBJECT DeviceObject,
131 IN PVOID Context);
132
133
134 /* FUNCTIONS ****************************************************************/
135
136 /**********************************************************************
137 * NAME EXPORTED
138 * DriverEntry
139 *
140 * DESCRIPTION:
141 * This function initializes the driver, locates and claims
142 * hardware resources, and creates various NT objects needed
143 * to process I/O requests.
144 *
145 * RUN LEVEL:
146 * PASSIVE_LEVEL
147 *
148 * ARGUMENTS:
149 * DriverObject
150 * System allocated Driver Object for this driver
151 * RegistryPath
152 * Name of registry driver service key
153 *
154 * RETURNS:
155 * Status.
156 */
157
158 NTSTATUS STDCALL
159 DriverEntry(IN PDRIVER_OBJECT DriverObject,
160 IN PUNICODE_STRING RegistryPath)
161 {
162 CLASS_INIT_DATA InitData;
163
164 DPRINT("CD-ROM Class Driver %s\n",
165 VERSION);
166 DPRINT("RegistryPath '%wZ'\n",
167 RegistryPath);
168
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;
173
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;
182
183 return(ScsiClassInitialize(DriverObject,
184 RegistryPath,
185 &InitData));
186 }
187
188
189 /**********************************************************************
190 * NAME EXPORTED
191 * CdromClassFindDevices
192 *
193 * DESCRIPTION:
194 * This function searches for device that are attached to the
195 * given scsi port.
196 *
197 * RUN LEVEL:
198 * PASSIVE_LEVEL
199 *
200 * ARGUMENTS:
201 * DriverObject
202 * System allocated Driver Object for this driver
203 * RegistryPath
204 * Name of registry driver service key.
205 * InitializationData
206 * Pointer to the main initialization data
207 * PortDeviceObject
208 * Scsi port device object
209 * PortNumber
210 * Port number
211 *
212 * RETURNS:
213 * TRUE: At least one disk drive was found
214 * FALSE: No disk drive found
215 */
216
217 BOOLEAN STDCALL
218 CdromClassFindDevices(IN PDRIVER_OBJECT DriverObject,
219 IN PUNICODE_STRING RegistryPath,
220 IN PCLASS_INIT_DATA InitializationData,
221 IN PDEVICE_OBJECT PortDeviceObject,
222 IN ULONG PortNumber)
223 {
224 PCONFIGURATION_INFORMATION ConfigInfo;
225 PIO_SCSI_CAPABILITIES PortCapabilities;
226 PSCSI_ADAPTER_BUS_INFO AdapterBusInfo;
227 PSCSI_INQUIRY_DATA UnitInfo;
228 PINQUIRYDATA InquiryData;
229 PCHAR Buffer;
230 ULONG Bus;
231 ULONG DeviceCount;
232 BOOLEAN FoundDevice;
233 NTSTATUS Status;
234
235 DPRINT("CdromClassFindDevices() called.\n");
236
237 /* Get port capabilities */
238 Status = ScsiClassGetCapabilities(PortDeviceObject,
239 &PortCapabilities);
240 if (!NT_SUCCESS(Status))
241 {
242 DPRINT1("ScsiClassGetCapabilities() failed! (Status 0x%lX)\n", Status);
243 return(FALSE);
244 }
245
246 DPRINT("PortCapabilities: %p\n", PortCapabilities);
247 DPRINT("MaximumTransferLength: %lu\n", PortCapabilities->MaximumTransferLength);
248 DPRINT("MaximumPhysicalPages: %lu\n", PortCapabilities->MaximumPhysicalPages);
249
250 /* Get inquiry data */
251 Status = ScsiClassGetInquiryData(PortDeviceObject,
252 (PSCSI_ADAPTER_BUS_INFO *)&Buffer);
253 if (!NT_SUCCESS(Status))
254 {
255 DPRINT1("ScsiClassGetInquiryData() failed! (Status 0x%lX)\n", Status);
256 return(FALSE);
257 }
258
259 /* Check whether there are unclaimed devices */
260 AdapterBusInfo = (PSCSI_ADAPTER_BUS_INFO)Buffer;
261 DeviceCount = ScsiClassFindUnclaimedDevices(InitializationData,
262 AdapterBusInfo);
263 if (DeviceCount == 0)
264 {
265 DPRINT("No unclaimed devices!\n");
266 return(FALSE);
267 }
268
269 DPRINT("Found %lu unclaimed devices!\n", DeviceCount);
270
271 ConfigInfo = IoGetConfigurationInformation();
272 DPRINT("Number of SCSI ports: %lu\n", ConfigInfo->ScsiPortCount);
273
274 /* Search each bus of this adapter */
275 for (Bus = 0; Bus < (ULONG)AdapterBusInfo->NumberOfBuses; Bus++)
276 {
277 DPRINT("Searching bus %lu\n", Bus);
278
279 UnitInfo = (PSCSI_INQUIRY_DATA)(Buffer + AdapterBusInfo->BusData[Bus].InquiryDataOffset);
280
281 while (AdapterBusInfo->BusData[Bus].InquiryDataOffset)
282 {
283 InquiryData = (PINQUIRYDATA)UnitInfo->InquiryData;
284
285 if ((InquiryData->DeviceType == READ_ONLY_DIRECT_ACCESS_DEVICE) &&
286 (InquiryData->DeviceTypeQualifier == 0) &&
287 (UnitInfo->DeviceClaimed == FALSE))
288 {
289 DPRINT("Vendor: '%.24s'\n",
290 InquiryData->VendorId);
291
292 /* Create device objects for disk */
293 Status = CdromClassCreateDeviceObject(DriverObject,
294 RegistryPath,
295 PortDeviceObject,
296 PortNumber,
297 ConfigInfo->CdRomCount,
298 PortCapabilities,
299 UnitInfo,
300 InitializationData);
301 if (NT_SUCCESS(Status))
302 {
303 ConfigInfo->CdRomCount++;
304 FoundDevice = TRUE;
305 }
306 }
307
308 if (UnitInfo->NextInquiryDataOffset == 0)
309 break;
310
311 UnitInfo = (PSCSI_INQUIRY_DATA)(Buffer + UnitInfo->NextInquiryDataOffset);
312 }
313 }
314
315 ExFreePool(Buffer);
316
317 DPRINT("CdromClassFindDevices() done\n");
318
319 return(FoundDevice);
320 }
321
322
323 /**********************************************************************
324 * NAME EXPORTED
325 * CdromClassCheckDevice
326 *
327 * DESCRIPTION
328 * This function checks the InquiryData for the correct device
329 * type and qualifier.
330 *
331 * RUN LEVEL
332 * PASSIVE_LEVEL
333 *
334 * ARGUMENTS
335 * InquiryData
336 * Pointer to the inquiry data for the device in question.
337 *
338 * RETURN VALUE
339 * TRUE: A disk device was found.
340 * FALSE: Otherwise.
341 */
342
343 BOOLEAN STDCALL
344 CdromClassCheckDevice(IN PINQUIRYDATA InquiryData)
345 {
346 return((InquiryData->DeviceType == READ_ONLY_DIRECT_ACCESS_DEVICE) &&
347 (InquiryData->DeviceTypeQualifier == 0));
348 }
349
350
351 /**********************************************************************
352 * NAME EXPORTED
353 * CdromClassCheckReadWrite
354 *
355 * DESCRIPTION
356 * This function checks the given IRP for correct data.
357 *
358 * RUN LEVEL
359 * PASSIVE_LEVEL
360 *
361 * ARGUMENTS
362 * DeviceObject
363 * Pointer to the device.
364 * Irp
365 * Irp to check.
366 *
367 * RETURN VALUE
368 * STATUS_SUCCESS: The IRP matches the requirements of the given device.
369 * Others: Failure.
370 */
371
372 NTSTATUS STDCALL
373 CdromClassCheckReadWrite(IN PDEVICE_OBJECT DeviceObject,
374 IN PIRP Irp)
375 {
376 DPRINT("CdromClassCheckReadWrite() called\n");
377
378 return(STATUS_SUCCESS);
379 }
380
381
382 static VOID
383 CdromClassCreateMediaChangeEvent(IN PDEVICE_EXTENSION DeviceExtension,
384 IN ULONG DeviceNumber)
385 {
386 WCHAR NameBuffer[MAX_PATH];
387 UNICODE_STRING Name;
388
389 swprintf (NameBuffer,
390 L"\\Device\\MediaChangeEvent%lu",
391 DeviceNumber);
392 RtlInitUnicodeString (&Name,
393 NameBuffer);
394
395 DeviceExtension->MediaChangeEvent =
396 IoCreateSynchronizationEvent (&Name,
397 &DeviceExtension->MediaChangeEventHandle);
398
399 KeClearEvent (DeviceExtension->MediaChangeEvent);
400 }
401
402
403 /**********************************************************************
404 * NAME EXPORTED
405 * CdromClassCreateDeviceObject
406 *
407 * DESCRIPTION:
408 * Create the raw device and any partition devices on this drive
409 *
410 * RUN LEVEL:
411 * PASSIVE_LEVEL
412 *
413 * ARGUMENTS:
414 * DriverObject
415 * System allocated Driver Object for this driver.
416 * RegistryPath
417 * Name of registry driver service key.
418 * PortDeviceObject
419 * PortNumber
420 * DeviceNumber
421 * Capabilities
422 * InquiryData
423 * InitializationData
424 *
425 * RETURNS:
426 * Status.
427 */
428
429 static NTSTATUS
430 CdromClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
431 IN PUNICODE_STRING RegistryPath,
432 IN PDEVICE_OBJECT PortDeviceObject,
433 IN ULONG PortNumber,
434 IN ULONG DeviceNumber,
435 IN PIO_SCSI_CAPABILITIES Capabilities,
436 IN PSCSI_INQUIRY_DATA InquiryData,
437 IN PCLASS_INIT_DATA InitializationData)
438 {
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;
445 CHAR NameBuffer[80];
446 HANDLE Handle;
447 PUCHAR Buffer;
448 ULONG Length;
449 PCDB Cdb;
450 NTSTATUS Status;
451
452 DPRINT("CdromClassCreateDeviceObject() called\n");
453
454 /* Claim the cdrom device */
455 Status = ScsiClassClaimDevice(PortDeviceObject,
456 InquiryData,
457 FALSE,
458 &PortDeviceObject);
459 if (!NT_SUCCESS(Status))
460 {
461 DbgPrint("Could not claim cdrom device\n");
462 return(Status);
463 }
464
465 /* Create cdrom device */
466 sprintf(NameBuffer,
467 "\\Device\\CdRom%lu",
468 DeviceNumber);
469
470 Status = ScsiClassCreateDeviceObject(DriverObject,
471 NameBuffer,
472 NULL,
473 &DiskDeviceObject,
474 InitializationData);
475 if (!NT_SUCCESS(Status))
476 {
477 DPRINT1("ScsiClassCreateDeviceObject() failed (Status %x)\n", Status);
478
479 /* Release (unclaim) the disk */
480 ScsiClassClaimDevice(PortDeviceObject,
481 InquiryData,
482 TRUE,
483 NULL);
484
485 return(Status);
486 }
487
488 DiskDeviceObject->Flags |= DO_DIRECT_IO;
489 DiskDeviceObject->Characteristics |= FILE_REMOVABLE_MEDIA;
490 DiskDeviceObject->StackSize = (CCHAR)PortDeviceObject->StackSize + 1;
491
492 if (PortDeviceObject->AlignmentRequirement > DiskDeviceObject->AlignmentRequirement)
493 {
494 DiskDeviceObject->AlignmentRequirement = PortDeviceObject->AlignmentRequirement;
495 }
496
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;
509
510 /* zero-out disk data */
511 CdromData = (PCDROM_DATA)(DiskDeviceExtension + 1);
512 RtlZeroMemory(CdromData,
513 sizeof(CDROM_DATA));
514
515 DiskDeviceExtension->SenseData = ExAllocatePool(NonPagedPool,
516 sizeof(SENSE_DATA));
517 if (DiskDeviceExtension->SenseData == NULL)
518 {
519 DPRINT1("Failed to allocate sense data buffer!\n");
520
521 IoDeleteDevice(DiskDeviceObject);
522
523 /* Release (unclaim) the disk */
524 ScsiClassClaimDevice(PortDeviceObject,
525 InquiryData,
526 TRUE,
527 NULL);
528
529 return(STATUS_INSUFFICIENT_RESOURCES);
530 }
531
532 /* Get timeout value */
533 DiskDeviceExtension->TimeOutValue =
534 ScsiClassQueryTimeOutRegistryValue(RegistryPath);
535 if (DiskDeviceExtension->TimeOutValue == 0)
536 DiskDeviceExtension->TimeOutValue = SCSI_CDROM_TIMEOUT;
537
538 /* Initialize lookaside list for SRBs */
539 ScsiClassInitializeSrbLookasideList(DiskDeviceExtension,
540 4);
541
542 /* Get disk geometry */
543 DiskDeviceExtension->DiskGeometry = ExAllocatePool(NonPagedPool,
544 sizeof(DISK_GEOMETRY));
545 if (DiskDeviceExtension->DiskGeometry == NULL)
546 {
547 DPRINT1("Failed to allocate geometry buffer!\n");
548
549 ExDeleteNPagedLookasideList(&DiskDeviceExtension->SrbLookasideListHead);
550
551 IoDeleteDevice(DiskDeviceObject);
552
553 /* Release (unclaim) the disk */
554 ScsiClassClaimDevice(PortDeviceObject,
555 InquiryData,
556 TRUE,
557 NULL);
558
559 return(STATUS_INSUFFICIENT_RESOURCES);
560 }
561
562 /* Read the drive's capacity */
563 Status = ScsiClassReadDriveCapacity(DiskDeviceObject);
564 if (!NT_SUCCESS(Status) ||
565 DiskDeviceExtension->DiskGeometry->BytesPerSector == 0)
566 {
567 /* Set ISO9660 defaults */
568 DiskDeviceExtension->DiskGeometry->BytesPerSector = 2048;
569 DiskDeviceExtension->DiskGeometry->MediaType = RemovableMedia;
570 DiskDeviceExtension->SectorShift = 11;
571 DiskDeviceExtension->PartitionLength.QuadPart = (ULONGLONG)0x7fffffff;
572 }
573 else
574 {
575 /* Make sure the BytesPerSector value is a power of 2 */
576 // DiskDeviceExtension->DiskGeometry->BytesPerSector = 2048;
577 }
578
579 DPRINT("SectorSize: %lu\n", DiskDeviceExtension->DiskGeometry->BytesPerSector);
580
581 /* Initialize media change support */
582 CdromClassCreateMediaChangeEvent (DiskDeviceExtension,
583 DeviceNumber);
584 if (DiskDeviceExtension->MediaChangeEvent != NULL)
585 {
586 DPRINT("Allocated media change event!\n");
587
588 /* FIXME: Allocate media change IRP and SRB */
589 }
590
591 /* Use 6 byte xa commands by default */
592 CdromData->XaFlags |= XA_USE_6_BYTE;
593
594 /* Read 'error recovery page' to get additional drive capabilities */
595 #if 0
596 Length = sizeof(MODE_READ_RECOVERY_PAGE) +
597 MODE_BLOCK_DESC_LENGTH +
598 MODE_HEADER_LENGTH;
599
600 RtlZeroMemory (&Srb,
601 sizeof(SCSI_REQUEST_BLOCK));
602 Srb.CdbLength = 6;
603 Srb.TimeOutValue = DiskDeviceExtension->TimeOutValue;
604
605 Cdb = (PCDB)Srb.Cdb;
606 Cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
607 Cdb->MODE_SENSE.PageCode = 0x01;
608 Cdb->MODE_SENSE.AllocationLength = (UCHAR)Length;
609
610 Buffer = ExAllocatePool (NonPagedPool,
611 sizeof(MODE_READ_RECOVERY_PAGE) +
612 MODE_BLOCK_DESC_LENGTH + MODE_HEADER_LENGTH10);
613 if (Buffer == NULL)
614 {
615 DPRINT1("Allocating recovery page buffer failed!\n");
616 return STATUS_INSUFFICIENT_RESOURCES;
617 }
618
619 Status = ScsiClassSendSrbSynchronous (DiskDeviceObject,
620 &Srb,
621 Buffer,
622 Length,
623 FALSE);
624 if (!NT_SUCCESS (Status))
625 {
626 DPRINT("MODE_SENSE(6) failed\n");
627
628 /* Try the 10 byte version */
629 Length = sizeof(MODE_READ_RECOVERY_PAGE) +
630 MODE_BLOCK_DESC_LENGTH +
631 MODE_HEADER_LENGTH10;
632
633 RtlZeroMemory (&Srb,
634 sizeof(SCSI_REQUEST_BLOCK));
635 Srb.CdbLength = 10;
636 Srb.TimeOutValue = DiskDeviceExtension->TimeOutValue;
637
638 Cdb = (PCDB)Srb.Cdb;
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);
643
644 Status = ScsiClassSendSrbSynchronous (DiskDeviceObject,
645 &Srb,
646 Buffer,
647 Length,
648 FALSE);
649 if (Status == STATUS_DATA_OVERRUN)
650 {
651 DPRINT1("Data overrun\n");
652
653 /* FIXME */
654 }
655 else if (NT_SUCCESS (Status))
656 {
657 DPRINT("Use 10 byte commands\n");
658 RtlCopyMemory (&CdromData->RecoveryData.Data10.Header,
659 Buffer,
660 sizeof (ERROR_RECOVERY_DATA10));
661 CdromData->RecoveryData.Data10.Header.ModeDataLength[0] = 0;
662 CdromData->RecoveryData.Data10.Header.ModeDataLength[1] = 0;
663
664 CdromData->XaFlags &= XA_USE_6_BYTE;
665 CdromData->XaFlags |= XA_USE_10_BYTE;
666 }
667 else
668 {
669 DPRINT("XA not supported\n");
670 CdromData->XaFlags |= XA_NOT_SUPPORTED;
671 }
672 }
673 else
674 {
675 DPRINT("Use 6 byte commands\n");
676 RtlCopyMemory (&CdromData->RecoveryData.Data6.Header,
677 Buffer,
678 sizeof (ERROR_RECOVERY_DATA6));
679 CdromData->RecoveryData.Data6.Header.ModeDataLength = 0;
680 }
681 ExFreePool (Buffer);
682 #endif
683
684 /* Initialize device timer */
685 IoInitializeTimer(DiskDeviceObject,
686 CdromTimerRoutine,
687 NULL);
688 IoStartTimer(DiskDeviceObject);
689
690 DPRINT("CdromClassCreateDeviceObjects() done\n");
691
692 return(STATUS_SUCCESS);
693 }
694
695
696 /**********************************************************************
697 * NAME
698 * CdromClassReadTocEntry
699 *
700 * ARGUMENTS:
701 * DeviceObject
702 * TrackNo
703 * Buffer
704 * Length
705 *
706 * RETURNS:
707 * Status.
708 */
709
710 static NTSTATUS
711 CdromClassReadTocEntry (PDEVICE_OBJECT DeviceObject,
712 UINT TrackNo,
713 PVOID Buffer,
714 UINT Length)
715 {
716 PDEVICE_EXTENSION DeviceExtension;
717 SCSI_REQUEST_BLOCK Srb;
718 PCDB Cdb;
719
720 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
721
722 RtlZeroMemory(&Srb, sizeof(SCSI_REQUEST_BLOCK));
723 Srb.CdbLength = 10;
724 Srb.TimeOutValue = DeviceExtension->TimeOutValue;
725
726 Cdb = (PCDB)Srb.Cdb;
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;
733
734 return(ScsiClassSendSrbSynchronous(DeviceObject,
735 &Srb,
736 Buffer,
737 Length,
738 FALSE));
739 }
740
741
742 static NTSTATUS
743 CdromClassReadLastSession (PDEVICE_OBJECT DeviceObject,
744 UINT TrackNo,
745 PVOID Buffer,
746 UINT Length)
747 {
748 PDEVICE_EXTENSION DeviceExtension;
749 SCSI_REQUEST_BLOCK Srb;
750 PCDB Cdb;
751
752 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
753
754 RtlZeroMemory(&Srb, sizeof(SCSI_REQUEST_BLOCK));
755 Srb.CdbLength = 10;
756 Srb.TimeOutValue = DeviceExtension->TimeOutValue;
757
758 Cdb = (PCDB)Srb.Cdb;
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;
765
766 return(ScsiClassSendSrbSynchronous(DeviceObject,
767 &Srb,
768 Buffer,
769 Length,
770 FALSE));
771 }
772
773
774 /**********************************************************************
775 * NAME EXPORTED
776 * CdromClassDeviceControl
777 *
778 * DESCRIPTION:
779 * Answer requests for device control calls
780 *
781 * RUN LEVEL:
782 * PASSIVE_LEVEL
783 *
784 * ARGUMENTS:
785 * DeviceObject
786 * Irp
787 * Standard dispatch arguments
788 *
789 * RETURNS:
790 * Status.
791 */
792
793 NTSTATUS STDCALL
794 CdromClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
795 IN PIRP Irp)
796 {
797 PDEVICE_EXTENSION DeviceExtension;
798 PIO_STACK_LOCATION IrpStack;
799 ULONG ControlCode, InputLength, OutputLength;
800 PCDROM_DATA CdromData;
801 ULONG Information;
802 NTSTATUS Status;
803
804 DPRINT("CdromClassDeviceControl() called!\n");
805
806 Status = STATUS_INVALID_DEVICE_REQUEST;
807 Information = 0;
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);
814
815 switch (ControlCode)
816 {
817 case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
818 DPRINT("IOCTL_CDROM_GET_DRIVE_GEOMETRY\n");
819 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_GEOMETRY))
820 {
821 Status = STATUS_INFO_LENGTH_MISMATCH;
822 break;
823 }
824 IoMarkIrpPending (Irp);
825 IoStartPacket (DeviceObject,
826 Irp,
827 NULL,
828 NULL);
829 return STATUS_PENDING;
830
831 case IOCTL_CDROM_CHECK_VERIFY:
832 DPRINT ("IOCTL_CDROM_CHECK_VERIFY\n");
833 if (OutputLength != 0 && OutputLength < sizeof (ULONG))
834 {
835 DPRINT1("Buffer too small\n");
836 Status = STATUS_BUFFER_TOO_SMALL;
837 break;
838 }
839 IoMarkIrpPending (Irp);
840 IoStartPacket (DeviceObject,
841 Irp,
842 NULL,
843 NULL);
844 return STATUS_PENDING;
845
846 case IOCTL_CDROM_READ_TOC:
847 DPRINT("IOCTL_CDROM_READ_TOC\n");
848 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(CDROM_TOC))
849 {
850 Status = STATUS_INFO_LENGTH_MISMATCH;
851 }
852 else
853 {
854 PCDROM_TOC TocBuffer;
855 USHORT Length;
856
857 TocBuffer = Irp->AssociatedIrp.SystemBuffer;
858
859 /* First read the lead out */
860 Length = 4 + sizeof(TRACK_DATA);
861 Status = CdromClassReadTocEntry(DeviceObject,
862 0xAA,
863 TocBuffer,
864 Length);
865 if (NT_SUCCESS(Status))
866 {
867 if (TocBuffer->FirstTrack == 0xaa)
868 {
869 /* there is an empty cd */
870 Information = Length;
871 }
872 else
873 {
874 /* read the toc */
875 Length = 4 + sizeof(TRACK_DATA) * (TocBuffer->LastTrack - TocBuffer->FirstTrack + 2);
876 Status = CdromClassReadTocEntry(DeviceObject,
877 TocBuffer->FirstTrack,
878 TocBuffer, Length);
879 if (NT_SUCCESS(Status))
880 {
881 Information = Length;
882 }
883 }
884 }
885 }
886 break;
887
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))
891 {
892 Status = STATUS_INFO_LENGTH_MISMATCH;
893 }
894 else
895 {
896 PCDROM_TOC TocBuffer;
897 USHORT Length;
898
899 TocBuffer = Irp->AssociatedIrp.SystemBuffer;
900 Length = 4 + sizeof(TRACK_DATA);
901 Status = CdromClassReadLastSession(DeviceObject,
902 0,
903 TocBuffer,
904 Length);
905 if (NT_SUCCESS(Status))
906 {
907 Information = Length;
908 }
909 }
910 break;
911
912 default:
913 /* Call the common device control function */
914 return(ScsiClassDeviceControl(DeviceObject, Irp));
915 }
916
917 /* Verify the device if the user caused the error */
918 if (!NT_SUCCESS(Status) && IoIsErrorUserInduced(Status))
919 {
920 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
921 }
922
923 Irp->IoStatus.Status = Status;
924 Irp->IoStatus.Information = Information;
925 IoCompleteRequest(Irp,
926 IO_DISK_INCREMENT);
927
928 return Status;
929 }
930
931
932 /**********************************************************************
933 * NAME
934 * CdromClassStartIo
935 *
936 * DESCRIPTION:
937 * Starts IRP processing.
938 *
939 * RUN LEVEL:
940 * PASSIVE_LEVEL
941 *
942 * ARGUMENTS:
943 * DeviceObject
944 * Irp
945 * Standard dispatch arguments
946 *
947 * RETURNS:
948 * None.
949 */
950 VOID STDCALL
951 CdromClassStartIo (IN PDEVICE_OBJECT DeviceObject,
952 IN PIRP Irp)
953 {
954 PDEVICE_EXTENSION DeviceExtension;
955 PIO_STACK_LOCATION IrpStack;
956 PIO_STACK_LOCATION SubIrpStack;
957 ULONG MaximumTransferLength;
958 ULONG TransferPages;
959 PSCSI_REQUEST_BLOCK Srb;
960 PIRP SubIrp;
961 PUCHAR SenseBuffer;
962 PVOID DataBuffer;
963 PCDB Cdb;
964
965 DPRINT("CdromClassStartIo() called!\n");
966
967 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
968 IrpStack = IoGetCurrentIrpStackLocation (Irp);
969
970 MaximumTransferLength = DeviceExtension->PortCapabilities->MaximumTransferLength;
971
972 if (IrpStack->MajorFunction == IRP_MJ_READ)
973 {
974 DPRINT ("CdromClassStartIo: IRP_MJ_READ\n");
975
976 TransferPages =
977 ADDRESS_AND_SIZE_TO_SPAN_PAGES (MmGetMdlVirtualAddress(Irp->MdlAddress),
978 IrpStack->Parameters.Read.Length);
979
980 /* Check transfer size */
981 if ((IrpStack->Parameters.Read.Length > MaximumTransferLength) ||
982 (TransferPages > DeviceExtension->PortCapabilities->MaximumPhysicalPages))
983 {
984 /* Transfer size is too large - split it */
985 TransferPages =
986 DeviceExtension->PortCapabilities->MaximumPhysicalPages - 1;
987
988 /* Adjust transfer size */
989 if (MaximumTransferLength > TransferPages * PAGE_SIZE)
990 MaximumTransferLength = TransferPages * PAGE_SIZE;
991
992 if (MaximumTransferLength == 0)
993 MaximumTransferLength = PAGE_SIZE;
994
995 /* Split the transfer */
996 ScsiClassSplitRequest (DeviceObject,
997 Irp,
998 MaximumTransferLength);
999 return;
1000 }
1001 else
1002 {
1003 /* Build SRB */
1004 ScsiClassBuildRequest (DeviceObject,
1005 Irp);
1006 }
1007 }
1008 else if (IrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL)
1009 {
1010 DPRINT ("CdromClassStartIo: IRP_MJ_IRP_MJ_DEVICE_CONTROL\n");
1011
1012 /* Allocate an IRP for sending requests to the port driver */
1013 SubIrp = IoAllocateIrp ((CCHAR)(DeviceObject->StackSize + 1),
1014 FALSE);
1015 if (SubIrp == NULL)
1016 {
1017 Irp->IoStatus.Information = 0;
1018 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1019 IoCompleteRequest (Irp,
1020 IO_DISK_INCREMENT);
1021 IoStartNextPacket (DeviceObject,
1022 FALSE);
1023 return;
1024 }
1025
1026 /* Allocate an SRB */
1027 Srb = ExAllocatePool (NonPagedPool,
1028 sizeof (SCSI_REQUEST_BLOCK));
1029 if (Srb == NULL)
1030 {
1031 IoFreeIrp (SubIrp);
1032 Irp->IoStatus.Information = 0;
1033 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1034 IoCompleteRequest (Irp,
1035 IO_DISK_INCREMENT);
1036 IoStartNextPacket (DeviceObject,
1037 FALSE);
1038 return;
1039 }
1040
1041 /* Allocte a sense buffer */
1042 SenseBuffer = ExAllocatePool (NonPagedPoolCacheAligned,
1043 SENSE_BUFFER_SIZE);
1044 if (SenseBuffer == NULL)
1045 {
1046 ExFreePool (Srb);
1047 IoFreeIrp (SubIrp);
1048 Irp->IoStatus.Information = 0;
1049 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1050 IoCompleteRequest (Irp,
1051 IO_DISK_INCREMENT);
1052 IoStartNextPacket (DeviceObject,
1053 FALSE);
1054 return;
1055 }
1056
1057 /* Initialize the IRP */
1058 IoSetNextIrpStackLocation (SubIrp);
1059 SubIrp->IoStatus.Information = 0;
1060 SubIrp->IoStatus.Status = STATUS_SUCCESS;
1061 SubIrp->Flags = 0;
1062 SubIrp->UserBuffer = NULL;
1063
1064 SubIrpStack = IoGetCurrentIrpStackLocation (SubIrp);
1065 SubIrpStack->DeviceObject = DeviceExtension->DeviceObject;
1066 SubIrpStack->Parameters.Others.Argument2 = (PVOID)Irp;
1067
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;
1073
1074 /* Initialize the SRB */
1075 RtlZeroMemory(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;
1084 Srb->NextSrb = 0;
1085 Srb->OriginalRequest = SubIrp;
1086 Srb->SenseInfoBuffer = SenseBuffer;
1087 Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
1088
1089 /* Initialize the CDB */
1090 Cdb = (PCDB)Srb->Cdb;
1091
1092 /* Set the completion routine */
1093 IoSetCompletionRoutine (SubIrp,
1094 CdromDeviceControlCompletion,
1095 Srb,
1096 TRUE,
1097 TRUE,
1098 TRUE);
1099
1100 switch (IrpStack->Parameters.DeviceIoControl.IoControlCode)
1101 {
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;
1108
1109 /* Allocate data buffer */
1110 DataBuffer = ExAllocatePool (NonPagedPoolCacheAligned,
1111 sizeof(READ_CAPACITY_DATA));
1112 if (DataBuffer == NULL)
1113 {
1114 Irp->IoStatus.Information = 0;
1115 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1116 IoCompleteRequest (Irp,
1117 IO_DISK_INCREMENT);
1118 ExFreePool (SenseBuffer);
1119 ExFreePool (Srb);
1120 IoFreeIrp (SubIrp);
1121 IoStartNextPacket (DeviceObject,
1122 FALSE);
1123 return;
1124 }
1125
1126 /* Allocate an MDL for the data buffer */
1127 SubIrp->MdlAddress = IoAllocateMdl (DataBuffer,
1128 sizeof(READ_CAPACITY_DATA),
1129 FALSE,
1130 FALSE,
1131 NULL);
1132 if (SubIrp->MdlAddress == NULL)
1133 {
1134 Irp->IoStatus.Information = 0;
1135 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1136 IoCompleteRequest (Irp,
1137 IO_DISK_INCREMENT);
1138 ExFreePool (DataBuffer);
1139 ExFreePool (SenseBuffer);
1140 ExFreePool (Srb);
1141 IoFreeIrp (SubIrp);
1142 IoStartNextPacket (DeviceObject,
1143 FALSE);
1144 return;
1145 }
1146
1147 MmBuildMdlForNonPagedPool (SubIrp->MdlAddress);
1148 Srb->DataBuffer = DataBuffer;
1149 Cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
1150
1151 IoCallDriver (DeviceExtension->PortDeviceObject,
1152 SubIrp);
1153 return;
1154
1155 case IOCTL_CDROM_CHECK_VERIFY:
1156 DPRINT ("CdromClassStartIo: IOCTL_CDROM_CHECK_VERIFY\n");
1157 Srb->CdbLength = 6;
1158 Srb->TimeOutValue = DeviceExtension->TimeOutValue * 2;
1159 Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;
1160 Cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
1161
1162 IoCallDriver (DeviceExtension->PortDeviceObject,
1163 SubIrp);
1164 return;
1165
1166 default:
1167 IoCompleteRequest (Irp,
1168 IO_NO_INCREMENT);
1169 return;
1170 }
1171 }
1172
1173 /* Call the SCSI port driver */
1174 IoCallDriver (DeviceExtension->PortDeviceObject,
1175 Irp);
1176 }
1177
1178
1179 NTSTATUS STDCALL
1180 CdromDeviceControlCompletion (IN PDEVICE_OBJECT DeviceObject,
1181 IN PIRP Irp,
1182 IN PVOID Context)
1183 {
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;
1190 PIRP OrigIrp;
1191 BOOLEAN Retry;
1192 NTSTATUS Status;
1193
1194 DPRINT ("CdromDeviceControlCompletion() called\n");
1195
1196 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
1197 PhysicalExtension = (PDEVICE_EXTENSION)DeviceExtension->PhysicalDevice->DeviceExtension;
1198 Srb = (PSCSI_REQUEST_BLOCK) Context;
1199
1200 IrpStack = IoGetCurrentIrpStackLocation (Irp);
1201
1202 /* Get the original IRP */
1203 OrigIrp = (PIRP)IrpStack->Parameters.Others.Argument2;
1204 OrigCurrentIrpStack = IoGetCurrentIrpStackLocation (OrigIrp);
1205 OrigNextIrpStack = IoGetNextIrpStackLocation (OrigIrp);
1206
1207 if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS)
1208 {
1209 Status = STATUS_SUCCESS;
1210 }
1211 else
1212 {
1213 DPRINT ("SrbStatus %lx\n", Srb->SrbStatus);
1214
1215 /* Interpret sense info */
1216 Retry = ScsiClassInterpretSenseInfo (DeviceObject,
1217 Srb,
1218 IrpStack->MajorFunction,
1219 IrpStack->Parameters.DeviceIoControl.IoControlCode,
1220 MAXIMUM_RETRIES - (ULONG)OrigNextIrpStack->Parameters.Others.Argument1,
1221 &Status);
1222 DPRINT ("Retry %u\n", Retry);
1223
1224
1225 DPRINT ("Status %lx\n", Status);
1226 }
1227
1228 if (NT_SUCCESS (Status))
1229 {
1230 switch (OrigCurrentIrpStack->Parameters.DeviceIoControl.IoControlCode)
1231 {
1232 case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
1233 {
1234 PREAD_CAPACITY_DATA CapacityBuffer;
1235 ULONG LastSector;
1236 ULONG SectorSize;
1237
1238 DPRINT1 ("CdromClassControlCompletion: IOCTL_CDROM_GET_DRIVE_GEOMETRY\n");
1239
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];
1245
1246 LastSector = (((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[0] << 24) |
1247 (((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[1] << 16) |
1248 (((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[2] << 8) |
1249 ((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[3];
1250
1251 if (SectorSize == 0)
1252 SectorSize = 2048;
1253 DeviceExtension->DiskGeometry->BytesPerSector = SectorSize;
1254
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);
1260
1261 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
1262 {
1263 DeviceExtension->DiskGeometry->MediaType = RemovableMedia;
1264 }
1265 else
1266 {
1267 DeviceExtension->DiskGeometry->MediaType = FixedMedia;
1268 }
1269 DeviceExtension->DiskGeometry->Cylinders.QuadPart =
1270 (LONGLONG)((LastSector + 1)/(32 * 64));
1271 DeviceExtension->DiskGeometry->SectorsPerTrack = 32;
1272 DeviceExtension->DiskGeometry->TracksPerCylinder = 64;
1273
1274 RtlCopyMemory (OrigIrp->AssociatedIrp.SystemBuffer,
1275 DeviceExtension->DiskGeometry,
1276 sizeof(DISK_GEOMETRY));
1277 OrigIrp->IoStatus.Information = sizeof(DISK_GEOMETRY);
1278 }
1279 break;
1280
1281 case IOCTL_CDROM_CHECK_VERIFY:
1282 DPRINT ("CdromDeviceControlCompletion: IOCTL_CDROM_CHECK_VERIFY\n");
1283 if (OrigCurrentIrpStack->Parameters.DeviceIoControl.OutputBufferLength != 0)
1284 {
1285 /* Return the media change counter */
1286 *((PULONG)(OrigIrp->AssociatedIrp.SystemBuffer)) =
1287 PhysicalExtension->MediaChangeCount;
1288 OrigIrp->IoStatus.Information = sizeof(ULONG);
1289 }
1290 else
1291 {
1292 OrigIrp->IoStatus.Information = 0;
1293 }
1294 break;
1295
1296
1297 default:
1298 OrigIrp->IoStatus.Information = 0;
1299 Status = STATUS_INVALID_DEVICE_REQUEST;
1300 break;
1301 }
1302 }
1303
1304 /* Release the SRB and associated buffers */
1305 if (Srb != NULL)
1306 {
1307 DPRINT("Srb %p\n", Srb);
1308
1309 if (Srb->DataBuffer != NULL)
1310 ExFreePool (Srb->DataBuffer);
1311
1312 if (Srb->SenseInfoBuffer != NULL)
1313 ExFreePool (Srb->SenseInfoBuffer);
1314
1315 ExFreePool (Srb);
1316 }
1317
1318 if (OrigIrp->PendingReturned)
1319 {
1320 IoMarkIrpPending (OrigIrp);
1321 }
1322
1323 /* Release the MDL */
1324 if (Irp->MdlAddress != NULL)
1325 {
1326 IoFreeMdl (Irp->MdlAddress);
1327 }
1328
1329 /* Release the sub irp */
1330 IoFreeIrp (Irp);
1331
1332 /* Set io status information */
1333 OrigIrp->IoStatus.Status = Status;
1334 if (!NT_SUCCESS(Status) && IoIsErrorUserInduced (Status))
1335 {
1336 IoSetHardErrorOrVerifyDevice (OrigIrp,
1337 DeviceObject);
1338 OrigIrp->IoStatus.Information = 0;
1339 }
1340
1341 /* Complete the original IRP */
1342 IoCompleteRequest (OrigIrp,
1343 IO_DISK_INCREMENT);
1344 IoStartNextPacket (DeviceObject,
1345 FALSE);
1346
1347 DPRINT ("CdromDeviceControlCompletion() done\n");
1348
1349 return STATUS_MORE_PROCESSING_REQUIRED;
1350 }
1351
1352
1353 VOID STDCALL
1354 CdromTimerRoutine(PDEVICE_OBJECT DeviceObject,
1355 PVOID Context)
1356 {
1357 DPRINT ("CdromTimerRoutine() called\n");
1358
1359 }
1360
1361 /* EOF */