migrate substitution keywords to SVN
[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$
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 #include <ntos/minmax.h>
41
42 #define NDEBUG
43 #include <debug.h>
44
45 #define VERSION "0.0.1"
46
47
48 #define SCSI_CDROM_TIMEOUT 10 /* Default timeout: 10 seconds */
49
50
51 typedef struct _ERROR_RECOVERY_DATA6
52 {
53 MODE_PARAMETER_HEADER Header;
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_READ_RECOVERY_PAGE ReadRecoveryPage;
62 } ERROR_RECOVERY_DATA10, *PERROR_RECOVERY_DATA10;
63
64 typedef struct _MODE_CAPABILITIES_DATA6
65 {
66 MODE_PARAMETER_HEADER Header;
67 MODE_CAPABILITIES_PAGE2 CababilitiesPage;
68 } MODE_CAPABILITIES_DATA6, *PMODE_CAPABILITIES_DATA6;
69
70 typedef struct _MODE_CAPABILITIES_DATA10
71 {
72 MODE_PARAMETER_HEADER10 Header;
73 MODE_CAPABILITIES_PAGE2 CababilitiesPage;
74 } MODE_CAPABILITIES_DATA10, *PMODE_CAPABILITIES_DATA10;
75
76 typedef struct _CDROM_DATA
77 {
78 BOOLEAN PlayActive;
79 BOOLEAN RawAccess;
80 USHORT XaFlags;
81
82 } CDROM_DATA, *PCDROM_DATA;
83
84 /* CDROM_DATA.XaFlags */
85 #define XA_USE_6_BYTE 0x0001
86 #define XA_USE_10_BYTE 0x0002
87 #define XA_USE_READ_CD 0x0004
88 #define XA_NOT_SUPPORTED 0x0008
89
90
91 BOOLEAN STDCALL
92 CdromClassFindDevices(IN PDRIVER_OBJECT DriverObject,
93 IN PUNICODE_STRING RegistryPath,
94 IN PCLASS_INIT_DATA InitializationData,
95 IN PDEVICE_OBJECT PortDeviceObject,
96 IN ULONG PortNumber);
97
98 BOOLEAN STDCALL
99 CdromClassCheckDevice(IN PINQUIRYDATA InquiryData);
100
101 NTSTATUS STDCALL
102 CdromClassCheckReadWrite(IN PDEVICE_OBJECT DeviceObject,
103 IN PIRP Irp);
104
105 static VOID
106 CdromClassCreateMediaChangeEvent(IN PDEVICE_EXTENSION DeviceExtension,
107 IN ULONG DeviceNumber);
108
109 static NTSTATUS
110 CdromClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
111 IN PUNICODE_STRING RegistryPath,
112 IN PDEVICE_OBJECT PortDeviceObject,
113 IN ULONG PortNumber,
114 IN ULONG DeviceNumber,
115 IN PIO_SCSI_CAPABILITIES Capabilities,
116 IN PSCSI_INQUIRY_DATA InquiryData,
117 IN PCLASS_INIT_DATA InitializationData);
118
119
120 NTSTATUS STDCALL
121 CdromClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
122 IN PIRP Irp);
123
124 VOID STDCALL
125 CdromClassStartIo (IN PDEVICE_OBJECT DeviceObject,
126 IN PIRP Irp);
127
128 NTSTATUS STDCALL
129 CdromDeviceControlCompletion (IN PDEVICE_OBJECT DeviceObject,
130 IN PIRP Irp,
131 IN PVOID Context);
132
133 VOID STDCALL
134 CdromTimerRoutine(IN PDEVICE_OBJECT DeviceObject,
135 IN PVOID Context);
136
137
138 /* FUNCTIONS ****************************************************************/
139
140 /**********************************************************************
141 * NAME EXPORTED
142 * DriverEntry
143 *
144 * DESCRIPTION:
145 * This function initializes the driver, locates and claims
146 * hardware resources, and creates various NT objects needed
147 * to process I/O requests.
148 *
149 * RUN LEVEL:
150 * PASSIVE_LEVEL
151 *
152 * ARGUMENTS:
153 * DriverObject
154 * System allocated Driver Object for this driver
155 * RegistryPath
156 * Name of registry driver service key
157 *
158 * RETURNS:
159 * Status.
160 */
161
162 NTSTATUS STDCALL
163 DriverEntry(IN PDRIVER_OBJECT DriverObject,
164 IN PUNICODE_STRING RegistryPath)
165 {
166 CLASS_INIT_DATA InitData;
167
168 DPRINT("CD-ROM Class Driver %s\n",
169 VERSION);
170 DPRINT("RegistryPath '%wZ'\n",
171 RegistryPath);
172
173 InitData.InitializationDataSize = sizeof(CLASS_INIT_DATA);
174 InitData.DeviceExtensionSize = sizeof(DEVICE_EXTENSION) + sizeof(CDROM_DATA);
175 InitData.DeviceType = FILE_DEVICE_CD_ROM;
176 InitData.DeviceCharacteristics = FILE_REMOVABLE_MEDIA | FILE_READ_ONLY_DEVICE;
177
178 InitData.ClassError = NULL;
179 InitData.ClassReadWriteVerification = CdromClassCheckReadWrite;
180 InitData.ClassFindDeviceCallBack = CdromClassCheckDevice;
181 InitData.ClassFindDevices = CdromClassFindDevices;
182 InitData.ClassDeviceControl = CdromClassDeviceControl;
183 InitData.ClassShutdownFlush = NULL;
184 InitData.ClassCreateClose = NULL;
185 InitData.ClassStartIo = CdromClassStartIo;
186
187 return(ScsiClassInitialize(DriverObject,
188 RegistryPath,
189 &InitData));
190 }
191
192
193 /**********************************************************************
194 * NAME EXPORTED
195 * CdromClassFindDevices
196 *
197 * DESCRIPTION:
198 * This function searches for device that are attached to the
199 * given scsi port.
200 *
201 * RUN LEVEL:
202 * PASSIVE_LEVEL
203 *
204 * ARGUMENTS:
205 * DriverObject
206 * System allocated Driver Object for this driver
207 * RegistryPath
208 * Name of registry driver service key.
209 * InitializationData
210 * Pointer to the main initialization data
211 * PortDeviceObject
212 * Scsi port device object
213 * PortNumber
214 * Port number
215 *
216 * RETURNS:
217 * TRUE: At least one disk drive was found
218 * FALSE: No disk drive found
219 */
220
221 BOOLEAN STDCALL
222 CdromClassFindDevices(IN PDRIVER_OBJECT DriverObject,
223 IN PUNICODE_STRING RegistryPath,
224 IN PCLASS_INIT_DATA InitializationData,
225 IN PDEVICE_OBJECT PortDeviceObject,
226 IN ULONG PortNumber)
227 {
228 PCONFIGURATION_INFORMATION ConfigInfo;
229 PIO_SCSI_CAPABILITIES PortCapabilities;
230 PSCSI_ADAPTER_BUS_INFO AdapterBusInfo;
231 PSCSI_INQUIRY_DATA UnitInfo;
232 PINQUIRYDATA InquiryData;
233 PCHAR Buffer;
234 ULONG Bus;
235 ULONG DeviceCount;
236 BOOLEAN FoundDevice = FALSE;
237 NTSTATUS Status;
238
239 DPRINT("CdromClassFindDevices() called.\n");
240
241 /* Get port capabilities */
242 Status = ScsiClassGetCapabilities(PortDeviceObject,
243 &PortCapabilities);
244 if (!NT_SUCCESS(Status))
245 {
246 DPRINT1("ScsiClassGetCapabilities() failed! (Status 0x%lX)\n", Status);
247 return(FALSE);
248 }
249
250 DPRINT("PortCapabilities: %p\n", PortCapabilities);
251 DPRINT("MaximumTransferLength: %lu\n", PortCapabilities->MaximumTransferLength);
252 DPRINT("MaximumPhysicalPages: %lu\n", PortCapabilities->MaximumPhysicalPages);
253
254 /* Get inquiry data */
255 Status = ScsiClassGetInquiryData(PortDeviceObject,
256 (PSCSI_ADAPTER_BUS_INFO *)&Buffer);
257 if (!NT_SUCCESS(Status))
258 {
259 DPRINT1("ScsiClassGetInquiryData() failed! (Status 0x%lX)\n", Status);
260 return(FALSE);
261 }
262
263 /* Check whether there are unclaimed devices */
264 AdapterBusInfo = (PSCSI_ADAPTER_BUS_INFO)Buffer;
265 DeviceCount = ScsiClassFindUnclaimedDevices(InitializationData,
266 AdapterBusInfo);
267 if (DeviceCount == 0)
268 {
269 DPRINT("No unclaimed devices!\n");
270 return(FALSE);
271 }
272
273 DPRINT("Found %lu unclaimed devices!\n", DeviceCount);
274
275 ConfigInfo = IoGetConfigurationInformation();
276 DPRINT("Number of SCSI ports: %lu\n", ConfigInfo->ScsiPortCount);
277
278 /* Search each bus of this adapter */
279 for (Bus = 0; Bus < (ULONG)AdapterBusInfo->NumberOfBuses; Bus++)
280 {
281 DPRINT("Searching bus %lu\n", Bus);
282
283 UnitInfo = (PSCSI_INQUIRY_DATA)(Buffer + AdapterBusInfo->BusData[Bus].InquiryDataOffset);
284
285 while (AdapterBusInfo->BusData[Bus].InquiryDataOffset)
286 {
287 InquiryData = (PINQUIRYDATA)UnitInfo->InquiryData;
288
289 if ((InquiryData->DeviceType == READ_ONLY_DIRECT_ACCESS_DEVICE) &&
290 (InquiryData->DeviceTypeQualifier == 0) &&
291 (UnitInfo->DeviceClaimed == FALSE))
292 {
293 DPRINT("Vendor: '%.24s'\n",
294 InquiryData->VendorId);
295
296 /* Create device objects for disk */
297 Status = CdromClassCreateDeviceObject(DriverObject,
298 RegistryPath,
299 PortDeviceObject,
300 PortNumber,
301 ConfigInfo->CdRomCount,
302 PortCapabilities,
303 UnitInfo,
304 InitializationData);
305 if (NT_SUCCESS(Status))
306 {
307 ConfigInfo->CdRomCount++;
308 FoundDevice = TRUE;
309 }
310 }
311
312 if (UnitInfo->NextInquiryDataOffset == 0)
313 break;
314
315 UnitInfo = (PSCSI_INQUIRY_DATA)(Buffer + UnitInfo->NextInquiryDataOffset);
316 }
317 }
318
319 ExFreePool(Buffer);
320
321 DPRINT("CdromClassFindDevices() done\n");
322
323 return(FoundDevice);
324 }
325
326
327 /**********************************************************************
328 * NAME EXPORTED
329 * CdromClassCheckDevice
330 *
331 * DESCRIPTION
332 * This function checks the InquiryData for the correct device
333 * type and qualifier.
334 *
335 * RUN LEVEL
336 * PASSIVE_LEVEL
337 *
338 * ARGUMENTS
339 * InquiryData
340 * Pointer to the inquiry data for the device in question.
341 *
342 * RETURN VALUE
343 * TRUE: A disk device was found.
344 * FALSE: Otherwise.
345 */
346
347 BOOLEAN STDCALL
348 CdromClassCheckDevice(IN PINQUIRYDATA InquiryData)
349 {
350 return((InquiryData->DeviceType == READ_ONLY_DIRECT_ACCESS_DEVICE) &&
351 (InquiryData->DeviceTypeQualifier == 0));
352 }
353
354
355 /**********************************************************************
356 * NAME EXPORTED
357 * CdromClassCheckReadWrite
358 *
359 * DESCRIPTION
360 * This function checks the given IRP for correct data.
361 *
362 * RUN LEVEL
363 * PASSIVE_LEVEL
364 *
365 * ARGUMENTS
366 * DeviceObject
367 * Pointer to the device.
368 * Irp
369 * Irp to check.
370 *
371 * RETURN VALUE
372 * STATUS_SUCCESS: The IRP matches the requirements of the given device.
373 * Others: Failure.
374 */
375
376 NTSTATUS STDCALL
377 CdromClassCheckReadWrite(IN PDEVICE_OBJECT DeviceObject,
378 IN PIRP Irp)
379 {
380 DPRINT("CdromClassCheckReadWrite() called\n");
381
382 return(STATUS_SUCCESS);
383 }
384
385
386 static VOID
387 CdromClassCreateMediaChangeEvent(IN PDEVICE_EXTENSION DeviceExtension,
388 IN ULONG DeviceNumber)
389 {
390 WCHAR NameBuffer[MAX_PATH];
391 UNICODE_STRING Name;
392
393 swprintf (NameBuffer,
394 L"\\Device\\MediaChangeEvent%lu",
395 DeviceNumber);
396 RtlInitUnicodeString (&Name,
397 NameBuffer);
398
399 DeviceExtension->MediaChangeEvent =
400 IoCreateSynchronizationEvent (&Name,
401 &DeviceExtension->MediaChangeEventHandle);
402
403 KeClearEvent (DeviceExtension->MediaChangeEvent);
404 }
405
406
407 /**********************************************************************
408 * NAME EXPORTED
409 * CdromClassCreateDeviceObject
410 *
411 * DESCRIPTION:
412 * Create the raw device and any partition devices on this drive
413 *
414 * RUN LEVEL:
415 * PASSIVE_LEVEL
416 *
417 * ARGUMENTS:
418 * DriverObject
419 * System allocated Driver Object for this driver.
420 * RegistryPath
421 * Name of registry driver service key.
422 * PortDeviceObject
423 * PortNumber
424 * DeviceNumber
425 * Capabilities
426 * InquiryData
427 * InitializationData
428 *
429 * RETURNS:
430 * Status.
431 */
432
433 static NTSTATUS
434 CdromClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
435 IN PUNICODE_STRING RegistryPath,
436 IN PDEVICE_OBJECT PortDeviceObject,
437 IN ULONG PortNumber,
438 IN ULONG DeviceNumber,
439 IN PIO_SCSI_CAPABILITIES Capabilities,
440 IN PSCSI_INQUIRY_DATA InquiryData,
441 IN PCLASS_INIT_DATA InitializationData)
442 {
443 PDEVICE_EXTENSION DiskDeviceExtension; /* defined in class2.h */
444 PDEVICE_OBJECT DiskDeviceObject;
445 PCDROM_DATA CdromData;
446 CHAR NameBuffer[80];
447 SCSI_REQUEST_BLOCK Srb;
448 PUCHAR Buffer;
449 ULONG Length;
450 PCDB Cdb;
451 NTSTATUS Status;
452
453 DPRINT("CdromClassCreateDeviceObject() called\n");
454
455 /* Claim the cdrom device */
456 Status = ScsiClassClaimDevice(PortDeviceObject,
457 InquiryData,
458 FALSE,
459 &PortDeviceObject);
460 if (!NT_SUCCESS(Status))
461 {
462 DbgPrint("Could not claim cdrom device\n");
463 return(Status);
464 }
465
466 /* Create cdrom device */
467 sprintf(NameBuffer,
468 "\\Device\\CdRom%lu",
469 DeviceNumber);
470
471 Status = ScsiClassCreateDeviceObject(DriverObject,
472 NameBuffer,
473 NULL,
474 &DiskDeviceObject,
475 InitializationData);
476 if (!NT_SUCCESS(Status))
477 {
478 DPRINT1("ScsiClassCreateDeviceObject() failed (Status %x)\n", Status);
479
480 /* Release (unclaim) the disk */
481 ScsiClassClaimDevice(PortDeviceObject,
482 InquiryData,
483 TRUE,
484 NULL);
485
486 return(Status);
487 }
488
489 DiskDeviceObject->Flags |= DO_DIRECT_IO;
490 DiskDeviceObject->Characteristics |= FILE_REMOVABLE_MEDIA;
491 DiskDeviceObject->StackSize = (CCHAR)PortDeviceObject->StackSize + 1;
492
493 if (PortDeviceObject->AlignmentRequirement > DiskDeviceObject->AlignmentRequirement)
494 {
495 DiskDeviceObject->AlignmentRequirement = PortDeviceObject->AlignmentRequirement;
496 }
497
498 DiskDeviceExtension = DiskDeviceObject->DeviceExtension;
499 DiskDeviceExtension->LockCount = 0;
500 DiskDeviceExtension->DeviceNumber = DeviceNumber;
501 DiskDeviceExtension->DeviceObject = DiskDeviceObject;
502 DiskDeviceExtension->PortDeviceObject = PortDeviceObject;
503 DiskDeviceExtension->PhysicalDevice = DiskDeviceObject;
504 DiskDeviceExtension->PortCapabilities = Capabilities;
505 DiskDeviceExtension->StartingOffset.QuadPart = 0;
506 DiskDeviceExtension->PortNumber = (UCHAR)PortNumber;
507 DiskDeviceExtension->PathId = InquiryData->PathId;
508 DiskDeviceExtension->TargetId = InquiryData->TargetId;
509 DiskDeviceExtension->Lun = InquiryData->Lun;
510
511 /* zero-out disk data */
512 CdromData = (PCDROM_DATA)(DiskDeviceExtension + 1);
513 RtlZeroMemory(CdromData,
514 sizeof(CDROM_DATA));
515
516 DiskDeviceExtension->SenseData = ExAllocatePool(NonPagedPool,
517 sizeof(SENSE_DATA));
518 if (DiskDeviceExtension->SenseData == NULL)
519 {
520 DPRINT1("Failed to allocate sense data buffer!\n");
521
522 IoDeleteDevice(DiskDeviceObject);
523
524 /* Release (unclaim) the disk */
525 ScsiClassClaimDevice(PortDeviceObject,
526 InquiryData,
527 TRUE,
528 NULL);
529
530 return(STATUS_INSUFFICIENT_RESOURCES);
531 }
532
533 /* Get timeout value */
534 DiskDeviceExtension->TimeOutValue =
535 ScsiClassQueryTimeOutRegistryValue(RegistryPath);
536 if (DiskDeviceExtension->TimeOutValue == 0)
537 DiskDeviceExtension->TimeOutValue = SCSI_CDROM_TIMEOUT;
538
539 /* Initialize lookaside list for SRBs */
540 ScsiClassInitializeSrbLookasideList(DiskDeviceExtension,
541 4);
542
543 /* Get disk geometry */
544 DiskDeviceExtension->DiskGeometry = ExAllocatePool(NonPagedPool,
545 sizeof(DISK_GEOMETRY));
546 if (DiskDeviceExtension->DiskGeometry == NULL)
547 {
548 DPRINT1("Failed to allocate geometry buffer!\n");
549
550 ExDeleteNPagedLookasideList(&DiskDeviceExtension->SrbLookasideListHead);
551
552 IoDeleteDevice(DiskDeviceObject);
553
554 /* Release (unclaim) the disk */
555 ScsiClassClaimDevice(PortDeviceObject,
556 InquiryData,
557 TRUE,
558 NULL);
559
560 return(STATUS_INSUFFICIENT_RESOURCES);
561 }
562
563 /* Read the drive's capacity */
564 Status = ScsiClassReadDriveCapacity(DiskDeviceObject);
565 if (!NT_SUCCESS(Status) ||
566 DiskDeviceExtension->DiskGeometry->BytesPerSector == 0)
567 {
568 /* Set ISO9660 defaults */
569 DiskDeviceExtension->DiskGeometry->BytesPerSector = 2048;
570 DiskDeviceExtension->DiskGeometry->MediaType = RemovableMedia;
571 DiskDeviceExtension->SectorShift = 11;
572 DiskDeviceExtension->PartitionLength.QuadPart = (ULONGLONG)0x7fffffff;
573 }
574 else
575 {
576 /* Make sure the BytesPerSector value is a power of 2 */
577 // DiskDeviceExtension->DiskGeometry->BytesPerSector = 2048;
578 }
579
580 DPRINT("SectorSize: %lu\n", DiskDeviceExtension->DiskGeometry->BytesPerSector);
581
582 /* Initialize media change support */
583 CdromClassCreateMediaChangeEvent (DiskDeviceExtension,
584 DeviceNumber);
585 if (DiskDeviceExtension->MediaChangeEvent != NULL)
586 {
587 DPRINT("Allocated media change event!\n");
588
589 /* FIXME: Allocate media change IRP and SRB */
590 }
591
592 /* Use 6 byte xa commands by default */
593 CdromData->XaFlags |= XA_USE_6_BYTE;
594
595 /* Read 'error recovery page' to get additional drive capabilities */
596 Length = sizeof(MODE_READ_RECOVERY_PAGE) + MODE_HEADER_LENGTH;
597
598 RtlZeroMemory (&Srb,
599 sizeof(SCSI_REQUEST_BLOCK));
600 Srb.CdbLength = 6;
601 Srb.TimeOutValue = DiskDeviceExtension->TimeOutValue;
602
603 Cdb = (PCDB)Srb.Cdb;
604 Cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
605 Cdb->MODE_SENSE.PageCode = 0x01;
606 Cdb->MODE_SENSE.AllocationLength = (UCHAR)Length;
607
608 Buffer = ExAllocatePool (NonPagedPool,
609 max(sizeof(ERROR_RECOVERY_DATA6),
610 max(sizeof(ERROR_RECOVERY_DATA10),
611 max(sizeof(MODE_CAPABILITIES_DATA6),
612 sizeof(MODE_CAPABILITIES_DATA10)))));
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
625 if (!NT_SUCCESS (Status))
626 {
627 DPRINT("MODE_SENSE(6) failed\n");
628
629 /* Try the 10 byte version */
630 Length = sizeof(MODE_READ_RECOVERY_PAGE) + MODE_HEADER_LENGTH10;
631
632 RtlZeroMemory (&Srb,
633 sizeof(SCSI_REQUEST_BLOCK));
634 Srb.CdbLength = 10;
635 Srb.TimeOutValue = DiskDeviceExtension->TimeOutValue;
636
637 Cdb = (PCDB)Srb.Cdb;
638 Cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
639 Cdb->MODE_SENSE10.PageCode = 0x01;
640 Cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(Length >> 8);
641 Cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(Length & 0xFF);
642
643 Status = ScsiClassSendSrbSynchronous (DiskDeviceObject,
644 &Srb,
645 Buffer,
646 Length,
647 FALSE);
648
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 CdromData->XaFlags &= XA_USE_6_BYTE;
659 CdromData->XaFlags |= XA_USE_10_BYTE;
660 }
661 else
662 {
663 DPRINT("XA not supported\n");
664 CdromData->XaFlags |= XA_NOT_SUPPORTED;
665 }
666 }
667 else
668 {
669 DPRINT("Use 6 byte commands\n");
670 }
671
672 /* Read 'capabilities & mechanical status page' to get additional drive capabilities */
673 Length = sizeof(MODE_READ_RECOVERY_PAGE) + MODE_HEADER_LENGTH;
674
675 if (!(CdromData->XaFlags & XA_NOT_SUPPORTED))
676 {
677 RtlZeroMemory (&Srb, sizeof(SCSI_REQUEST_BLOCK));
678 Srb.TimeOutValue = DiskDeviceExtension->TimeOutValue;
679 Cdb = (PCDB)Srb.Cdb;
680
681 if (CdromData->XaFlags & XA_USE_10_BYTE)
682 {
683 /* Try the 10 byte version */
684 Length = sizeof(MODE_CAPABILITIES_PAGE2) + MODE_HEADER_LENGTH10;
685
686 Srb.CdbLength = 10;
687 Cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
688 Cdb->MODE_SENSE10.PageCode = 0x2a;
689 Cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(Length >> 8);
690 Cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(Length & 0xFF);
691 }
692 else
693 {
694 Length = sizeof(MODE_CAPABILITIES_PAGE2) + MODE_HEADER_LENGTH;
695
696 Srb.CdbLength = 6;
697 Cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
698 Cdb->MODE_SENSE.PageCode = 0x2a;
699 Cdb->MODE_SENSE.AllocationLength = (UCHAR)Length;
700 }
701 Status = ScsiClassSendSrbSynchronous (DiskDeviceObject,
702 &Srb,
703 Buffer,
704 Length,
705 FALSE);
706 if (NT_SUCCESS (Status))
707 {
708 #if 0
709 PMODE_CAPABILITIES_PAGE2 CapabilitiesData;
710 if (CdromData->XaFlags & XA_USE_10_BYTE)
711 {
712 CapabilitiesData = (PMODE_CAPABILITIES_PAGE2)(Buffer + sizeof(MODE_PARAMETER_HEADER10));
713 }
714 else
715 {
716 CapabilitiesData = (PMODE_CAPABILITIES_PAGE2)(Buffer + sizeof(MODE_PARAMETER_HEADER));
717 }
718
719 DbgPrint("Capabilities for '%s':\n", NameBuffer);
720 if (CapabilitiesData->Reserved2[0] & 0x20)
721 {
722 DbgPrint(" Drive supports reading of DVD-RAM discs\n");
723 }
724 if (CapabilitiesData->Reserved2[0] & 0x10)
725 {
726 DbgPrint(" Drive supports reading of DVD-R discs\n");
727 }
728 if (CapabilitiesData->Reserved2[0] & 0x08)
729 {
730 DbgPrint(" Drive supports reading of DVD-ROM discs\n");
731 }
732 if (CapabilitiesData->Reserved2[0] & 0x04)
733 {
734 DbgPrint(" Drive supports reading CD-R discs with addressing method 2\n");
735 }
736 if (CapabilitiesData->Reserved2[0] & 0x02)
737 {
738 DbgPrint(" Drive can read from CD-R/W (CD-E) discs (orange book, part III)\n");
739 }
740 if (CapabilitiesData->Reserved2[0] & 0x01)
741 {
742 DbgPrint(" Drive supports read from CD-R discs (orange book, part II)\n");
743 }
744 DPRINT("CapabilitiesData.Reserved2[1] %x\n", CapabilitiesData->Reserved2[1]);
745 if (CapabilitiesData->Reserved2[1] & 0x01)
746 {
747 DbgPrint(" Drive can write to CD-R discs (orange book, part II)\n");
748 }
749 if (CapabilitiesData->Reserved2[1] & 0x02)
750 {
751 DbgPrint(" Drive can write to CD-R/W (CD-E) discs (orange book, part III)\n");
752 }
753 if (CapabilitiesData->Reserved2[1] & 0x04)
754 {
755 DbgPrint(" Drive can fake writes\n");
756 }
757 if (CapabilitiesData->Reserved2[1] & 0x10)
758 {
759 DbgPrint(" Drive can write DVD-R discs\n");
760 }
761 if (CapabilitiesData->Reserved2[1] & 0x20)
762 {
763 DbgPrint(" Drive can write DVD-RAM discs\n");
764 }
765 DPRINT("CapabilitiesData.Capabilities[0] %x\n", CapabilitiesData->Capabilities[0]);
766 if (CapabilitiesData->Capabilities[0] & 0x01)
767 {
768 DbgPrint(" Drive supports audio play operations\n");
769 }
770 if (CapabilitiesData->Capabilities[0] & 0x02)
771 {
772 DbgPrint(" Drive can deliver a composite audio/video data stream\n");
773 }
774 if (CapabilitiesData->Capabilities[0] & 0x04)
775 {
776 DbgPrint(" Drive supports digital output on port 1\n");
777 }
778 if (CapabilitiesData->Capabilities[0] & 0x08)
779 {
780 DbgPrint(" Drive supports digital output on port 2\n");
781 }
782 if (CapabilitiesData->Capabilities[0] & 0x10)
783 {
784 DbgPrint(" Drive can read mode 2, form 1 (XA) data\n");
785 }
786 if (CapabilitiesData->Capabilities[0] & 0x20)
787 {
788 DbgPrint(" Drive can read mode 2, form 2 data\n");
789 }
790 if (CapabilitiesData->Capabilities[0] & 0x40)
791 {
792 DbgPrint(" Drive can read multisession discs\n");
793 }
794 DPRINT("CapabilitiesData.Capabilities[1] %x\n", CapabilitiesData->Capabilities[1]);
795 if (CapabilitiesData->Capabilities[1] & 0x01)
796 {
797 DbgPrint(" Drive can read Red Book audio data\n");
798 }
799 if (CapabilitiesData->Capabilities[1] & 0x02)
800 {
801 DbgPrint(" Drive can continue a read cdda operation from a loss of streaming\n");
802 }
803 if (CapabilitiesData->Capabilities[1] & 0x04)
804 {
805 DbgPrint(" Subchannel reads can return combined R-W information\n");
806 }
807 if (CapabilitiesData->Capabilities[1] & 0x08)
808 {
809 DbgPrint(" R-W data will be returned deinterleaved and error corrected\n");
810 }
811 if (CapabilitiesData->Capabilities[1] & 0x10)
812 {
813 DbgPrint(" Drive supports C2 error pointers\n");
814 }
815 if (CapabilitiesData->Capabilities[1] & 0x20)
816 {
817 DbgPrint(" Drive can return International Standard Recording Code info\n");
818 }
819 if (CapabilitiesData->Capabilities[1] & 0x40)
820 {
821 DbgPrint(" Drive can return Media Catalog Number (UPC) info\n");
822 }
823 DPRINT("CapabilitiesData.Capabilities[2] %x\n", CapabilitiesData->Capabilities[2]);
824 if (CapabilitiesData->Capabilities[2] & 0x01)
825 {
826 DbgPrint(" Drive can lock the door\n");
827 }
828 if (CapabilitiesData->Capabilities[2] & 0x02)
829 {
830 DbgPrint(" The door is locked\n");
831 }
832 if (CapabilitiesData->Capabilities[2] & 0x04)
833 {
834 }
835 if (CapabilitiesData->Capabilities[2] & 0x08)
836 {
837 DbgPrint(" Drive can eject a disc or changer cartridge\n");
838 }
839 if (CapabilitiesData->Capabilities[2] & 0x10)
840 {
841 DbgPrint(" Drive supports C2 error pointers\n");
842 }
843 switch (CapabilitiesData->Capabilities[2] >> 5)
844 {
845 case 0:
846 DbgPrint(" Drive use a caddy type loading mechanism\n");
847 break;
848 case 1:
849 DbgPrint(" Drive use a tray type loading mechanism\n");
850 break;
851 case 2:
852 DbgPrint(" Drive use a pop-up type loading mechanism\n");
853 break;
854 case 4:
855 DbgPrint(" Drive is a changer with individually changeable discs\n");
856 break;
857 case 5:
858 DbgPrint(" Drive is a changer with cartridge mechanism\n");
859 break;
860 }
861 DPRINT("CapabilitiesData.Capabilities[3] %x\n", CapabilitiesData->Capabilities[3]);
862 if (CapabilitiesData->Capabilities[3] & 0x01)
863 {
864 DbgPrint(" Audio level for each channel can be controlled independently\n");
865 }
866 if (CapabilitiesData->Capabilities[3] & 0x02)
867 {
868 DbgPrint(" Audio for each channel can be muted independently\n");
869 }
870 if (CapabilitiesData->Capabilities[3] & 0x04)
871 {
872 DbgPrint(" Changer can report exact contents of slots\n");
873 }
874 if (CapabilitiesData->Capabilities[3] & 0x08)
875 {
876 DbgPrint(" Drive supports software slot selection\n");
877 }
878 DbgPrint(" Maximum speed is %d kB/s\n",
879 (CapabilitiesData->MaximumSpeedSupported[0] << 8)
880 | CapabilitiesData->MaximumSpeedSupported[1]);
881 DbgPrint(" Current speed is %d kB/s\n",
882 (CapabilitiesData->CurrentSpeed[0] << 8)
883 | CapabilitiesData->CurrentSpeed[1]);
884 DbgPrint(" Number of discrete volume levels is %d\n",
885 (CapabilitiesData->Reserved3 << 8)
886 | CapabilitiesData->NumberVolumeLevels);
887 DbgPrint(" Buffer size is %d kB\n",
888 (CapabilitiesData->BufferSize[0] << 8)
889 | CapabilitiesData->BufferSize[1]);
890 #endif
891 }
892 else
893 {
894 DPRINT("XA not supported\n");
895 CdromData->XaFlags |= XA_NOT_SUPPORTED;
896 }
897
898 }
899
900
901 ExFreePool (Buffer);
902
903 /* Initialize device timer */
904 IoInitializeTimer(DiskDeviceObject,
905 CdromTimerRoutine,
906 NULL);
907 IoStartTimer(DiskDeviceObject);
908
909 DPRINT("CdromClassCreateDeviceObjects() done\n");
910
911 return(STATUS_SUCCESS);
912 }
913
914
915 /**********************************************************************
916 * NAME
917 * CdromClassReadTocEntry
918 *
919 * ARGUMENTS:
920 * DeviceObject
921 * TrackNo
922 * Buffer
923 * Length
924 *
925 * RETURNS:
926 * Status.
927 */
928 static NTSTATUS
929 CdromClassReadTocEntry (PDEVICE_OBJECT DeviceObject,
930 UINT TrackNo,
931 PVOID Buffer,
932 UINT Length)
933 {
934 PDEVICE_EXTENSION DeviceExtension;
935 SCSI_REQUEST_BLOCK Srb;
936 PCDB Cdb;
937
938 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
939
940 RtlZeroMemory(&Srb, sizeof(SCSI_REQUEST_BLOCK));
941 Srb.CdbLength = 10;
942 Srb.TimeOutValue = DeviceExtension->TimeOutValue;
943
944 Cdb = (PCDB)Srb.Cdb;
945 Cdb->READ_TOC.OperationCode = SCSIOP_READ_TOC;
946 Cdb->READ_TOC.StartingTrack = TrackNo;
947 Cdb->READ_TOC.Format = 0;
948 Cdb->READ_TOC.AllocationLength[0] = Length >> 8;
949 Cdb->READ_TOC.AllocationLength[1] = Length & 0xff;
950 Cdb->READ_TOC.Msf = 1;
951
952 return(ScsiClassSendSrbSynchronous(DeviceObject,
953 &Srb,
954 Buffer,
955 Length,
956 FALSE));
957 }
958
959
960 static NTSTATUS
961 CdromClassReadLastSession (PDEVICE_OBJECT DeviceObject,
962 UINT TrackNo,
963 PVOID Buffer,
964 UINT Length)
965 {
966 PDEVICE_EXTENSION DeviceExtension;
967 SCSI_REQUEST_BLOCK Srb;
968 PCDB Cdb;
969
970 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
971
972 RtlZeroMemory(&Srb, sizeof(SCSI_REQUEST_BLOCK));
973 Srb.CdbLength = 10;
974 Srb.TimeOutValue = DeviceExtension->TimeOutValue;
975
976 Cdb = (PCDB)Srb.Cdb;
977 Cdb->READ_TOC.OperationCode = SCSIOP_READ_TOC;
978 Cdb->READ_TOC.StartingTrack = TrackNo;
979 Cdb->READ_TOC.Format = 1;
980 Cdb->READ_TOC.AllocationLength[0] = Length >> 8;
981 Cdb->READ_TOC.AllocationLength[1] = Length & 0xff;
982 Cdb->READ_TOC.Msf = 0;
983
984 return(ScsiClassSendSrbSynchronous(DeviceObject,
985 &Srb,
986 Buffer,
987 Length,
988 FALSE));
989 }
990
991
992 /**********************************************************************
993 * NAME EXPORTED
994 * CdromClassDeviceControl
995 *
996 * DESCRIPTION:
997 * Answer requests for device control calls
998 *
999 * RUN LEVEL:
1000 * PASSIVE_LEVEL
1001 *
1002 * ARGUMENTS:
1003 * DeviceObject
1004 * Irp
1005 * Standard dispatch arguments
1006 *
1007 * RETURNS:
1008 * Status.
1009 */
1010
1011 NTSTATUS STDCALL
1012 CdromClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
1013 IN PIRP Irp)
1014 {
1015 PDEVICE_EXTENSION DeviceExtension;
1016 PIO_STACK_LOCATION IrpStack;
1017 ULONG ControlCode, InputLength, OutputLength;
1018 PCDROM_DATA CdromData;
1019 ULONG Information;
1020 NTSTATUS Status;
1021
1022 DPRINT("CdromClassDeviceControl() called!\n");
1023
1024 Status = STATUS_INVALID_DEVICE_REQUEST;
1025 Information = 0;
1026 IrpStack = IoGetCurrentIrpStackLocation(Irp);
1027 ControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;
1028 InputLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
1029 OutputLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
1030 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
1031 CdromData = (PCDROM_DATA)(DeviceExtension + 1);
1032
1033 switch (ControlCode)
1034 {
1035 case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
1036 DPRINT ("CdromClassDeviceControl: IOCTL_CDROM_GET_DRIVE_GEOMETRY\n");
1037 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_GEOMETRY))
1038 {
1039 Status = STATUS_INFO_LENGTH_MISMATCH;
1040 break;
1041 }
1042 IoMarkIrpPending (Irp);
1043 IoStartPacket (DeviceObject,
1044 Irp,
1045 NULL,
1046 NULL);
1047 return STATUS_PENDING;
1048
1049 case IOCTL_CDROM_CHECK_VERIFY:
1050 DPRINT ("CdromClassDeviceControl: IOCTL_CDROM_CHECK_VERIFY\n");
1051 if (OutputLength != 0 && OutputLength < sizeof (ULONG))
1052 {
1053 DPRINT1("Buffer too small\n");
1054 Status = STATUS_BUFFER_TOO_SMALL;
1055 break;
1056 }
1057 IoMarkIrpPending (Irp);
1058 IoStartPacket (DeviceObject,
1059 Irp,
1060 NULL,
1061 NULL);
1062 return STATUS_PENDING;
1063
1064 case IOCTL_CDROM_READ_TOC:
1065 DPRINT("IOCTL_CDROM_READ_TOC\n");
1066 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(CDROM_TOC))
1067 {
1068 Status = STATUS_INFO_LENGTH_MISMATCH;
1069 }
1070 else
1071 {
1072 PCDROM_TOC TocBuffer;
1073 USHORT Length;
1074
1075 TocBuffer = Irp->AssociatedIrp.SystemBuffer;
1076
1077 /* First read the lead out */
1078 Length = 4 + sizeof(TRACK_DATA);
1079 Status = CdromClassReadTocEntry(DeviceObject,
1080 0xAA,
1081 TocBuffer,
1082 Length);
1083 if (NT_SUCCESS(Status))
1084 {
1085 if (TocBuffer->FirstTrack == 0xaa)
1086 {
1087 /* there is an empty cd */
1088 Information = Length;
1089 }
1090 else
1091 {
1092 /* read the toc */
1093 Length = 4 + sizeof(TRACK_DATA) * (TocBuffer->LastTrack - TocBuffer->FirstTrack + 2);
1094 Status = CdromClassReadTocEntry(DeviceObject,
1095 TocBuffer->FirstTrack,
1096 TocBuffer, Length);
1097 if (NT_SUCCESS(Status))
1098 {
1099 Information = Length;
1100 }
1101 }
1102 }
1103 }
1104 break;
1105
1106 case IOCTL_CDROM_GET_LAST_SESSION:
1107 DPRINT("IOCTL_CDROM_GET_LAST_SESSION\n");
1108 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < 4 + sizeof(TRACK_DATA))
1109 {
1110 Status = STATUS_INFO_LENGTH_MISMATCH;
1111 }
1112 else
1113 {
1114 PCDROM_TOC TocBuffer;
1115 USHORT Length;
1116
1117 TocBuffer = Irp->AssociatedIrp.SystemBuffer;
1118 Length = 4 + sizeof(TRACK_DATA);
1119 Status = CdromClassReadLastSession(DeviceObject,
1120 0,
1121 TocBuffer,
1122 Length);
1123 if (NT_SUCCESS(Status))
1124 {
1125 Information = Length;
1126 }
1127 }
1128 break;
1129
1130 default:
1131 /* Call the common device control function */
1132 return(ScsiClassDeviceControl(DeviceObject, Irp));
1133 }
1134
1135 /* Verify the device if the user caused the error */
1136 if (!NT_SUCCESS(Status) && IoIsErrorUserInduced(Status))
1137 {
1138 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
1139 }
1140
1141 Irp->IoStatus.Status = Status;
1142 Irp->IoStatus.Information = Information;
1143 IoCompleteRequest(Irp,
1144 IO_DISK_INCREMENT);
1145
1146 return Status;
1147 }
1148
1149
1150 /**********************************************************************
1151 * NAME
1152 * CdromClassStartIo
1153 *
1154 * DESCRIPTION:
1155 * Starts IRP processing.
1156 *
1157 * RUN LEVEL:
1158 * PASSIVE_LEVEL
1159 *
1160 * ARGUMENTS:
1161 * DeviceObject
1162 * Irp
1163 * Standard dispatch arguments
1164 *
1165 * RETURNS:
1166 * None.
1167 */
1168 VOID STDCALL
1169 CdromClassStartIo (IN PDEVICE_OBJECT DeviceObject,
1170 IN PIRP Irp)
1171 {
1172 PDEVICE_EXTENSION DeviceExtension;
1173 PIO_STACK_LOCATION IrpStack;
1174 PIO_STACK_LOCATION SubIrpStack;
1175 ULONG MaximumTransferLength;
1176 ULONG TransferPages;
1177 PSCSI_REQUEST_BLOCK Srb;
1178 PIRP SubIrp;
1179 PUCHAR SenseBuffer;
1180 PVOID DataBuffer;
1181 PCDB Cdb;
1182
1183 DPRINT("CdromClassStartIo() called!\n");
1184
1185 IoMarkIrpPending (Irp);
1186
1187 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
1188 IrpStack = IoGetCurrentIrpStackLocation (Irp);
1189
1190 MaximumTransferLength = DeviceExtension->PortCapabilities->MaximumTransferLength;
1191
1192 if (DeviceObject->Flags & DO_VERIFY_VOLUME)
1193 {
1194 if (!(IrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME))
1195 {
1196 DPRINT1 ("Verify required\n");
1197
1198 if (Irp->Tail.Overlay.Thread)
1199 {
1200 IoSetHardErrorOrVerifyDevice (Irp,
1201 DeviceObject);
1202 }
1203 Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
1204
1205 /* FIXME: Update drive capacity */
1206
1207 return;
1208 }
1209 }
1210
1211 if (IrpStack->MajorFunction == IRP_MJ_READ)
1212 {
1213 DPRINT ("CdromClassStartIo: IRP_MJ_READ\n");
1214
1215 TransferPages =
1216 ADDRESS_AND_SIZE_TO_SPAN_PAGES (MmGetMdlVirtualAddress(Irp->MdlAddress),
1217 IrpStack->Parameters.Read.Length);
1218
1219 /* Check transfer size */
1220 if ((IrpStack->Parameters.Read.Length > MaximumTransferLength) ||
1221 (TransferPages > DeviceExtension->PortCapabilities->MaximumPhysicalPages))
1222 {
1223 /* Transfer size is too large - split it */
1224 TransferPages =
1225 DeviceExtension->PortCapabilities->MaximumPhysicalPages - 1;
1226
1227 /* Adjust transfer size */
1228 if (MaximumTransferLength > TransferPages * PAGE_SIZE)
1229 MaximumTransferLength = TransferPages * PAGE_SIZE;
1230
1231 if (MaximumTransferLength == 0)
1232 MaximumTransferLength = PAGE_SIZE;
1233
1234 /* Split the transfer */
1235 ScsiClassSplitRequest (DeviceObject,
1236 Irp,
1237 MaximumTransferLength);
1238 return;
1239 }
1240 else
1241 {
1242 /* Build SRB */
1243 ScsiClassBuildRequest (DeviceObject,
1244 Irp);
1245 }
1246 }
1247 else if (IrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL)
1248 {
1249 DPRINT ("CdromClassStartIo: IRP_MJ_IRP_MJ_DEVICE_CONTROL\n");
1250
1251 /* Allocate an IRP for sending requests to the port driver */
1252 SubIrp = IoAllocateIrp ((CCHAR)(DeviceObject->StackSize + 1),
1253 FALSE);
1254 if (SubIrp == NULL)
1255 {
1256 Irp->IoStatus.Information = 0;
1257 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1258 IoCompleteRequest (Irp,
1259 IO_DISK_INCREMENT);
1260 IoStartNextPacket (DeviceObject,
1261 FALSE);
1262 return;
1263 }
1264
1265 /* Allocate an SRB */
1266 Srb = ExAllocatePool (NonPagedPool,
1267 sizeof (SCSI_REQUEST_BLOCK));
1268 if (Srb == NULL)
1269 {
1270 IoFreeIrp (SubIrp);
1271 Irp->IoStatus.Information = 0;
1272 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1273 IoCompleteRequest (Irp,
1274 IO_DISK_INCREMENT);
1275 IoStartNextPacket (DeviceObject,
1276 FALSE);
1277 return;
1278 }
1279
1280 /* Allocte a sense buffer */
1281 SenseBuffer = ExAllocatePool (NonPagedPoolCacheAligned,
1282 SENSE_BUFFER_SIZE);
1283 if (SenseBuffer == NULL)
1284 {
1285 ExFreePool (Srb);
1286 IoFreeIrp (SubIrp);
1287 Irp->IoStatus.Information = 0;
1288 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1289 IoCompleteRequest (Irp,
1290 IO_DISK_INCREMENT);
1291 IoStartNextPacket (DeviceObject,
1292 FALSE);
1293 return;
1294 }
1295
1296 /* Initialize the IRP */
1297 IoSetNextIrpStackLocation (SubIrp);
1298 SubIrp->IoStatus.Information = 0;
1299 SubIrp->IoStatus.Status = STATUS_SUCCESS;
1300 SubIrp->Flags = 0;
1301 SubIrp->UserBuffer = NULL;
1302
1303 SubIrpStack = IoGetCurrentIrpStackLocation (SubIrp);
1304 SubIrpStack->DeviceObject = DeviceExtension->DeviceObject;
1305 SubIrpStack->Parameters.Others.Argument2 = (PVOID)Irp;
1306
1307 /* Initialize next stack location */
1308 SubIrpStack = IoGetNextIrpStackLocation (SubIrp);
1309 SubIrpStack->MajorFunction = IRP_MJ_SCSI;
1310 SubIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
1311 SubIrpStack->Parameters.Scsi.Srb = Srb;
1312
1313 /* Initialize the SRB */
1314 RtlZeroMemory(Srb,
1315 sizeof (SCSI_REQUEST_BLOCK));
1316 Srb->Length = sizeof (SCSI_REQUEST_BLOCK);
1317 Srb->PathId = DeviceExtension->PathId;
1318 Srb->TargetId = DeviceExtension->TargetId;
1319 Srb->Lun = DeviceExtension->Lun;
1320 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1321 Srb->SrbStatus = SRB_STATUS_SUCCESS;
1322 Srb->ScsiStatus = 0;
1323 Srb->NextSrb = 0;
1324 Srb->OriginalRequest = SubIrp;
1325 Srb->SenseInfoBuffer = SenseBuffer;
1326 Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
1327
1328 /* Initialize the CDB */
1329 Cdb = (PCDB)Srb->Cdb;
1330
1331 /* Set the completion routine */
1332 IoSetCompletionRoutine (SubIrp,
1333 CdromDeviceControlCompletion,
1334 Srb,
1335 TRUE,
1336 TRUE,
1337 TRUE);
1338
1339 switch (IrpStack->Parameters.DeviceIoControl.IoControlCode)
1340 {
1341 case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
1342 DPRINT ("CdromClassStartIo: IOCTL_CDROM_GET_DRIVE_GEOMETRY\n");
1343 Srb->DataTransferLength = sizeof(READ_CAPACITY_DATA);
1344 Srb->CdbLength = 10;
1345 Srb->TimeOutValue = DeviceExtension->TimeOutValue;
1346 Srb->SrbFlags = SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN;
1347 Cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
1348
1349 /* Allocate data buffer */
1350 DataBuffer = ExAllocatePool (NonPagedPoolCacheAligned,
1351 sizeof(READ_CAPACITY_DATA));
1352 if (DataBuffer == NULL)
1353 {
1354 Irp->IoStatus.Information = 0;
1355 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1356 IoCompleteRequest (Irp,
1357 IO_DISK_INCREMENT);
1358 ExFreePool (SenseBuffer);
1359 ExFreePool (Srb);
1360 IoFreeIrp (SubIrp);
1361 IoStartNextPacket (DeviceObject,
1362 FALSE);
1363 return;
1364 }
1365
1366 /* Allocate an MDL for the data buffer */
1367 SubIrp->MdlAddress = IoAllocateMdl (DataBuffer,
1368 sizeof(READ_CAPACITY_DATA),
1369 FALSE,
1370 FALSE,
1371 NULL);
1372 if (SubIrp->MdlAddress == NULL)
1373 {
1374 Irp->IoStatus.Information = 0;
1375 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1376 IoCompleteRequest (Irp,
1377 IO_DISK_INCREMENT);
1378 ExFreePool (DataBuffer);
1379 ExFreePool (SenseBuffer);
1380 ExFreePool (Srb);
1381 IoFreeIrp (SubIrp);
1382 IoStartNextPacket (DeviceObject,
1383 FALSE);
1384 return;
1385 }
1386
1387 MmBuildMdlForNonPagedPool (SubIrp->MdlAddress);
1388 Srb->DataBuffer = DataBuffer;
1389
1390 IoCallDriver (DeviceExtension->PortDeviceObject,
1391 SubIrp);
1392 return;
1393
1394 case IOCTL_CDROM_CHECK_VERIFY:
1395 DPRINT ("CdromClassStartIo: IOCTL_CDROM_CHECK_VERIFY\n");
1396 Srb->CdbLength = 6;
1397 Srb->TimeOutValue = DeviceExtension->TimeOutValue * 2;
1398 Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;
1399 Cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
1400
1401 IoCallDriver (DeviceExtension->PortDeviceObject,
1402 SubIrp);
1403 return;
1404
1405 default:
1406 IoCompleteRequest (Irp,
1407 IO_NO_INCREMENT);
1408 return;
1409 }
1410 }
1411
1412 /* Call the SCSI port driver */
1413 IoCallDriver (DeviceExtension->PortDeviceObject,
1414 Irp);
1415 }
1416
1417
1418 NTSTATUS STDCALL
1419 CdromDeviceControlCompletion (IN PDEVICE_OBJECT DeviceObject,
1420 IN PIRP Irp,
1421 IN PVOID Context)
1422 {
1423 PDEVICE_EXTENSION DeviceExtension;
1424 PDEVICE_EXTENSION PhysicalExtension;
1425 PIO_STACK_LOCATION IrpStack;
1426 PIO_STACK_LOCATION OrigCurrentIrpStack;
1427 PIO_STACK_LOCATION OrigNextIrpStack;
1428 PSCSI_REQUEST_BLOCK Srb;
1429 PIRP OrigIrp;
1430 BOOLEAN Retry;
1431 NTSTATUS Status;
1432
1433 DPRINT ("CdromDeviceControlCompletion() called\n");
1434
1435 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
1436 PhysicalExtension = (PDEVICE_EXTENSION)DeviceExtension->PhysicalDevice->DeviceExtension;
1437 Srb = (PSCSI_REQUEST_BLOCK) Context;
1438
1439 IrpStack = IoGetCurrentIrpStackLocation (Irp);
1440
1441 /* Get the original IRP */
1442 OrigIrp = (PIRP)IrpStack->Parameters.Others.Argument2;
1443 OrigCurrentIrpStack = IoGetCurrentIrpStackLocation (OrigIrp);
1444 OrigNextIrpStack = IoGetNextIrpStackLocation (OrigIrp);
1445
1446 if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS)
1447 {
1448 Status = STATUS_SUCCESS;
1449 }
1450 else
1451 {
1452 DPRINT ("SrbStatus %lx\n", Srb->SrbStatus);
1453
1454 /* Interpret sense info */
1455 Retry = ScsiClassInterpretSenseInfo (DeviceObject,
1456 Srb,
1457 IrpStack->MajorFunction,
1458 IrpStack->Parameters.DeviceIoControl.IoControlCode,
1459 MAXIMUM_RETRIES - (ULONG)OrigNextIrpStack->Parameters.Others.Argument1,
1460 &Status);
1461 DPRINT ("Retry %u\n", Retry);
1462
1463 if (Retry == TRUE &&
1464 (ULONG)OrigNextIrpStack->Parameters.Others.Argument1 > 0)
1465 {
1466 DPRINT1 ("Try again (Retry count %lu)\n",
1467 (ULONG)OrigNextIrpStack->Parameters.Others.Argument1);
1468
1469 (ULONG)OrigNextIrpStack->Parameters.Others.Argument1--;
1470
1471 /* Release 'old' buffers */
1472 ExFreePool (Srb->SenseInfoBuffer);
1473 if (Srb->DataBuffer)
1474 ExFreePool(Srb->DataBuffer);
1475 ExFreePool(Srb);
1476
1477 if (Irp->MdlAddress != NULL)
1478 IoFreeMdl(Irp->MdlAddress);
1479
1480 IoFreeIrp(Irp);
1481
1482 /* Call the StartIo routine again */
1483 CdromClassStartIo (DeviceObject,
1484 OrigIrp);
1485
1486 return STATUS_MORE_PROCESSING_REQUIRED;
1487 }
1488
1489 DPRINT ("Status %lx\n", Status);
1490 }
1491
1492 if (NT_SUCCESS (Status))
1493 {
1494 switch (OrigCurrentIrpStack->Parameters.DeviceIoControl.IoControlCode)
1495 {
1496 case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
1497 {
1498 PREAD_CAPACITY_DATA CapacityBuffer;
1499 ULONG LastSector;
1500 ULONG SectorSize;
1501
1502 DPRINT ("CdromClassControlCompletion: IOCTL_CDROM_GET_DRIVE_GEOMETRY\n");
1503
1504 CapacityBuffer = (PREAD_CAPACITY_DATA)Srb->DataBuffer;
1505 SectorSize = (((PUCHAR)&CapacityBuffer->BytesPerBlock)[0] << 24) |
1506 (((PUCHAR)&CapacityBuffer->BytesPerBlock)[1] << 16) |
1507 (((PUCHAR)&CapacityBuffer->BytesPerBlock)[2] << 8) |
1508 ((PUCHAR)&CapacityBuffer->BytesPerBlock)[3];
1509
1510 LastSector = (((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[0] << 24) |
1511 (((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[1] << 16) |
1512 (((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[2] << 8) |
1513 ((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[3];
1514
1515 if (SectorSize == 0)
1516 SectorSize = 2048;
1517 DeviceExtension->DiskGeometry->BytesPerSector = SectorSize;
1518
1519 DeviceExtension->PartitionLength.QuadPart = (LONGLONG)(LastSector + 1);
1520 WHICH_BIT(DeviceExtension->DiskGeometry->BytesPerSector,
1521 DeviceExtension->SectorShift);
1522 DeviceExtension->PartitionLength.QuadPart =
1523 (DeviceExtension->PartitionLength.QuadPart << DeviceExtension->SectorShift);
1524
1525 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
1526 {
1527 DeviceExtension->DiskGeometry->MediaType = RemovableMedia;
1528 }
1529 else
1530 {
1531 DeviceExtension->DiskGeometry->MediaType = FixedMedia;
1532 }
1533 DeviceExtension->DiskGeometry->Cylinders.QuadPart =
1534 (LONGLONG)((LastSector + 1)/(32 * 64));
1535 DeviceExtension->DiskGeometry->SectorsPerTrack = 32;
1536 DeviceExtension->DiskGeometry->TracksPerCylinder = 64;
1537
1538 RtlCopyMemory (OrigIrp->AssociatedIrp.SystemBuffer,
1539 DeviceExtension->DiskGeometry,
1540 sizeof(DISK_GEOMETRY));
1541 OrigIrp->IoStatus.Information = sizeof(DISK_GEOMETRY);
1542 }
1543 break;
1544
1545 case IOCTL_CDROM_CHECK_VERIFY:
1546 DPRINT ("CdromDeviceControlCompletion: IOCTL_CDROM_CHECK_VERIFY\n");
1547 if (OrigCurrentIrpStack->Parameters.DeviceIoControl.OutputBufferLength != 0)
1548 {
1549 /* Return the media change counter */
1550 *((PULONG)(OrigIrp->AssociatedIrp.SystemBuffer)) =
1551 PhysicalExtension->MediaChangeCount;
1552 OrigIrp->IoStatus.Information = sizeof(ULONG);
1553 }
1554 else
1555 {
1556 OrigIrp->IoStatus.Information = 0;
1557 }
1558 break;
1559
1560 default:
1561 OrigIrp->IoStatus.Information = 0;
1562 Status = STATUS_INVALID_DEVICE_REQUEST;
1563 break;
1564 }
1565 }
1566
1567 /* Release the SRB and associated buffers */
1568 if (Srb != NULL)
1569 {
1570 DPRINT("Srb %p\n", Srb);
1571
1572 if (Srb->DataBuffer != NULL)
1573 ExFreePool (Srb->DataBuffer);
1574
1575 if (Srb->SenseInfoBuffer != NULL)
1576 ExFreePool (Srb->SenseInfoBuffer);
1577
1578 ExFreePool (Srb);
1579 }
1580
1581 if (OrigIrp->PendingReturned)
1582 {
1583 IoMarkIrpPending (OrigIrp);
1584 }
1585
1586 /* Release the MDL */
1587 if (Irp->MdlAddress != NULL)
1588 {
1589 IoFreeMdl (Irp->MdlAddress);
1590 }
1591
1592 /* Release the sub irp */
1593 IoFreeIrp (Irp);
1594
1595 /* Set io status information */
1596 OrigIrp->IoStatus.Status = Status;
1597 if (!NT_SUCCESS(Status) && IoIsErrorUserInduced (Status))
1598 {
1599 IoSetHardErrorOrVerifyDevice (OrigIrp,
1600 DeviceObject);
1601 OrigIrp->IoStatus.Information = 0;
1602 }
1603
1604 /* Complete the original IRP */
1605 IoCompleteRequest (OrigIrp,
1606 IO_DISK_INCREMENT);
1607 IoStartNextPacket (DeviceObject,
1608 FALSE);
1609
1610 DPRINT ("CdromDeviceControlCompletion() done\n");
1611
1612 return STATUS_MORE_PROCESSING_REQUIRED;
1613 }
1614
1615
1616 VOID STDCALL
1617 CdromTimerRoutine(PDEVICE_OBJECT DeviceObject,
1618 PVOID Context)
1619 {
1620 DPRINT ("CdromTimerRoutine() called\n");
1621
1622 }
1623
1624 /* EOF */