Retry failed requests.
[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.25 2003/11/10 18:09:54 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 static NTSTATUS
710 CdromClassReadTocEntry (PDEVICE_OBJECT DeviceObject,
711 UINT TrackNo,
712 PVOID Buffer,
713 UINT Length)
714 {
715 PDEVICE_EXTENSION DeviceExtension;
716 SCSI_REQUEST_BLOCK Srb;
717 PCDB Cdb;
718
719 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
720
721 RtlZeroMemory(&Srb, sizeof(SCSI_REQUEST_BLOCK));
722 Srb.CdbLength = 10;
723 Srb.TimeOutValue = DeviceExtension->TimeOutValue;
724
725 Cdb = (PCDB)Srb.Cdb;
726 Cdb->READ_TOC.OperationCode = SCSIOP_READ_TOC;
727 Cdb->READ_TOC.StartingTrack = TrackNo;
728 Cdb->READ_TOC.Format = 0;
729 Cdb->READ_TOC.AllocationLength[0] = Length >> 8;
730 Cdb->READ_TOC.AllocationLength[1] = Length & 0xff;
731 Cdb->READ_TOC.Msf = 1;
732
733 return(ScsiClassSendSrbSynchronous(DeviceObject,
734 &Srb,
735 Buffer,
736 Length,
737 FALSE));
738 }
739
740
741 static NTSTATUS
742 CdromClassReadLastSession (PDEVICE_OBJECT DeviceObject,
743 UINT TrackNo,
744 PVOID Buffer,
745 UINT Length)
746 {
747 PDEVICE_EXTENSION DeviceExtension;
748 SCSI_REQUEST_BLOCK Srb;
749 PCDB Cdb;
750
751 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
752
753 RtlZeroMemory(&Srb, sizeof(SCSI_REQUEST_BLOCK));
754 Srb.CdbLength = 10;
755 Srb.TimeOutValue = DeviceExtension->TimeOutValue;
756
757 Cdb = (PCDB)Srb.Cdb;
758 Cdb->READ_TOC.OperationCode = SCSIOP_READ_TOC;
759 Cdb->READ_TOC.StartingTrack = TrackNo;
760 Cdb->READ_TOC.Format = 1;
761 Cdb->READ_TOC.AllocationLength[0] = Length >> 8;
762 Cdb->READ_TOC.AllocationLength[1] = Length & 0xff;
763 Cdb->READ_TOC.Msf = 0;
764
765 return(ScsiClassSendSrbSynchronous(DeviceObject,
766 &Srb,
767 Buffer,
768 Length,
769 FALSE));
770 }
771
772
773 /**********************************************************************
774 * NAME EXPORTED
775 * CdromClassDeviceControl
776 *
777 * DESCRIPTION:
778 * Answer requests for device control calls
779 *
780 * RUN LEVEL:
781 * PASSIVE_LEVEL
782 *
783 * ARGUMENTS:
784 * DeviceObject
785 * Irp
786 * Standard dispatch arguments
787 *
788 * RETURNS:
789 * Status.
790 */
791
792 NTSTATUS STDCALL
793 CdromClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
794 IN PIRP Irp)
795 {
796 PDEVICE_EXTENSION DeviceExtension;
797 PIO_STACK_LOCATION IrpStack;
798 ULONG ControlCode, InputLength, OutputLength;
799 PCDROM_DATA CdromData;
800 ULONG Information;
801 NTSTATUS Status;
802
803 DPRINT("CdromClassDeviceControl() called!\n");
804
805 Status = STATUS_INVALID_DEVICE_REQUEST;
806 Information = 0;
807 IrpStack = IoGetCurrentIrpStackLocation(Irp);
808 ControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;
809 InputLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
810 OutputLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
811 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
812 CdromData = (PCDROM_DATA)(DeviceExtension + 1);
813
814 switch (ControlCode)
815 {
816 case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
817 DPRINT ("CdromClassDeviceControl: IOCTL_CDROM_GET_DRIVE_GEOMETRY\n");
818 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_GEOMETRY))
819 {
820 Status = STATUS_INFO_LENGTH_MISMATCH;
821 break;
822 }
823 IoMarkIrpPending (Irp);
824 IoStartPacket (DeviceObject,
825 Irp,
826 NULL,
827 NULL);
828 return STATUS_PENDING;
829
830 case IOCTL_CDROM_CHECK_VERIFY:
831 DPRINT ("CdromClassDeviceControl: IOCTL_CDROM_CHECK_VERIFY\n");
832 if (OutputLength != 0 && OutputLength < sizeof (ULONG))
833 {
834 DPRINT1("Buffer too small\n");
835 Status = STATUS_BUFFER_TOO_SMALL;
836 break;
837 }
838 IoMarkIrpPending (Irp);
839 IoStartPacket (DeviceObject,
840 Irp,
841 NULL,
842 NULL);
843 return STATUS_PENDING;
844
845 case IOCTL_CDROM_READ_TOC:
846 DPRINT("IOCTL_CDROM_READ_TOC\n");
847 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(CDROM_TOC))
848 {
849 Status = STATUS_INFO_LENGTH_MISMATCH;
850 }
851 else
852 {
853 PCDROM_TOC TocBuffer;
854 USHORT Length;
855
856 TocBuffer = Irp->AssociatedIrp.SystemBuffer;
857
858 /* First read the lead out */
859 Length = 4 + sizeof(TRACK_DATA);
860 Status = CdromClassReadTocEntry(DeviceObject,
861 0xAA,
862 TocBuffer,
863 Length);
864 if (NT_SUCCESS(Status))
865 {
866 if (TocBuffer->FirstTrack == 0xaa)
867 {
868 /* there is an empty cd */
869 Information = Length;
870 }
871 else
872 {
873 /* read the toc */
874 Length = 4 + sizeof(TRACK_DATA) * (TocBuffer->LastTrack - TocBuffer->FirstTrack + 2);
875 Status = CdromClassReadTocEntry(DeviceObject,
876 TocBuffer->FirstTrack,
877 TocBuffer, Length);
878 if (NT_SUCCESS(Status))
879 {
880 Information = Length;
881 }
882 }
883 }
884 }
885 break;
886
887 case IOCTL_CDROM_GET_LAST_SESSION:
888 DPRINT("IOCTL_CDROM_GET_LAST_SESSION\n");
889 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < 4 + sizeof(TRACK_DATA))
890 {
891 Status = STATUS_INFO_LENGTH_MISMATCH;
892 }
893 else
894 {
895 PCDROM_TOC TocBuffer;
896 USHORT Length;
897
898 TocBuffer = Irp->AssociatedIrp.SystemBuffer;
899 Length = 4 + sizeof(TRACK_DATA);
900 Status = CdromClassReadLastSession(DeviceObject,
901 0,
902 TocBuffer,
903 Length);
904 if (NT_SUCCESS(Status))
905 {
906 Information = Length;
907 }
908 }
909 break;
910
911 default:
912 /* Call the common device control function */
913 return(ScsiClassDeviceControl(DeviceObject, Irp));
914 }
915
916 /* Verify the device if the user caused the error */
917 if (!NT_SUCCESS(Status) && IoIsErrorUserInduced(Status))
918 {
919 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
920 }
921
922 Irp->IoStatus.Status = Status;
923 Irp->IoStatus.Information = Information;
924 IoCompleteRequest(Irp,
925 IO_DISK_INCREMENT);
926
927 return Status;
928 }
929
930
931 /**********************************************************************
932 * NAME
933 * CdromClassStartIo
934 *
935 * DESCRIPTION:
936 * Starts IRP processing.
937 *
938 * RUN LEVEL:
939 * PASSIVE_LEVEL
940 *
941 * ARGUMENTS:
942 * DeviceObject
943 * Irp
944 * Standard dispatch arguments
945 *
946 * RETURNS:
947 * None.
948 */
949 VOID STDCALL
950 CdromClassStartIo (IN PDEVICE_OBJECT DeviceObject,
951 IN PIRP Irp)
952 {
953 PDEVICE_EXTENSION DeviceExtension;
954 PIO_STACK_LOCATION IrpStack;
955 PIO_STACK_LOCATION SubIrpStack;
956 ULONG MaximumTransferLength;
957 ULONG TransferPages;
958 PSCSI_REQUEST_BLOCK Srb;
959 PIRP SubIrp;
960 PUCHAR SenseBuffer;
961 PVOID DataBuffer;
962 PCDB Cdb;
963
964 DPRINT("CdromClassStartIo() called!\n");
965
966 IoMarkIrpPending (Irp);
967
968 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
969 IrpStack = IoGetCurrentIrpStackLocation (Irp);
970
971 MaximumTransferLength = DeviceExtension->PortCapabilities->MaximumTransferLength;
972
973 if (DeviceObject->Flags & DO_VERIFY_VOLUME)
974 {
975 if (!(IrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME))
976 {
977 DPRINT1 ("Verify required\n");
978
979 if (Irp->Tail.Overlay.Thread)
980 {
981 IoSetHardErrorOrVerifyDevice (Irp,
982 DeviceObject);
983 }
984 Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
985
986 /* FIXME: Update drive capacity */
987
988 return;
989 }
990 }
991
992 if (IrpStack->MajorFunction == IRP_MJ_READ)
993 {
994 DPRINT ("CdromClassStartIo: IRP_MJ_READ\n");
995
996 TransferPages =
997 ADDRESS_AND_SIZE_TO_SPAN_PAGES (MmGetMdlVirtualAddress(Irp->MdlAddress),
998 IrpStack->Parameters.Read.Length);
999
1000 /* Check transfer size */
1001 if ((IrpStack->Parameters.Read.Length > MaximumTransferLength) ||
1002 (TransferPages > DeviceExtension->PortCapabilities->MaximumPhysicalPages))
1003 {
1004 /* Transfer size is too large - split it */
1005 TransferPages =
1006 DeviceExtension->PortCapabilities->MaximumPhysicalPages - 1;
1007
1008 /* Adjust transfer size */
1009 if (MaximumTransferLength > TransferPages * PAGE_SIZE)
1010 MaximumTransferLength = TransferPages * PAGE_SIZE;
1011
1012 if (MaximumTransferLength == 0)
1013 MaximumTransferLength = PAGE_SIZE;
1014
1015 /* Split the transfer */
1016 ScsiClassSplitRequest (DeviceObject,
1017 Irp,
1018 MaximumTransferLength);
1019 return;
1020 }
1021 else
1022 {
1023 /* Build SRB */
1024 ScsiClassBuildRequest (DeviceObject,
1025 Irp);
1026 }
1027 }
1028 else if (IrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL)
1029 {
1030 DPRINT ("CdromClassStartIo: IRP_MJ_IRP_MJ_DEVICE_CONTROL\n");
1031
1032 /* Allocate an IRP for sending requests to the port driver */
1033 SubIrp = IoAllocateIrp ((CCHAR)(DeviceObject->StackSize + 1),
1034 FALSE);
1035 if (SubIrp == NULL)
1036 {
1037 Irp->IoStatus.Information = 0;
1038 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1039 IoCompleteRequest (Irp,
1040 IO_DISK_INCREMENT);
1041 IoStartNextPacket (DeviceObject,
1042 FALSE);
1043 return;
1044 }
1045
1046 /* Allocate an SRB */
1047 Srb = ExAllocatePool (NonPagedPool,
1048 sizeof (SCSI_REQUEST_BLOCK));
1049 if (Srb == NULL)
1050 {
1051 IoFreeIrp (SubIrp);
1052 Irp->IoStatus.Information = 0;
1053 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1054 IoCompleteRequest (Irp,
1055 IO_DISK_INCREMENT);
1056 IoStartNextPacket (DeviceObject,
1057 FALSE);
1058 return;
1059 }
1060
1061 /* Allocte a sense buffer */
1062 SenseBuffer = ExAllocatePool (NonPagedPoolCacheAligned,
1063 SENSE_BUFFER_SIZE);
1064 if (SenseBuffer == NULL)
1065 {
1066 ExFreePool (Srb);
1067 IoFreeIrp (SubIrp);
1068 Irp->IoStatus.Information = 0;
1069 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1070 IoCompleteRequest (Irp,
1071 IO_DISK_INCREMENT);
1072 IoStartNextPacket (DeviceObject,
1073 FALSE);
1074 return;
1075 }
1076
1077 /* Initialize the IRP */
1078 IoSetNextIrpStackLocation (SubIrp);
1079 SubIrp->IoStatus.Information = 0;
1080 SubIrp->IoStatus.Status = STATUS_SUCCESS;
1081 SubIrp->Flags = 0;
1082 SubIrp->UserBuffer = NULL;
1083
1084 SubIrpStack = IoGetCurrentIrpStackLocation (SubIrp);
1085 SubIrpStack->DeviceObject = DeviceExtension->DeviceObject;
1086 SubIrpStack->Parameters.Others.Argument2 = (PVOID)Irp;
1087
1088 /* Initialize next stack location */
1089 SubIrpStack = IoGetNextIrpStackLocation (SubIrp);
1090 SubIrpStack->MajorFunction = IRP_MJ_SCSI;
1091 SubIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
1092 SubIrpStack->Parameters.Scsi.Srb = Srb;
1093
1094 /* Initialize the SRB */
1095 RtlZeroMemory(Srb,
1096 sizeof (SCSI_REQUEST_BLOCK));
1097 Srb->Length = sizeof (SCSI_REQUEST_BLOCK);
1098 Srb->PathId = DeviceExtension->PathId;
1099 Srb->TargetId = DeviceExtension->TargetId;
1100 Srb->Lun = DeviceExtension->Lun;
1101 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1102 Srb->SrbStatus = SRB_STATUS_SUCCESS;
1103 Srb->ScsiStatus = 0;
1104 Srb->NextSrb = 0;
1105 Srb->OriginalRequest = SubIrp;
1106 Srb->SenseInfoBuffer = SenseBuffer;
1107 Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
1108
1109 /* Initialize the CDB */
1110 Cdb = (PCDB)Srb->Cdb;
1111
1112 /* Set the completion routine */
1113 IoSetCompletionRoutine (SubIrp,
1114 CdromDeviceControlCompletion,
1115 Srb,
1116 TRUE,
1117 TRUE,
1118 TRUE);
1119
1120 switch (IrpStack->Parameters.DeviceIoControl.IoControlCode)
1121 {
1122 case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
1123 DPRINT ("CdromClassStartIo: IOCTL_CDROM_GET_DRIVE_GEOMETRY\n");
1124 Srb->DataTransferLength = sizeof(READ_CAPACITY_DATA);
1125 Srb->CdbLength = 10;
1126 Srb->TimeOutValue = DeviceExtension->TimeOutValue;
1127 Srb->SrbFlags = SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN;
1128 Cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
1129
1130 /* Allocate data buffer */
1131 DataBuffer = ExAllocatePool (NonPagedPoolCacheAligned,
1132 sizeof(READ_CAPACITY_DATA));
1133 if (DataBuffer == NULL)
1134 {
1135 Irp->IoStatus.Information = 0;
1136 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1137 IoCompleteRequest (Irp,
1138 IO_DISK_INCREMENT);
1139 ExFreePool (SenseBuffer);
1140 ExFreePool (Srb);
1141 IoFreeIrp (SubIrp);
1142 IoStartNextPacket (DeviceObject,
1143 FALSE);
1144 return;
1145 }
1146
1147 /* Allocate an MDL for the data buffer */
1148 SubIrp->MdlAddress = IoAllocateMdl (DataBuffer,
1149 sizeof(READ_CAPACITY_DATA),
1150 FALSE,
1151 FALSE,
1152 NULL);
1153 if (SubIrp->MdlAddress == NULL)
1154 {
1155 Irp->IoStatus.Information = 0;
1156 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1157 IoCompleteRequest (Irp,
1158 IO_DISK_INCREMENT);
1159 ExFreePool (DataBuffer);
1160 ExFreePool (SenseBuffer);
1161 ExFreePool (Srb);
1162 IoFreeIrp (SubIrp);
1163 IoStartNextPacket (DeviceObject,
1164 FALSE);
1165 return;
1166 }
1167
1168 MmBuildMdlForNonPagedPool (SubIrp->MdlAddress);
1169 Srb->DataBuffer = DataBuffer;
1170
1171 IoCallDriver (DeviceExtension->PortDeviceObject,
1172 SubIrp);
1173 return;
1174
1175 case IOCTL_CDROM_CHECK_VERIFY:
1176 DPRINT ("CdromClassStartIo: IOCTL_CDROM_CHECK_VERIFY\n");
1177 Srb->CdbLength = 6;
1178 Srb->TimeOutValue = DeviceExtension->TimeOutValue * 2;
1179 Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;
1180 Cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
1181
1182 IoCallDriver (DeviceExtension->PortDeviceObject,
1183 SubIrp);
1184 return;
1185
1186 default:
1187 IoCompleteRequest (Irp,
1188 IO_NO_INCREMENT);
1189 return;
1190 }
1191 }
1192
1193 /* Call the SCSI port driver */
1194 IoCallDriver (DeviceExtension->PortDeviceObject,
1195 Irp);
1196 }
1197
1198
1199 NTSTATUS STDCALL
1200 CdromDeviceControlCompletion (IN PDEVICE_OBJECT DeviceObject,
1201 IN PIRP Irp,
1202 IN PVOID Context)
1203 {
1204 PDEVICE_EXTENSION DeviceExtension;
1205 PDEVICE_EXTENSION PhysicalExtension;
1206 PIO_STACK_LOCATION IrpStack;
1207 PIO_STACK_LOCATION OrigCurrentIrpStack;
1208 PIO_STACK_LOCATION OrigNextIrpStack;
1209 PSCSI_REQUEST_BLOCK Srb;
1210 PIRP OrigIrp;
1211 BOOLEAN Retry;
1212 NTSTATUS Status;
1213
1214 DPRINT ("CdromDeviceControlCompletion() called\n");
1215
1216 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
1217 PhysicalExtension = (PDEVICE_EXTENSION)DeviceExtension->PhysicalDevice->DeviceExtension;
1218 Srb = (PSCSI_REQUEST_BLOCK) Context;
1219
1220 IrpStack = IoGetCurrentIrpStackLocation (Irp);
1221
1222 /* Get the original IRP */
1223 OrigIrp = (PIRP)IrpStack->Parameters.Others.Argument2;
1224 OrigCurrentIrpStack = IoGetCurrentIrpStackLocation (OrigIrp);
1225 OrigNextIrpStack = IoGetNextIrpStackLocation (OrigIrp);
1226
1227 if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS)
1228 {
1229 Status = STATUS_SUCCESS;
1230 }
1231 else
1232 {
1233 DPRINT ("SrbStatus %lx\n", Srb->SrbStatus);
1234
1235 /* Interpret sense info */
1236 Retry = ScsiClassInterpretSenseInfo (DeviceObject,
1237 Srb,
1238 IrpStack->MajorFunction,
1239 IrpStack->Parameters.DeviceIoControl.IoControlCode,
1240 MAXIMUM_RETRIES - (ULONG)OrigNextIrpStack->Parameters.Others.Argument1,
1241 &Status);
1242 DPRINT ("Retry %u\n", Retry);
1243
1244 if (Retry == TRUE &&
1245 (ULONG)OrigNextIrpStack->Parameters.Others.Argument1 > 0)
1246 {
1247 DPRINT1 ("Try again (Retry count %lu)\n",
1248 (ULONG)OrigNextIrpStack->Parameters.Others.Argument1);
1249
1250 (ULONG)OrigNextIrpStack->Parameters.Others.Argument1--;
1251
1252 /* Release 'old' buffers */
1253 ExFreePool (Srb->SenseInfoBuffer);
1254 if (Srb->DataBuffer)
1255 ExFreePool(Srb->DataBuffer);
1256 ExFreePool(Srb);
1257
1258 if (Irp->MdlAddress != NULL)
1259 IoFreeMdl(Irp->MdlAddress);
1260
1261 IoFreeIrp(Irp);
1262
1263 /* Call the StartIo routine again */
1264 CdromClassStartIo (DeviceObject,
1265 OrigIrp);
1266
1267 return STATUS_MORE_PROCESSING_REQUIRED;
1268 }
1269
1270 DPRINT ("Status %lx\n", Status);
1271 }
1272
1273 if (NT_SUCCESS (Status))
1274 {
1275 switch (OrigCurrentIrpStack->Parameters.DeviceIoControl.IoControlCode)
1276 {
1277 case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
1278 {
1279 PREAD_CAPACITY_DATA CapacityBuffer;
1280 ULONG LastSector;
1281 ULONG SectorSize;
1282
1283 DPRINT ("CdromClassControlCompletion: IOCTL_CDROM_GET_DRIVE_GEOMETRY\n");
1284
1285 CapacityBuffer = (PREAD_CAPACITY_DATA)Srb->DataBuffer;
1286 SectorSize = (((PUCHAR)&CapacityBuffer->BytesPerBlock)[0] << 24) |
1287 (((PUCHAR)&CapacityBuffer->BytesPerBlock)[1] << 16) |
1288 (((PUCHAR)&CapacityBuffer->BytesPerBlock)[2] << 8) |
1289 ((PUCHAR)&CapacityBuffer->BytesPerBlock)[3];
1290
1291 LastSector = (((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[0] << 24) |
1292 (((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[1] << 16) |
1293 (((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[2] << 8) |
1294 ((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[3];
1295
1296 if (SectorSize == 0)
1297 SectorSize = 2048;
1298 DeviceExtension->DiskGeometry->BytesPerSector = SectorSize;
1299
1300 DeviceExtension->PartitionLength.QuadPart = (LONGLONG)(LastSector + 1);
1301 WHICH_BIT(DeviceExtension->DiskGeometry->BytesPerSector,
1302 DeviceExtension->SectorShift);
1303 DeviceExtension->PartitionLength.QuadPart =
1304 (DeviceExtension->PartitionLength.QuadPart << DeviceExtension->SectorShift);
1305
1306 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
1307 {
1308 DeviceExtension->DiskGeometry->MediaType = RemovableMedia;
1309 }
1310 else
1311 {
1312 DeviceExtension->DiskGeometry->MediaType = FixedMedia;
1313 }
1314 DeviceExtension->DiskGeometry->Cylinders.QuadPart =
1315 (LONGLONG)((LastSector + 1)/(32 * 64));
1316 DeviceExtension->DiskGeometry->SectorsPerTrack = 32;
1317 DeviceExtension->DiskGeometry->TracksPerCylinder = 64;
1318
1319 RtlCopyMemory (OrigIrp->AssociatedIrp.SystemBuffer,
1320 DeviceExtension->DiskGeometry,
1321 sizeof(DISK_GEOMETRY));
1322 OrigIrp->IoStatus.Information = sizeof(DISK_GEOMETRY);
1323 }
1324 break;
1325
1326 case IOCTL_CDROM_CHECK_VERIFY:
1327 DPRINT ("CdromDeviceControlCompletion: IOCTL_CDROM_CHECK_VERIFY\n");
1328 if (OrigCurrentIrpStack->Parameters.DeviceIoControl.OutputBufferLength != 0)
1329 {
1330 /* Return the media change counter */
1331 *((PULONG)(OrigIrp->AssociatedIrp.SystemBuffer)) =
1332 PhysicalExtension->MediaChangeCount;
1333 OrigIrp->IoStatus.Information = sizeof(ULONG);
1334 }
1335 else
1336 {
1337 OrigIrp->IoStatus.Information = 0;
1338 }
1339 break;
1340
1341 default:
1342 OrigIrp->IoStatus.Information = 0;
1343 Status = STATUS_INVALID_DEVICE_REQUEST;
1344 break;
1345 }
1346 }
1347
1348 /* Release the SRB and associated buffers */
1349 if (Srb != NULL)
1350 {
1351 DPRINT("Srb %p\n", Srb);
1352
1353 if (Srb->DataBuffer != NULL)
1354 ExFreePool (Srb->DataBuffer);
1355
1356 if (Srb->SenseInfoBuffer != NULL)
1357 ExFreePool (Srb->SenseInfoBuffer);
1358
1359 ExFreePool (Srb);
1360 }
1361
1362 if (OrigIrp->PendingReturned)
1363 {
1364 IoMarkIrpPending (OrigIrp);
1365 }
1366
1367 /* Release the MDL */
1368 if (Irp->MdlAddress != NULL)
1369 {
1370 IoFreeMdl (Irp->MdlAddress);
1371 }
1372
1373 /* Release the sub irp */
1374 IoFreeIrp (Irp);
1375
1376 /* Set io status information */
1377 OrigIrp->IoStatus.Status = Status;
1378 if (!NT_SUCCESS(Status) && IoIsErrorUserInduced (Status))
1379 {
1380 IoSetHardErrorOrVerifyDevice (OrigIrp,
1381 DeviceObject);
1382 OrigIrp->IoStatus.Information = 0;
1383 }
1384
1385 /* Complete the original IRP */
1386 IoCompleteRequest (OrigIrp,
1387 IO_DISK_INCREMENT);
1388 IoStartNextPacket (DeviceObject,
1389 FALSE);
1390
1391 DPRINT ("CdromDeviceControlCompletion() done\n");
1392
1393 return STATUS_MORE_PROCESSING_REQUIRED;
1394 }
1395
1396
1397 VOID STDCALL
1398 CdromTimerRoutine(PDEVICE_OBJECT DeviceObject,
1399 PVOID Context)
1400 {
1401 DPRINT ("CdromTimerRoutine() called\n");
1402
1403 }
1404
1405 /* EOF */