:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[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 //  return(TRUE);
279 }
280
281
282 /**********************************************************************
283  * NAME                                                 EXPORTED
284  *      CdromClassCheckDevice
285  *
286  * DESCRIPTION
287  *      This function checks the InquiryData for the correct device
288  *      type and qualifier.
289  *
290  * RUN LEVEL
291  *      PASSIVE_LEVEL
292  *
293  * ARGUMENTS
294  *      InquiryData
295  *              Pointer to the inquiry data for the device in question.
296  *
297  * RETURN VALUE
298  *      TRUE: A disk device was found.
299  *      FALSE: Otherwise.
300  */
301
302 BOOLEAN STDCALL
303 CdromClassCheckDevice(IN PINQUIRYDATA InquiryData)
304 {
305   return((InquiryData->DeviceType == READ_ONLY_DIRECT_ACCESS_DEVICE) &&
306          (InquiryData->DeviceTypeQualifier == 0));
307 }
308
309
310 /**********************************************************************
311  * NAME                                                 EXPORTED
312  *      CdromClassCheckReadWrite
313  *
314  * DESCRIPTION
315  *      This function checks the given IRP for correct data.
316  *
317  * RUN LEVEL
318  *      PASSIVE_LEVEL
319  *
320  * ARGUMENTS
321  *      DeviceObject
322  *              Pointer to the device.
323  *      Irp
324  *              Irp to check.
325  *
326  * RETURN VALUE
327  *      STATUS_SUCCESS: The IRP matches the requirements of the given device.
328  *      Others: Failure.
329  */
330
331 NTSTATUS STDCALL
332 CdromClassCheckReadWrite(IN PDEVICE_OBJECT DeviceObject,
333                          IN PIRP Irp)
334 {
335   DPRINT("CdromClassCheckReadWrite() called\n");
336
337   return(STATUS_SUCCESS);
338 }
339
340
341 /**********************************************************************
342  * NAME                                                 EXPORTED
343  *      CdromClassCreateDeviceObject
344  *
345  * DESCRIPTION:
346  *      Create the raw device and any partition devices on this drive
347  *
348  * RUN LEVEL:
349  *      PASSIVE_LEVEL
350  *
351  * ARGUMENTS:
352  *      DriverObject
353  *              System allocated Driver Object for this driver.
354  *      RegistryPath
355  *              Name of registry driver service key.
356  *      PortDeviceObject
357  *      PortNumber
358  *      DeviceNumber
359  *      Capabilities
360  *      InquiryData
361  *      InitializationData
362  *
363  * RETURNS:
364  *      Status.
365  */
366
367 static NTSTATUS
368 CdromClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
369                              IN PUNICODE_STRING RegistryPath,
370                              IN PDEVICE_OBJECT PortDeviceObject,
371                              IN ULONG PortNumber,
372                              IN ULONG DeviceNumber,
373                              IN PIO_SCSI_CAPABILITIES Capabilities,
374                              IN PSCSI_INQUIRY_DATA InquiryData,
375                              IN PCLASS_INIT_DATA InitializationData)
376 {
377   OBJECT_ATTRIBUTES ObjectAttributes;
378   UNICODE_STRING UnicodeDeviceDirName;
379   CHAR NameBuffer[80];
380   PDEVICE_OBJECT DiskDeviceObject;
381   PDEVICE_EXTENSION DiskDeviceExtension; /* defined in class2.h */
382   HANDLE Handle;
383   PCDROM_DATA CdromData;
384   NTSTATUS Status;
385
386   DPRINT("CdromClassCreateDeviceObject() called\n");
387
388   /* Claim the cdrom device */
389   Status = ScsiClassClaimDevice(PortDeviceObject,
390                                 InquiryData,
391                                 FALSE,
392                                 &PortDeviceObject);
393   if (!NT_SUCCESS(Status))
394     {
395       DbgPrint("Could not claim cdrom device\n");
396       return(Status);
397     }
398
399   /* Create cdrom device */
400   sprintf(NameBuffer,
401           "\\Device\\CdRom%lu",
402           DeviceNumber);
403
404   Status = ScsiClassCreateDeviceObject(DriverObject,
405                                        NameBuffer,
406                                        NULL,
407                                        &DiskDeviceObject,
408                                        InitializationData);
409   if (!NT_SUCCESS(Status))
410     {
411       DPRINT1("ScsiClassCreateDeviceObject() failed (Status %x)\n", Status);
412
413       /* Release (unclaim) the disk */
414       ScsiClassClaimDevice(PortDeviceObject,
415                            InquiryData,
416                            TRUE,
417                            NULL);
418
419       return(Status);
420     }
421
422   DiskDeviceObject->Flags |= DO_DIRECT_IO;
423   DiskDeviceObject->Characteristics |= FILE_REMOVABLE_MEDIA;
424   DiskDeviceObject->StackSize = (CCHAR)PortDeviceObject->StackSize + 1;
425
426   if (PortDeviceObject->AlignmentRequirement > DiskDeviceObject->AlignmentRequirement)
427     {
428       DiskDeviceObject->AlignmentRequirement = PortDeviceObject->AlignmentRequirement;
429     }
430
431   DiskDeviceExtension = DiskDeviceObject->DeviceExtension;
432   DiskDeviceExtension->LockCount = 0;
433   DiskDeviceExtension->DeviceNumber = DeviceNumber;
434   DiskDeviceExtension->PortDeviceObject = PortDeviceObject;
435   DiskDeviceExtension->PhysicalDevice = DiskDeviceObject;
436   DiskDeviceExtension->PortCapabilities = Capabilities;
437   DiskDeviceExtension->StartingOffset.QuadPart = 0;
438   DiskDeviceExtension->PortNumber = (UCHAR)PortNumber;
439   DiskDeviceExtension->PathId = InquiryData->PathId;
440   DiskDeviceExtension->TargetId = InquiryData->TargetId;
441   DiskDeviceExtension->Lun = InquiryData->Lun;
442
443   /* zero-out disk data */
444   CdromData = (PCDROM_DATA)(DiskDeviceExtension + 1);
445   RtlZeroMemory(CdromData,
446                 sizeof(CDROM_DATA));
447
448   DiskDeviceExtension->SenseData = ExAllocatePool(NonPagedPool,
449                                                   sizeof(SENSE_DATA));
450   if (DiskDeviceExtension->SenseData == NULL)
451     {
452       DPRINT1("Failed to allocate sense data buffer!\n");
453
454       IoDeleteDevice(DiskDeviceObject);
455
456       /* Release (unclaim) the disk */
457       ScsiClassClaimDevice(PortDeviceObject,
458                            InquiryData,
459                            TRUE,
460                            NULL);
461
462       return(STATUS_INSUFFICIENT_RESOURCES);
463     }
464
465   /* Get disk geometry */
466   DiskDeviceExtension->DiskGeometry = ExAllocatePool(NonPagedPool,
467                                                      sizeof(DISK_GEOMETRY));
468   if (DiskDeviceExtension->DiskGeometry == NULL)
469     {
470       DPRINT1("Failed to allocate geometry buffer!\n");
471
472       IoDeleteDevice(DiskDeviceObject);
473
474       /* Release (unclaim) the disk */
475       ScsiClassClaimDevice(PortDeviceObject,
476                            InquiryData,
477                            TRUE,
478                            NULL);
479
480       return(STATUS_INSUFFICIENT_RESOURCES);
481     }
482
483   /* Read the drive's capacity */
484   Status = ScsiClassReadDriveCapacity(DiskDeviceObject);
485   if (!NT_SUCCESS(Status) ||
486       DiskDeviceExtension->DiskGeometry->BytesPerSector == 0)
487     {
488       /* Set ISO9660 defaults */
489       DiskDeviceExtension->DiskGeometry->BytesPerSector = 2048;
490       DiskDeviceExtension->DiskGeometry->MediaType = RemovableMedia;
491       DiskDeviceExtension->SectorShift = 11;
492       DiskDeviceExtension->PartitionLength.QuadPart = (ULONGLONG)0x7fffffff;
493     }
494   else
495     {
496       /* Make sure the BytesPerSector value is a power of 2 */
497 //      DiskDeviceExtension->DiskGeometry->BytesPerSector = 2048;
498     }
499
500   DPRINT("SectorSize: %lu\n", DiskDeviceExtension->DiskGeometry->BytesPerSector);
501
502   /* FIXME: initialize media change support */
503
504   IoInitializeTimer(DiskDeviceObject,
505                     CdromTimerRoutine,
506                     NULL);
507   IoStartTimer(DiskDeviceObject);
508
509   DPRINT("CdromClassCreateDeviceObjects() done\n");
510
511   return(STATUS_SUCCESS);
512 }
513
514 /**********************************************************************
515  * NAME
516  *      CdromClassReadTocEntry
517  *
518  * ARGUMENTS:
519  *      DeviceObject
520  *      TrackNo
521  *      Buffer
522  *      Length
523  *
524  * RETURNS:
525  *      Status.
526  */
527
528 static NTSTATUS
529 CdromClassReadTocEntry(PDEVICE_OBJECT DeviceObject, UINT TrackNo, PVOID Buffer, UINT Length)
530 {
531   PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
532   SCSI_REQUEST_BLOCK Srb;
533   PCDB Cdb;
534
535   RtlZeroMemory(&Srb, sizeof(SCSI_REQUEST_BLOCK));
536   Srb.CdbLength = 10;
537   Srb.TimeOutValue = DeviceExtension->TimeOutValue;
538
539   Cdb = (PCDB)Srb.Cdb;
540   Cdb->READ_TOC.OperationCode = SCSIOP_READ_TOC;
541   Cdb->READ_TOC.StartingTrack = TrackNo;
542   Cdb->READ_TOC.Format = 0;
543   Cdb->READ_TOC.AllocationLength[0] = Length >> 8;
544   Cdb->READ_TOC.AllocationLength[1] = Length & 0xff;
545   Cdb->READ_TOC.Msf = 1;
546  
547   return ScsiClassSendSrbSynchronous(DeviceObject,
548                                      &Srb,
549                                      Buffer,
550                                      Length,
551                                      FALSE);
552 }
553
554 static NTSTATUS
555 CdromClassReadLastSession(PDEVICE_OBJECT DeviceObject, UINT TrackNo, PVOID Buffer, UINT Length)
556 {
557   PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
558   SCSI_REQUEST_BLOCK Srb;
559   PCDB Cdb;
560
561   RtlZeroMemory(&Srb, sizeof(SCSI_REQUEST_BLOCK));
562   Srb.CdbLength = 10;
563   Srb.TimeOutValue = DeviceExtension->TimeOutValue;
564
565   Cdb = (PCDB)Srb.Cdb;
566   Cdb->READ_TOC.OperationCode = SCSIOP_READ_TOC;
567   Cdb->READ_TOC.StartingTrack = TrackNo;
568   Cdb->READ_TOC.Format = 1;
569   Cdb->READ_TOC.AllocationLength[0] = Length >> 8;
570   Cdb->READ_TOC.AllocationLength[1] = Length & 0xff;
571   Cdb->READ_TOC.Msf = 0;
572  
573   return ScsiClassSendSrbSynchronous(DeviceObject,
574                                      &Srb,
575                                      Buffer,
576                                      Length,
577                                      FALSE);
578 }
579
580 /**********************************************************************
581  * NAME                                                 EXPORTED
582  *      CdromClassDeviceControl
583  *
584  * DESCRIPTION:
585  *      Answer requests for device control calls
586  *
587  * RUN LEVEL:
588  *      PASSIVE_LEVEL
589  *
590  * ARGUMENTS:
591  *      DeviceObject
592  *      Irp
593  *              Standard dispatch arguments
594  *
595  * RETURNS:
596  *      Status.
597  */
598
599 NTSTATUS STDCALL
600 CdromClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
601                         IN PIRP Irp)
602 {
603   PDEVICE_EXTENSION DeviceExtension;
604   PIO_STACK_LOCATION IrpStack;
605   ULONG ControlCode, InputLength, OutputLength;
606   PCDROM_DATA CdromData;
607   ULONG Information;
608   NTSTATUS Status;
609
610   DPRINT("CdromClassDeviceControl() called!\n");
611
612   Status = STATUS_INVALID_DEVICE_REQUEST;
613   Information = 0;
614   IrpStack = IoGetCurrentIrpStackLocation(Irp);
615   ControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;
616   InputLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
617   OutputLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
618   DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
619   CdromData = (PCDROM_DATA)(DeviceExtension + 1);
620
621   switch (ControlCode)
622     {
623       case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
624         DPRINT("IOCTL_CDROM_GET_DRIVE_GEOMETRY\n");
625         if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_GEOMETRY))
626           {
627             Status = STATUS_INVALID_PARAMETER;
628           }
629         else
630           {
631             PDISK_GEOMETRY Geometry;
632
633             if (DeviceExtension->DiskGeometry == NULL)
634               {
635                 DPRINT("No cdrom geometry available!\n");
636                 DeviceExtension->DiskGeometry = ExAllocatePool(NonPagedPool,
637                                                                sizeof(DISK_GEOMETRY));
638               }
639             Status = ScsiClassReadDriveCapacity(DeviceObject);
640             if (NT_SUCCESS(Status))
641               {
642                 Geometry = (PDISK_GEOMETRY)Irp->AssociatedIrp.SystemBuffer;
643                 RtlMoveMemory(Geometry,
644                               DeviceExtension->DiskGeometry,
645                               sizeof(DISK_GEOMETRY));
646
647                 Status = STATUS_SUCCESS;
648                 Information = sizeof(DISK_GEOMETRY);
649               }
650           }
651         break;
652       case IOCTL_CDROM_READ_TOC:
653           DPRINT("IOCTL_CDROM_READ_TOC\n");
654           if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(CDROM_TOC))
655           {
656               Status = STATUS_INFO_LENGTH_MISMATCH;
657           }
658           else
659           {
660               PCDROM_TOC TocBuffer;
661               USHORT Length;
662
663               TocBuffer = Irp->AssociatedIrp.SystemBuffer;
664
665               /* First read the lead out */
666               Length = 4 + sizeof(TRACK_DATA);
667               Status = CdromClassReadTocEntry(DeviceObject, 0xaa, TocBuffer, Length);
668
669               if (NT_SUCCESS(Status))
670               {
671                  if (TocBuffer->FirstTrack == 0xaa)
672                  {
673                     /* there is an empty cd */
674                     Information = Length; 
675                  }
676                  else
677                  {
678                     /* read the toc */
679                     Length = 4 + sizeof(TRACK_DATA) * (TocBuffer->LastTrack - TocBuffer->FirstTrack + 2);
680                     Status = CdromClassReadTocEntry(DeviceObject, TocBuffer->FirstTrack, TocBuffer, Length);
681                     if (NT_SUCCESS(Status))
682                     {
683                        Information = Length;
684                     }
685                  }
686               }
687           }
688           break;
689       case IOCTL_CDROM_GET_LAST_SESSION:
690           DPRINT("IOCTL_CDROM_GET_LAST_SESSION\n");
691           if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < 4 + sizeof(TRACK_DATA))
692           {
693               Status = STATUS_INFO_LENGTH_MISMATCH;
694           }
695           else
696           {
697               USHORT Length;
698               PCDROM_TOC TocBuffer = Irp->AssociatedIrp.SystemBuffer;
699
700               Length = 4 + sizeof(TRACK_DATA);
701               Status = CdromClassReadLastSession(DeviceObject, 0, TocBuffer, Length);
702               if (NT_SUCCESS(Status))
703               {
704                  Information = Length;
705               }
706           }
707           break;
708       default:
709         /* Call the common device control function */
710         return(ScsiClassDeviceControl(DeviceObject, Irp));
711     }
712
713   /* Verify the device if the user caused the error */
714   if (!NT_SUCCESS(Status) && IoIsErrorUserInduced(Status))
715     {
716       IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
717     }
718
719   Irp->IoStatus.Status = Status;
720   Irp->IoStatus.Information = Information;
721   IoCompleteRequest(Irp,
722                     IO_NO_INCREMENT);
723
724   return(STATUS_SUCCESS);
725 }
726
727
728 /**********************************************************************
729  * NAME                                                 EXPORTED
730  *      CdromClassShutdownFlush
731  *
732  * DESCRIPTION:
733  *      Answer requests for shutdown and flush calls
734  *
735  * RUN LEVEL:
736  *      PASSIVE_LEVEL
737  *
738  * ARGUMENTS:
739  *      DeviceObject
740  *      Irp
741  *              Standard dispatch arguments
742  *
743  * RETURNS:
744  *      Status.
745  */
746
747 NTSTATUS STDCALL
748 CdromClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject,
749                         IN PIRP Irp)
750 {
751   DPRINT("CdromClassShutdownFlush() called!\n");
752
753   Irp->IoStatus.Status = STATUS_SUCCESS;
754   Irp->IoStatus.Information = 0;
755   IoCompleteRequest(Irp, IO_NO_INCREMENT);
756
757   return(STATUS_SUCCESS);
758 }
759
760
761 VOID STDCALL
762 CdromTimerRoutine(PDEVICE_OBJECT DeviceObject,
763                   PVOID Context)
764 {
765   DPRINT("CdromTimerRoutine() called\n");
766
767 }
768
769 /* EOF */