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