update for HEAD-2003021201
[reactos.git] / 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$
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 typedef struct _CDROM_DATA
48 {
49   ULONG Dummy;
50 } CDROM_DATA, *PCDROM_DATA;
51
52
53
54 BOOLEAN STDCALL
55 CdromClassFindDevices(IN PDRIVER_OBJECT DriverObject,
56                       IN PUNICODE_STRING RegistryPath,
57                       IN PCLASS_INIT_DATA InitializationData,
58                       IN PDEVICE_OBJECT PortDeviceObject,
59                       IN ULONG PortNumber);
60
61 BOOLEAN STDCALL
62 CdromClassCheckDevice(IN PINQUIRYDATA InquiryData);
63
64 NTSTATUS STDCALL
65 CdromClassCheckReadWrite(IN PDEVICE_OBJECT DeviceObject,
66                          IN PIRP Irp);
67
68 static NTSTATUS
69 CdromClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
70                              IN PUNICODE_STRING RegistryPath,
71                              IN PDEVICE_OBJECT PortDeviceObject,
72                              IN ULONG PortNumber,
73                              IN ULONG DeviceNumber,
74                              IN PIO_SCSI_CAPABILITIES Capabilities,
75                              IN PSCSI_INQUIRY_DATA InquiryData,
76                              IN PCLASS_INIT_DATA InitializationData);
77
78
79 NTSTATUS STDCALL
80 CdromClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
81                         IN PIRP Irp);
82
83 NTSTATUS STDCALL
84 CdromClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject,
85                         IN PIRP Irp);
86
87 VOID STDCALL
88 CdromTimerRoutine(IN PDEVICE_OBJECT DeviceObject,
89                   IN PVOID Context);
90
91
92 /* FUNCTIONS ****************************************************************/
93
94 /**********************************************************************
95  * NAME                                                 EXPORTED
96  *      DriverEntry
97  *
98  * DESCRIPTION:
99  *      This function initializes the driver, locates and claims 
100  *      hardware resources, and creates various NT objects needed
101  *      to process I/O requests.
102  *
103  * RUN LEVEL:
104  *      PASSIVE_LEVEL
105  *
106  * ARGUMENTS:
107  *      DriverObject
108  *              System allocated Driver Object for this driver
109  *      RegistryPath
110  *              Name of registry driver service key
111  *
112  * RETURNS:
113  *      Status.
114  */
115
116 NTSTATUS STDCALL
117 DriverEntry(IN PDRIVER_OBJECT DriverObject,
118             IN PUNICODE_STRING RegistryPath)
119 {
120   CLASS_INIT_DATA InitData;
121
122   DPRINT("CD-ROM Class Driver %s\n",
123          VERSION);
124   DPRINT("RegistryPath '%wZ'\n",
125          RegistryPath);
126
127   InitData.InitializationDataSize = sizeof(CLASS_INIT_DATA);
128   InitData.DeviceExtensionSize = sizeof(DEVICE_EXTENSION) + sizeof(CDROM_DATA);
129   InitData.DeviceType = FILE_DEVICE_CD_ROM;
130   InitData.DeviceCharacteristics = FILE_REMOVABLE_MEDIA | FILE_READ_ONLY_DEVICE;
131
132   InitData.ClassError = NULL;   // CdromClassProcessError;
133   InitData.ClassReadWriteVerification = CdromClassCheckReadWrite;
134   InitData.ClassFindDeviceCallBack = CdromClassCheckDevice;
135   InitData.ClassFindDevices = CdromClassFindDevices;
136   InitData.ClassDeviceControl = CdromClassDeviceControl;
137   InitData.ClassShutdownFlush = CdromClassShutdownFlush;
138   InitData.ClassCreateClose = NULL;
139   InitData.ClassStartIo = NULL;
140
141   return(ScsiClassInitialize(DriverObject,
142                              RegistryPath,
143                              &InitData));
144 }
145
146
147 /**********************************************************************
148  * NAME                                                 EXPORTED
149  *      CdromClassFindDevices
150  *
151  * DESCRIPTION:
152  *      This function searches for device that are attached to the
153  *      given scsi port.
154  *
155  * RUN LEVEL:
156  *      PASSIVE_LEVEL
157  *
158  * ARGUMENTS:
159  *      DriverObject
160  *              System allocated Driver Object for this driver
161  *      RegistryPath
162  *              Name of registry driver service key.
163  *      InitializationData
164  *              Pointer to the main initialization data
165  *      PortDeviceObject
166  *              Scsi port device object
167  *      PortNumber
168  *              Port number
169  *
170  * RETURNS:
171  *      TRUE: At least one disk drive was found
172  *      FALSE: No disk drive found
173  */
174
175 BOOLEAN STDCALL
176 CdromClassFindDevices(IN PDRIVER_OBJECT DriverObject,
177                       IN PUNICODE_STRING RegistryPath,
178                       IN PCLASS_INIT_DATA InitializationData,
179                       IN PDEVICE_OBJECT PortDeviceObject,
180                       IN ULONG PortNumber)
181 {
182   PCONFIGURATION_INFORMATION ConfigInfo;
183   PIO_SCSI_CAPABILITIES PortCapabilities;
184   PSCSI_ADAPTER_BUS_INFO AdapterBusInfo;
185   PSCSI_INQUIRY_DATA UnitInfo;
186   PINQUIRYDATA InquiryData;
187   PCHAR Buffer;
188   ULONG Bus;
189   ULONG DeviceCount;
190   BOOLEAN FoundDevice;
191   NTSTATUS Status;
192
193   DPRINT("CdromClassFindDevices() called.\n");
194
195   /* Get port capabilities */
196   Status = ScsiClassGetCapabilities(PortDeviceObject,
197                                     &PortCapabilities);
198   if (!NT_SUCCESS(Status))
199     {
200       DPRINT1("ScsiClassGetCapabilities() failed! (Status 0x%lX)\n", Status);
201       return(FALSE);
202     }
203
204   DPRINT("PortCapabilities: %p\n", PortCapabilities);
205   DPRINT("MaximumTransferLength: %lu\n", PortCapabilities->MaximumTransferLength);
206   DPRINT("MaximumPhysicalPages: %lu\n", PortCapabilities->MaximumPhysicalPages);
207
208   /* Get inquiry data */
209   Status = ScsiClassGetInquiryData(PortDeviceObject,
210                                    (PSCSI_ADAPTER_BUS_INFO *)&Buffer);
211   if (!NT_SUCCESS(Status))
212     {
213       DPRINT1("ScsiClassGetInquiryData() failed! (Status 0x%lX)\n", Status);
214       return(FALSE);
215     }
216
217   /* Check whether there are unclaimed devices */
218   AdapterBusInfo = (PSCSI_ADAPTER_BUS_INFO)Buffer;
219   DeviceCount = ScsiClassFindUnclaimedDevices(InitializationData,
220                                               AdapterBusInfo);
221   if (DeviceCount == 0)
222     {
223       DPRINT("No unclaimed devices!\n");
224       return(FALSE);
225     }
226
227   DPRINT("Found %lu unclaimed devices!\n", DeviceCount);
228
229   ConfigInfo = IoGetConfigurationInformation();
230   DPRINT("Number of SCSI ports: %lu\n", ConfigInfo->ScsiPortCount);
231
232   /* Search each bus of this adapter */
233   for (Bus = 0; Bus < (ULONG)AdapterBusInfo->NumberOfBuses; Bus++)
234     {
235       DPRINT("Searching bus %lu\n", Bus);
236
237       UnitInfo = (PSCSI_INQUIRY_DATA)(Buffer + AdapterBusInfo->BusData[Bus].InquiryDataOffset);
238
239       while (AdapterBusInfo->BusData[Bus].InquiryDataOffset)
240         {
241           InquiryData = (PINQUIRYDATA)UnitInfo->InquiryData;
242
243           if ((InquiryData->DeviceType == READ_ONLY_DIRECT_ACCESS_DEVICE) &&
244               (InquiryData->DeviceTypeQualifier == 0) &&
245               (UnitInfo->DeviceClaimed == FALSE))
246             {
247               DPRINT("Vendor: '%.24s'\n",
248                      InquiryData->VendorId);
249
250               /* Create device objects for disk */
251               Status = CdromClassCreateDeviceObject(DriverObject,
252                                                     RegistryPath,
253                                                     PortDeviceObject,
254                                                     PortNumber,
255                                                     ConfigInfo->CDRomCount,
256                                                     PortCapabilities,
257                                                     UnitInfo,
258                                                     InitializationData);
259               if (NT_SUCCESS(Status))
260                 {
261                   ConfigInfo->CDRomCount++;
262                   FoundDevice = TRUE;
263                 }
264             }
265
266           if (UnitInfo->NextInquiryDataOffset == 0)
267             break;
268
269           UnitInfo = (PSCSI_INQUIRY_DATA)(Buffer + UnitInfo->NextInquiryDataOffset);
270         }
271     }
272
273   ExFreePool(Buffer);
274
275   DPRINT("CdromClassFindDevices() done\n");
276
277   return(FoundDevice);
278 }
279
280
281 /**********************************************************************
282  * NAME                                                 EXPORTED
283  *      CdromClassCheckDevice
284  *
285  * DESCRIPTION
286  *      This function checks the InquiryData for the correct device
287  *      type and qualifier.
288  *
289  * RUN LEVEL
290  *      PASSIVE_LEVEL
291  *
292  * ARGUMENTS
293  *      InquiryData
294  *              Pointer to the inquiry data for the device in question.
295  *
296  * RETURN VALUE
297  *      TRUE: A disk device was found.
298  *      FALSE: Otherwise.
299  */
300
301 BOOLEAN STDCALL
302 CdromClassCheckDevice(IN PINQUIRYDATA InquiryData)
303 {
304   return((InquiryData->DeviceType == READ_ONLY_DIRECT_ACCESS_DEVICE) &&
305          (InquiryData->DeviceTypeQualifier == 0));
306 }
307
308
309 /**********************************************************************
310  * NAME                                                 EXPORTED
311  *      CdromClassCheckReadWrite
312  *
313  * DESCRIPTION
314  *      This function checks the given IRP for correct data.
315  *
316  * RUN LEVEL
317  *      PASSIVE_LEVEL
318  *
319  * ARGUMENTS
320  *      DeviceObject
321  *              Pointer to the device.
322  *      Irp
323  *              Irp to check.
324  *
325  * RETURN VALUE
326  *      STATUS_SUCCESS: The IRP matches the requirements of the given device.
327  *      Others: Failure.
328  */
329
330 NTSTATUS STDCALL
331 CdromClassCheckReadWrite(IN PDEVICE_OBJECT DeviceObject,
332                          IN PIRP Irp)
333 {
334   DPRINT("CdromClassCheckReadWrite() called\n");
335
336   return(STATUS_SUCCESS);
337 }
338
339
340 /**********************************************************************
341  * NAME                                                 EXPORTED
342  *      CdromClassCreateDeviceObject
343  *
344  * DESCRIPTION:
345  *      Create the raw device and any partition devices on this drive
346  *
347  * RUN LEVEL:
348  *      PASSIVE_LEVEL
349  *
350  * ARGUMENTS:
351  *      DriverObject
352  *              System allocated Driver Object for this driver.
353  *      RegistryPath
354  *              Name of registry driver service key.
355  *      PortDeviceObject
356  *      PortNumber
357  *      DeviceNumber
358  *      Capabilities
359  *      InquiryData
360  *      InitializationData
361  *
362  * RETURNS:
363  *      Status.
364  */
365
366 static NTSTATUS
367 CdromClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
368                              IN PUNICODE_STRING RegistryPath,
369                              IN PDEVICE_OBJECT PortDeviceObject,
370                              IN ULONG PortNumber,
371                              IN ULONG DeviceNumber,
372                              IN PIO_SCSI_CAPABILITIES Capabilities,
373                              IN PSCSI_INQUIRY_DATA InquiryData,
374                              IN PCLASS_INIT_DATA InitializationData)
375 {
376   OBJECT_ATTRIBUTES ObjectAttributes;
377   UNICODE_STRING UnicodeDeviceDirName;
378   CHAR NameBuffer[80];
379   PDEVICE_OBJECT DiskDeviceObject;
380   PDEVICE_EXTENSION DiskDeviceExtension; /* defined in class2.h */
381   HANDLE Handle;
382   PCDROM_DATA CdromData;
383   NTSTATUS Status;
384
385   DPRINT("CdromClassCreateDeviceObject() called\n");
386
387   /* Claim the cdrom device */
388   Status = ScsiClassClaimDevice(PortDeviceObject,
389                                 InquiryData,
390                                 FALSE,
391                                 &PortDeviceObject);
392   if (!NT_SUCCESS(Status))
393     {
394       DbgPrint("Could not claim cdrom device\n");
395       return(Status);
396     }
397
398   /* Create cdrom device */
399   sprintf(NameBuffer,
400           "\\Device\\CdRom%lu",
401           DeviceNumber);
402
403   Status = ScsiClassCreateDeviceObject(DriverObject,
404                                        NameBuffer,
405                                        NULL,
406                                        &DiskDeviceObject,
407                                        InitializationData);
408   if (!NT_SUCCESS(Status))
409     {
410       DPRINT1("ScsiClassCreateDeviceObject() failed (Status %x)\n", Status);
411
412       /* Release (unclaim) the disk */
413       ScsiClassClaimDevice(PortDeviceObject,
414                            InquiryData,
415                            TRUE,
416                            NULL);
417
418       return(Status);
419     }
420
421   DiskDeviceObject->Flags |= DO_DIRECT_IO;
422   DiskDeviceObject->Characteristics |= FILE_REMOVABLE_MEDIA;
423   DiskDeviceObject->StackSize = (CCHAR)PortDeviceObject->StackSize + 1;
424
425   if (PortDeviceObject->AlignmentRequirement > DiskDeviceObject->AlignmentRequirement)
426     {
427       DiskDeviceObject->AlignmentRequirement = PortDeviceObject->AlignmentRequirement;
428     }
429
430   DiskDeviceExtension = DiskDeviceObject->DeviceExtension;
431   DiskDeviceExtension->LockCount = 0;
432   DiskDeviceExtension->DeviceNumber = DeviceNumber;
433   DiskDeviceExtension->PortDeviceObject = PortDeviceObject;
434   DiskDeviceExtension->PhysicalDevice = DiskDeviceObject;
435   DiskDeviceExtension->PortCapabilities = Capabilities;
436   DiskDeviceExtension->StartingOffset.QuadPart = 0;
437   DiskDeviceExtension->PortNumber = (UCHAR)PortNumber;
438   DiskDeviceExtension->PathId = InquiryData->PathId;
439   DiskDeviceExtension->TargetId = InquiryData->TargetId;
440   DiskDeviceExtension->Lun = InquiryData->Lun;
441
442   /* zero-out disk data */
443   CdromData = (PCDROM_DATA)(DiskDeviceExtension + 1);
444   RtlZeroMemory(CdromData,
445                 sizeof(CDROM_DATA));
446
447   DiskDeviceExtension->SenseData = ExAllocatePool(NonPagedPool,
448                                                   sizeof(SENSE_DATA));
449   if (DiskDeviceExtension->SenseData == NULL)
450     {
451       DPRINT1("Failed to allocate sense data buffer!\n");
452
453       IoDeleteDevice(DiskDeviceObject);
454
455       /* Release (unclaim) the disk */
456       ScsiClassClaimDevice(PortDeviceObject,
457                            InquiryData,
458                            TRUE,
459                            NULL);
460
461       return(STATUS_INSUFFICIENT_RESOURCES);
462     }
463
464   /* Initialize lookaside list for SRBs */
465   ScsiClassInitializeSrbLookasideList(DiskDeviceExtension,
466                                       4);
467
468   /* Get disk geometry */
469   DiskDeviceExtension->DiskGeometry = ExAllocatePool(NonPagedPool,
470                                                      sizeof(DISK_GEOMETRY));
471   if (DiskDeviceExtension->DiskGeometry == NULL)
472     {
473       DPRINT1("Failed to allocate geometry buffer!\n");
474
475       ExDeleteNPagedLookasideList(&DiskDeviceExtension->SrbLookasideListHead);
476
477       IoDeleteDevice(DiskDeviceObject);
478
479       /* Release (unclaim) the disk */
480       ScsiClassClaimDevice(PortDeviceObject,
481                            InquiryData,
482                            TRUE,
483                            NULL);
484
485       return(STATUS_INSUFFICIENT_RESOURCES);
486     }
487
488   /* Read the drive's capacity */
489   Status = ScsiClassReadDriveCapacity(DiskDeviceObject);
490   if (!NT_SUCCESS(Status) ||
491       DiskDeviceExtension->DiskGeometry->BytesPerSector == 0)
492     {
493       /* Set ISO9660 defaults */
494       DiskDeviceExtension->DiskGeometry->BytesPerSector = 2048;
495       DiskDeviceExtension->DiskGeometry->MediaType = RemovableMedia;
496       DiskDeviceExtension->SectorShift = 11;
497       DiskDeviceExtension->PartitionLength.QuadPart = (ULONGLONG)0x7fffffff;
498     }
499   else
500     {
501       /* Make sure the BytesPerSector value is a power of 2 */
502 //      DiskDeviceExtension->DiskGeometry->BytesPerSector = 2048;
503     }
504
505   DPRINT("SectorSize: %lu\n", DiskDeviceExtension->DiskGeometry->BytesPerSector);
506
507   /* FIXME: initialize media change support */
508
509   IoInitializeTimer(DiskDeviceObject,
510                     CdromTimerRoutine,
511                     NULL);
512   IoStartTimer(DiskDeviceObject);
513
514   DPRINT("CdromClassCreateDeviceObjects() done\n");
515
516   return(STATUS_SUCCESS);
517 }
518
519
520 /**********************************************************************
521  * NAME
522  *      CdromClassReadTocEntry
523  *
524  * ARGUMENTS:
525  *      DeviceObject
526  *      TrackNo
527  *      Buffer
528  *      Length
529  *
530  * RETURNS:
531  *      Status.
532  */
533
534 static NTSTATUS
535 CdromClassReadTocEntry(PDEVICE_OBJECT DeviceObject, UINT TrackNo, PVOID Buffer, UINT Length)
536 {
537   PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
538   SCSI_REQUEST_BLOCK Srb;
539   PCDB Cdb;
540
541   RtlZeroMemory(&Srb, sizeof(SCSI_REQUEST_BLOCK));
542   Srb.CdbLength = 10;
543   Srb.TimeOutValue = DeviceExtension->TimeOutValue;
544
545   Cdb = (PCDB)Srb.Cdb;
546   Cdb->READ_TOC.OperationCode = SCSIOP_READ_TOC;
547   Cdb->READ_TOC.StartingTrack = TrackNo;
548   Cdb->READ_TOC.Format = 0;
549   Cdb->READ_TOC.AllocationLength[0] = Length >> 8;
550   Cdb->READ_TOC.AllocationLength[1] = Length & 0xff;
551   Cdb->READ_TOC.Msf = 1;
552
553   return(ScsiClassSendSrbSynchronous(DeviceObject,
554                                      &Srb,
555                                      Buffer,
556                                      Length,
557                                      FALSE));
558 }
559
560
561 static NTSTATUS
562 CdromClassReadLastSession(PDEVICE_OBJECT DeviceObject, UINT TrackNo, PVOID Buffer, UINT Length)
563 {
564   PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
565   SCSI_REQUEST_BLOCK Srb;
566   PCDB Cdb;
567
568   RtlZeroMemory(&Srb, sizeof(SCSI_REQUEST_BLOCK));
569   Srb.CdbLength = 10;
570   Srb.TimeOutValue = DeviceExtension->TimeOutValue;
571
572   Cdb = (PCDB)Srb.Cdb;
573   Cdb->READ_TOC.OperationCode = SCSIOP_READ_TOC;
574   Cdb->READ_TOC.StartingTrack = TrackNo;
575   Cdb->READ_TOC.Format = 1;
576   Cdb->READ_TOC.AllocationLength[0] = Length >> 8;
577   Cdb->READ_TOC.AllocationLength[1] = Length & 0xff;
578   Cdb->READ_TOC.Msf = 0;
579
580   return(ScsiClassSendSrbSynchronous(DeviceObject,
581                                      &Srb,
582                                      Buffer,
583                                      Length,
584                                      FALSE));
585 }
586
587
588 /**********************************************************************
589  * NAME                                                 EXPORTED
590  *      CdromClassDeviceControl
591  *
592  * DESCRIPTION:
593  *      Answer requests for device control calls
594  *
595  * RUN LEVEL:
596  *      PASSIVE_LEVEL
597  *
598  * ARGUMENTS:
599  *      DeviceObject
600  *      Irp
601  *              Standard dispatch arguments
602  *
603  * RETURNS:
604  *      Status.
605  */
606
607 NTSTATUS STDCALL
608 CdromClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
609                         IN PIRP Irp)
610 {
611   PDEVICE_EXTENSION DeviceExtension;
612   PIO_STACK_LOCATION IrpStack;
613   ULONG ControlCode, InputLength, OutputLength;
614   PCDROM_DATA CdromData;
615   ULONG Information;
616   NTSTATUS Status;
617
618   DPRINT("CdromClassDeviceControl() called!\n");
619
620   Status = STATUS_INVALID_DEVICE_REQUEST;
621   Information = 0;
622   IrpStack = IoGetCurrentIrpStackLocation(Irp);
623   ControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;
624   InputLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
625   OutputLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
626   DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
627   CdromData = (PCDROM_DATA)(DeviceExtension + 1);
628
629   switch (ControlCode)
630     {
631       case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
632         DPRINT("IOCTL_CDROM_GET_DRIVE_GEOMETRY\n");
633         if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_GEOMETRY))
634           {
635             Status = STATUS_INVALID_PARAMETER;
636           }
637         else
638           {
639             PDISK_GEOMETRY Geometry;
640
641             if (DeviceExtension->DiskGeometry == NULL)
642               {
643                 DPRINT("No cdrom geometry available!\n");
644                 DeviceExtension->DiskGeometry = ExAllocatePool(NonPagedPool,
645                                                                sizeof(DISK_GEOMETRY));
646               }
647             Status = ScsiClassReadDriveCapacity(DeviceObject);
648             if (NT_SUCCESS(Status))
649               {
650                 Geometry = (PDISK_GEOMETRY)Irp->AssociatedIrp.SystemBuffer;
651                 RtlMoveMemory(Geometry,
652                               DeviceExtension->DiskGeometry,
653                               sizeof(DISK_GEOMETRY));
654
655                 Status = STATUS_SUCCESS;
656                 Information = sizeof(DISK_GEOMETRY);
657               }
658           }
659         break;
660
661       case IOCTL_CDROM_READ_TOC:
662         DPRINT("IOCTL_CDROM_READ_TOC\n");
663         if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(CDROM_TOC))
664           {
665             Status = STATUS_INFO_LENGTH_MISMATCH;
666           }
667         else
668           {
669             PCDROM_TOC TocBuffer;
670             USHORT Length;
671
672             TocBuffer = Irp->AssociatedIrp.SystemBuffer;
673
674             /* First read the lead out */
675             Length = 4 + sizeof(TRACK_DATA);
676             Status = CdromClassReadTocEntry(DeviceObject,
677                                             0xAA,
678                                             TocBuffer,
679                                             Length);
680             if (NT_SUCCESS(Status))
681               {
682                 if (TocBuffer->FirstTrack == 0xaa)
683                   {
684                     /* there is an empty cd */
685                     Information = Length;
686                   }
687                 else
688                   {
689                     /* read the toc */
690                     Length = 4 + sizeof(TRACK_DATA) * (TocBuffer->LastTrack - TocBuffer->FirstTrack + 2);
691                     Status = CdromClassReadTocEntry(DeviceObject,
692                                                     TocBuffer->FirstTrack,
693                                                     TocBuffer, Length);
694                     if (NT_SUCCESS(Status))
695                       {
696                         Information = Length;
697                       }
698                   }
699               }
700           }
701         break;
702
703       case IOCTL_CDROM_GET_LAST_SESSION:
704         DPRINT("IOCTL_CDROM_GET_LAST_SESSION\n");
705         if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < 4 + sizeof(TRACK_DATA))
706           {
707             Status = STATUS_INFO_LENGTH_MISMATCH;
708           }
709         else
710           {
711             PCDROM_TOC TocBuffer;
712             USHORT Length;
713
714             TocBuffer = Irp->AssociatedIrp.SystemBuffer;
715             Length = 4 + sizeof(TRACK_DATA);
716             Status = CdromClassReadLastSession(DeviceObject,
717                                                0,
718                                                TocBuffer,
719                                                Length);
720             if (NT_SUCCESS(Status))
721               {
722                 Information = Length;
723               }
724           }
725         break;
726
727       default:
728         /* Call the common device control function */
729         return(ScsiClassDeviceControl(DeviceObject, Irp));
730     }
731
732   /* Verify the device if the user caused the error */
733   if (!NT_SUCCESS(Status) && IoIsErrorUserInduced(Status))
734     {
735       IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
736     }
737
738   Irp->IoStatus.Status = Status;
739   Irp->IoStatus.Information = Information;
740   IoCompleteRequest(Irp,
741                     IO_NO_INCREMENT);
742
743   return(STATUS_SUCCESS);
744 }
745
746
747 /**********************************************************************
748  * NAME                                                 EXPORTED
749  *      CdromClassShutdownFlush
750  *
751  * DESCRIPTION:
752  *      Answer requests for shutdown and flush calls
753  *
754  * RUN LEVEL:
755  *      PASSIVE_LEVEL
756  *
757  * ARGUMENTS:
758  *      DeviceObject
759  *      Irp
760  *              Standard dispatch arguments
761  *
762  * RETURNS:
763  *      Status.
764  */
765
766 NTSTATUS STDCALL
767 CdromClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject,
768                         IN PIRP Irp)
769 {
770   DPRINT("CdromClassShutdownFlush() called!\n");
771
772   Irp->IoStatus.Status = STATUS_SUCCESS;
773   Irp->IoStatus.Information = 0;
774   IoCompleteRequest(Irp, IO_NO_INCREMENT);
775
776   return(STATUS_SUCCESS);
777 }
778
779
780 VOID STDCALL
781 CdromTimerRoutine(PDEVICE_OBJECT DeviceObject,
782                   PVOID Context)
783 {
784   DPRINT("CdromTimerRoutine() called\n");
785
786 }
787
788 /* EOF */