Use W32API.
[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/ntddscsi.h>
39 #include <ddk/ntdddisk.h>
40 #include <ddk/ntddcdrm.h>
41 #include <ddk/class2.h>
42 #include <ntos/minmax.h>
43 #include <stdio.h>
44
45 #define NDEBUG
46 #include <debug.h>
47
48 #define VERSION "0.0.1"
49
50
51 #define SCSI_CDROM_TIMEOUT 10 /* Default timeout: 10 seconds */
52
53
54 typedef struct _ERROR_RECOVERY_DATA6
55 {
56 MODE_PARAMETER_HEADER Header;
57 MODE_READ_RECOVERY_PAGE ReadRecoveryPage;
58 } ERROR_RECOVERY_DATA6, *PERROR_RECOVERY_DATA6;
59
60
61 typedef struct _ERROR_RECOVERY_DATA10
62 {
63 MODE_PARAMETER_HEADER10 Header;
64 MODE_READ_RECOVERY_PAGE ReadRecoveryPage;
65 } ERROR_RECOVERY_DATA10, *PERROR_RECOVERY_DATA10;
66
67 typedef struct _MODE_CAPABILITIES_DATA6
68 {
69 MODE_PARAMETER_HEADER Header;
70 MODE_CAPABILITIES_PAGE2 CababilitiesPage;
71 } MODE_CAPABILITIES_DATA6, *PMODE_CAPABILITIES_DATA6;
72
73 typedef struct _MODE_CAPABILITIES_DATA10
74 {
75 MODE_PARAMETER_HEADER10 Header;
76 MODE_CAPABILITIES_PAGE2 CababilitiesPage;
77 } MODE_CAPABILITIES_DATA10, *PMODE_CAPABILITIES_DATA10;
78
79 typedef struct _CDROM_DATA
80 {
81 BOOLEAN PlayActive;
82 BOOLEAN RawAccess;
83 USHORT XaFlags;
84
85 } CDROM_DATA, *PCDROM_DATA;
86
87 /* CDROM_DATA.XaFlags */
88 #define XA_USE_6_BYTE 0x0001
89 #define XA_USE_10_BYTE 0x0002
90 #define XA_USE_READ_CD 0x0004
91 #define XA_NOT_SUPPORTED 0x0008
92
93
94 BOOLEAN STDCALL
95 CdromClassFindDevices(IN PDRIVER_OBJECT DriverObject,
96 IN PUNICODE_STRING RegistryPath,
97 IN PCLASS_INIT_DATA InitializationData,
98 IN PDEVICE_OBJECT PortDeviceObject,
99 IN ULONG PortNumber);
100
101 BOOLEAN STDCALL
102 CdromClassCheckDevice(IN PINQUIRYDATA InquiryData);
103
104 NTSTATUS STDCALL
105 CdromClassCheckReadWrite(IN PDEVICE_OBJECT DeviceObject,
106 IN PIRP Irp);
107
108 static VOID
109 CdromClassCreateMediaChangeEvent(IN PDEVICE_EXTENSION DeviceExtension,
110 IN ULONG DeviceNumber);
111
112 static NTSTATUS
113 CdromClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
114 IN PUNICODE_STRING RegistryPath,
115 IN PDEVICE_OBJECT PortDeviceObject,
116 IN ULONG PortNumber,
117 IN ULONG DeviceNumber,
118 IN PIO_SCSI_CAPABILITIES Capabilities,
119 IN PSCSI_INQUIRY_DATA InquiryData,
120 IN PCLASS_INIT_DATA InitializationData);
121
122
123 NTSTATUS STDCALL
124 CdromClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
125 IN PIRP Irp);
126
127 VOID STDCALL
128 CdromClassStartIo (IN PDEVICE_OBJECT DeviceObject,
129 IN PIRP Irp);
130
131 NTSTATUS STDCALL
132 CdromDeviceControlCompletion (IN PDEVICE_OBJECT DeviceObject,
133 IN PIRP Irp,
134 IN PVOID Context);
135
136 VOID STDCALL
137 CdromTimerRoutine(IN PDEVICE_OBJECT DeviceObject,
138 IN PVOID Context);
139
140 VOID STDCALL
141 CdromWorkItem(IN PDEVICE_OBJECT DeviceObject,
142 IN PVOID Context);
143
144
145 /* FUNCTIONS ****************************************************************/
146
147 /**********************************************************************
148 * NAME EXPORTED
149 * DriverEntry
150 *
151 * DESCRIPTION:
152 * This function initializes the driver, locates and claims
153 * hardware resources, and creates various NT objects needed
154 * to process I/O requests.
155 *
156 * RUN LEVEL:
157 * PASSIVE_LEVEL
158 *
159 * ARGUMENTS:
160 * DriverObject
161 * System allocated Driver Object for this driver
162 * RegistryPath
163 * Name of registry driver service key
164 *
165 * RETURNS:
166 * Status.
167 */
168
169 NTSTATUS STDCALL
170 DriverEntry(IN PDRIVER_OBJECT DriverObject,
171 IN PUNICODE_STRING RegistryPath)
172 {
173 CLASS_INIT_DATA InitData;
174
175 DPRINT("CD-ROM Class Driver %s\n",
176 VERSION);
177 DPRINT("RegistryPath '%wZ'\n",
178 RegistryPath);
179
180 InitData.InitializationDataSize = sizeof(CLASS_INIT_DATA);
181 InitData.DeviceExtensionSize = sizeof(DEVICE_EXTENSION) + sizeof(CDROM_DATA);
182 InitData.DeviceType = FILE_DEVICE_CD_ROM;
183 InitData.DeviceCharacteristics = FILE_REMOVABLE_MEDIA | FILE_READ_ONLY_DEVICE;
184
185 InitData.ClassError = NULL;
186 InitData.ClassReadWriteVerification = CdromClassCheckReadWrite;
187 InitData.ClassFindDeviceCallBack = CdromClassCheckDevice;
188 InitData.ClassFindDevices = CdromClassFindDevices;
189 InitData.ClassDeviceControl = CdromClassDeviceControl;
190 InitData.ClassShutdownFlush = NULL;
191 InitData.ClassCreateClose = NULL;
192 InitData.ClassStartIo = CdromClassStartIo;
193
194 return(ScsiClassInitialize(DriverObject,
195 RegistryPath,
196 &InitData));
197 }
198
199
200 /**********************************************************************
201 * NAME EXPORTED
202 * CdromClassFindDevices
203 *
204 * DESCRIPTION:
205 * This function searches for device that are attached to the
206 * given scsi port.
207 *
208 * RUN LEVEL:
209 * PASSIVE_LEVEL
210 *
211 * ARGUMENTS:
212 * DriverObject
213 * System allocated Driver Object for this driver
214 * RegistryPath
215 * Name of registry driver service key.
216 * InitializationData
217 * Pointer to the main initialization data
218 * PortDeviceObject
219 * Scsi port device object
220 * PortNumber
221 * Port number
222 *
223 * RETURNS:
224 * TRUE: At least one disk drive was found
225 * FALSE: No disk drive found
226 */
227
228 BOOLEAN STDCALL
229 CdromClassFindDevices(IN PDRIVER_OBJECT DriverObject,
230 IN PUNICODE_STRING RegistryPath,
231 IN PCLASS_INIT_DATA InitializationData,
232 IN PDEVICE_OBJECT PortDeviceObject,
233 IN ULONG PortNumber)
234 {
235 PCONFIGURATION_INFORMATION ConfigInfo;
236 PIO_SCSI_CAPABILITIES PortCapabilities;
237 PSCSI_ADAPTER_BUS_INFO AdapterBusInfo;
238 PSCSI_INQUIRY_DATA UnitInfo;
239 PINQUIRYDATA InquiryData;
240 PCHAR Buffer;
241 ULONG Bus;
242 ULONG DeviceCount;
243 BOOLEAN FoundDevice = FALSE;
244 NTSTATUS Status;
245
246 DPRINT("CdromClassFindDevices() called.\n");
247
248 /* Get port capabilities */
249 Status = ScsiClassGetCapabilities(PortDeviceObject,
250 &PortCapabilities);
251 if (!NT_SUCCESS(Status))
252 {
253 DPRINT1("ScsiClassGetCapabilities() failed! (Status 0x%lX)\n", Status);
254 return(FALSE);
255 }
256
257 DPRINT("PortCapabilities: %p\n", PortCapabilities);
258 DPRINT("MaximumTransferLength: %lu\n", PortCapabilities->MaximumTransferLength);
259 DPRINT("MaximumPhysicalPages: %lu\n", PortCapabilities->MaximumPhysicalPages);
260
261 /* Get inquiry data */
262 Status = ScsiClassGetInquiryData(PortDeviceObject,
263 (PSCSI_ADAPTER_BUS_INFO *)&Buffer);
264 if (!NT_SUCCESS(Status))
265 {
266 DPRINT1("ScsiClassGetInquiryData() failed! (Status 0x%lX)\n", Status);
267 return(FALSE);
268 }
269
270 /* Check whether there are unclaimed devices */
271 AdapterBusInfo = (PSCSI_ADAPTER_BUS_INFO)Buffer;
272 DeviceCount = ScsiClassFindUnclaimedDevices(InitializationData,
273 AdapterBusInfo);
274 if (DeviceCount == 0)
275 {
276 DPRINT("No unclaimed devices!\n");
277 return(FALSE);
278 }
279
280 DPRINT("Found %lu unclaimed devices!\n", DeviceCount);
281
282 ConfigInfo = IoGetConfigurationInformation();
283 DPRINT("Number of SCSI ports: %lu\n", ConfigInfo->ScsiPortCount);
284
285 /* Search each bus of this adapter */
286 for (Bus = 0; Bus < (ULONG)AdapterBusInfo->NumberOfBuses; Bus++)
287 {
288 DPRINT("Searching bus %lu\n", Bus);
289
290 UnitInfo = (PSCSI_INQUIRY_DATA)(Buffer + AdapterBusInfo->BusData[Bus].InquiryDataOffset);
291
292 while (AdapterBusInfo->BusData[Bus].InquiryDataOffset)
293 {
294 InquiryData = (PINQUIRYDATA)UnitInfo->InquiryData;
295
296 if ((InquiryData->DeviceType == READ_ONLY_DIRECT_ACCESS_DEVICE) &&
297 (InquiryData->DeviceTypeQualifier == 0) &&
298 (UnitInfo->DeviceClaimed == FALSE))
299 {
300 DPRINT("Vendor: '%.24s'\n",
301 InquiryData->VendorId);
302
303 /* Create device objects for disk */
304 Status = CdromClassCreateDeviceObject(DriverObject,
305 RegistryPath,
306 PortDeviceObject,
307 PortNumber,
308 ConfigInfo->CdRomCount,
309 PortCapabilities,
310 UnitInfo,
311 InitializationData);
312 if (NT_SUCCESS(Status))
313 {
314 ConfigInfo->CdRomCount++;
315 FoundDevice = TRUE;
316 }
317 }
318
319 if (UnitInfo->NextInquiryDataOffset == 0)
320 break;
321
322 UnitInfo = (PSCSI_INQUIRY_DATA)(Buffer + UnitInfo->NextInquiryDataOffset);
323 }
324 }
325
326 ExFreePool(Buffer);
327
328 DPRINT("CdromClassFindDevices() done\n");
329
330 return(FoundDevice);
331 }
332
333
334 /**********************************************************************
335 * NAME EXPORTED
336 * CdromClassCheckDevice
337 *
338 * DESCRIPTION
339 * This function checks the InquiryData for the correct device
340 * type and qualifier.
341 *
342 * RUN LEVEL
343 * PASSIVE_LEVEL
344 *
345 * ARGUMENTS
346 * InquiryData
347 * Pointer to the inquiry data for the device in question.
348 *
349 * RETURN VALUE
350 * TRUE: A disk device was found.
351 * FALSE: Otherwise.
352 */
353
354 BOOLEAN STDCALL
355 CdromClassCheckDevice(IN PINQUIRYDATA InquiryData)
356 {
357 return((InquiryData->DeviceType == READ_ONLY_DIRECT_ACCESS_DEVICE) &&
358 (InquiryData->DeviceTypeQualifier == 0));
359 }
360
361
362 /**********************************************************************
363 * NAME EXPORTED
364 * CdromClassCheckReadWrite
365 *
366 * DESCRIPTION
367 * This function checks the given IRP for correct data.
368 *
369 * RUN LEVEL
370 * PASSIVE_LEVEL
371 *
372 * ARGUMENTS
373 * DeviceObject
374 * Pointer to the device.
375 * Irp
376 * Irp to check.
377 *
378 * RETURN VALUE
379 * STATUS_SUCCESS: The IRP matches the requirements of the given device.
380 * Others: Failure.
381 */
382
383 NTSTATUS STDCALL
384 CdromClassCheckReadWrite(IN PDEVICE_OBJECT DeviceObject,
385 IN PIRP Irp)
386 {
387 DPRINT("CdromClassCheckReadWrite() called\n");
388
389 return(STATUS_SUCCESS);
390 }
391
392
393 static VOID
394 CdromClassCreateMediaChangeEvent(IN PDEVICE_EXTENSION DeviceExtension,
395 IN ULONG DeviceNumber)
396 {
397
398
399 DeviceExtension->MediaChangeEvent =
400 IoCreateSynchronizationEvent (NULL,
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 IoCompleteRequest (Irp,
1207 IO_DISK_INCREMENT);
1208 IoStartNextPacket (DeviceObject,
1209 FALSE);
1210 return;
1211 }
1212 }
1213
1214 if (IrpStack->MajorFunction == IRP_MJ_READ)
1215 {
1216 DPRINT ("CdromClassStartIo: IRP_MJ_READ\n");
1217
1218 TransferPages =
1219 ADDRESS_AND_SIZE_TO_SPAN_PAGES (MmGetMdlVirtualAddress(Irp->MdlAddress),
1220 IrpStack->Parameters.Read.Length);
1221
1222 /* Check transfer size */
1223 if ((IrpStack->Parameters.Read.Length > MaximumTransferLength) ||
1224 (TransferPages > DeviceExtension->PortCapabilities->MaximumPhysicalPages))
1225 {
1226 /* Transfer size is too large - split it */
1227 TransferPages =
1228 DeviceExtension->PortCapabilities->MaximumPhysicalPages - 1;
1229
1230 /* Adjust transfer size */
1231 if (MaximumTransferLength > TransferPages * PAGE_SIZE)
1232 MaximumTransferLength = TransferPages * PAGE_SIZE;
1233
1234 if (MaximumTransferLength == 0)
1235 MaximumTransferLength = PAGE_SIZE;
1236
1237 /* Split the transfer */
1238 ScsiClassSplitRequest (DeviceObject,
1239 Irp,
1240 MaximumTransferLength);
1241 return;
1242 }
1243 else
1244 {
1245 /* Build SRB */
1246 ScsiClassBuildRequest (DeviceObject,
1247 Irp);
1248 }
1249 }
1250 else if (IrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL)
1251 {
1252 DPRINT ("CdromClassStartIo: IRP_MJ_IRP_MJ_DEVICE_CONTROL\n");
1253
1254 /* Allocate an IRP for sending requests to the port driver */
1255 SubIrp = IoAllocateIrp ((CCHAR)(DeviceObject->StackSize + 1),
1256 FALSE);
1257 if (SubIrp == NULL)
1258 {
1259 Irp->IoStatus.Information = 0;
1260 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1261 IoCompleteRequest (Irp,
1262 IO_DISK_INCREMENT);
1263 IoStartNextPacket (DeviceObject,
1264 FALSE);
1265 return;
1266 }
1267
1268 /* Allocate an SRB */
1269 Srb = ExAllocatePool (NonPagedPool,
1270 sizeof (SCSI_REQUEST_BLOCK));
1271 if (Srb == NULL)
1272 {
1273 IoFreeIrp (SubIrp);
1274 Irp->IoStatus.Information = 0;
1275 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1276 IoCompleteRequest (Irp,
1277 IO_DISK_INCREMENT);
1278 IoStartNextPacket (DeviceObject,
1279 FALSE);
1280 return;
1281 }
1282
1283 /* Allocte a sense buffer */
1284 SenseBuffer = ExAllocatePool (NonPagedPoolCacheAligned,
1285 SENSE_BUFFER_SIZE);
1286 if (SenseBuffer == NULL)
1287 {
1288 ExFreePool (Srb);
1289 IoFreeIrp (SubIrp);
1290 Irp->IoStatus.Information = 0;
1291 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1292 IoCompleteRequest (Irp,
1293 IO_DISK_INCREMENT);
1294 IoStartNextPacket (DeviceObject,
1295 FALSE);
1296 return;
1297 }
1298
1299 /* Initialize the IRP */
1300 IoSetNextIrpStackLocation (SubIrp);
1301 SubIrp->IoStatus.Information = 0;
1302 SubIrp->IoStatus.Status = STATUS_SUCCESS;
1303 SubIrp->Flags = 0;
1304 SubIrp->UserBuffer = NULL;
1305
1306 SubIrpStack = IoGetCurrentIrpStackLocation (SubIrp);
1307 SubIrpStack->DeviceObject = DeviceExtension->DeviceObject;
1308 SubIrpStack->Parameters.Others.Argument2 = (PVOID)Irp;
1309
1310 /* Initialize next stack location */
1311 SubIrpStack = IoGetNextIrpStackLocation (SubIrp);
1312 SubIrpStack->MajorFunction = IRP_MJ_SCSI;
1313 SubIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
1314 SubIrpStack->Parameters.Scsi.Srb = Srb;
1315
1316 /* Initialize the SRB */
1317 RtlZeroMemory(Srb,
1318 sizeof (SCSI_REQUEST_BLOCK));
1319 Srb->Length = sizeof (SCSI_REQUEST_BLOCK);
1320 Srb->PathId = DeviceExtension->PathId;
1321 Srb->TargetId = DeviceExtension->TargetId;
1322 Srb->Lun = DeviceExtension->Lun;
1323 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1324 Srb->SrbStatus = SRB_STATUS_SUCCESS;
1325 Srb->ScsiStatus = 0;
1326 Srb->NextSrb = 0;
1327 Srb->OriginalRequest = SubIrp;
1328 Srb->SenseInfoBuffer = SenseBuffer;
1329 Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
1330
1331 /* Initialize the CDB */
1332 Cdb = (PCDB)Srb->Cdb;
1333
1334 /* Set the completion routine */
1335 IoSetCompletionRoutine (SubIrp,
1336 CdromDeviceControlCompletion,
1337 Srb,
1338 TRUE,
1339 TRUE,
1340 TRUE);
1341
1342 switch (IrpStack->Parameters.DeviceIoControl.IoControlCode)
1343 {
1344 case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
1345 DPRINT ("CdromClassStartIo: IOCTL_CDROM_GET_DRIVE_GEOMETRY\n");
1346 Srb->DataTransferLength = sizeof(READ_CAPACITY_DATA);
1347 Srb->CdbLength = 10;
1348 Srb->TimeOutValue = DeviceExtension->TimeOutValue;
1349 Srb->SrbFlags = SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN;
1350 Cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
1351
1352 /* Allocate data buffer */
1353 DataBuffer = ExAllocatePool (NonPagedPoolCacheAligned,
1354 sizeof(READ_CAPACITY_DATA));
1355 if (DataBuffer == NULL)
1356 {
1357 Irp->IoStatus.Information = 0;
1358 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1359 IoCompleteRequest (Irp,
1360 IO_DISK_INCREMENT);
1361 ExFreePool (SenseBuffer);
1362 ExFreePool (Srb);
1363 IoFreeIrp (SubIrp);
1364 IoStartNextPacket (DeviceObject,
1365 FALSE);
1366 return;
1367 }
1368
1369 /* Allocate an MDL for the data buffer */
1370 SubIrp->MdlAddress = IoAllocateMdl (DataBuffer,
1371 sizeof(READ_CAPACITY_DATA),
1372 FALSE,
1373 FALSE,
1374 NULL);
1375 if (SubIrp->MdlAddress == NULL)
1376 {
1377 Irp->IoStatus.Information = 0;
1378 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1379 IoCompleteRequest (Irp,
1380 IO_DISK_INCREMENT);
1381 ExFreePool (DataBuffer);
1382 ExFreePool (SenseBuffer);
1383 ExFreePool (Srb);
1384 IoFreeIrp (SubIrp);
1385 IoStartNextPacket (DeviceObject,
1386 FALSE);
1387 return;
1388 }
1389
1390 MmBuildMdlForNonPagedPool (SubIrp->MdlAddress);
1391 Srb->DataBuffer = DataBuffer;
1392
1393 IoCallDriver (DeviceExtension->PortDeviceObject,
1394 SubIrp);
1395 return;
1396
1397 case IOCTL_CDROM_CHECK_VERIFY:
1398 DPRINT ("CdromClassStartIo: IOCTL_CDROM_CHECK_VERIFY\n");
1399 Srb->CdbLength = 6;
1400 Srb->TimeOutValue = DeviceExtension->TimeOutValue * 2;
1401 Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;
1402 Cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
1403
1404 IoCallDriver (DeviceExtension->PortDeviceObject,
1405 SubIrp);
1406 return;
1407
1408 default:
1409 IoCompleteRequest (Irp,
1410 IO_NO_INCREMENT);
1411 return;
1412 }
1413 }
1414
1415 /* Call the SCSI port driver */
1416 IoCallDriver (DeviceExtension->PortDeviceObject,
1417 Irp);
1418 }
1419
1420
1421 NTSTATUS STDCALL
1422 CdromDeviceControlCompletion (IN PDEVICE_OBJECT DeviceObject,
1423 IN PIRP Irp,
1424 IN PVOID Context)
1425 {
1426 PDEVICE_EXTENSION DeviceExtension;
1427 PDEVICE_EXTENSION PhysicalExtension;
1428 PIO_STACK_LOCATION IrpStack;
1429 PIO_STACK_LOCATION OrigCurrentIrpStack;
1430 PIO_STACK_LOCATION OrigNextIrpStack;
1431 PSCSI_REQUEST_BLOCK Srb;
1432 PIRP OrigIrp;
1433 BOOLEAN Retry;
1434 NTSTATUS Status;
1435
1436 DPRINT ("CdromDeviceControlCompletion() called\n");
1437
1438 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
1439 PhysicalExtension = (PDEVICE_EXTENSION)DeviceExtension->PhysicalDevice->DeviceExtension;
1440 Srb = (PSCSI_REQUEST_BLOCK) Context;
1441
1442 IrpStack = IoGetCurrentIrpStackLocation (Irp);
1443
1444 /* Get the original IRP */
1445 OrigIrp = (PIRP)IrpStack->Parameters.Others.Argument2;
1446 OrigCurrentIrpStack = IoGetCurrentIrpStackLocation (OrigIrp);
1447 OrigNextIrpStack = IoGetNextIrpStackLocation (OrigIrp);
1448
1449 if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS)
1450 {
1451 Status = STATUS_SUCCESS;
1452 }
1453 else
1454 {
1455 DPRINT ("SrbStatus %lx\n", Srb->SrbStatus);
1456
1457 /* Interpret sense info */
1458 Retry = ScsiClassInterpretSenseInfo (DeviceObject,
1459 Srb,
1460 IrpStack->MajorFunction,
1461 IrpStack->Parameters.DeviceIoControl.IoControlCode,
1462 MAXIMUM_RETRIES - (ULONG)OrigNextIrpStack->Parameters.Others.Argument1,
1463 &Status);
1464 DPRINT ("Retry %u\n", Retry);
1465
1466 if (Retry == TRUE &&
1467 (ULONG)OrigNextIrpStack->Parameters.Others.Argument1 > 0)
1468 {
1469 DPRINT1 ("Try again (Retry count %lu)\n",
1470 (ULONG)OrigNextIrpStack->Parameters.Others.Argument1);
1471
1472 (ULONG)OrigNextIrpStack->Parameters.Others.Argument1--;
1473
1474 /* Release 'old' buffers */
1475 ExFreePool (Srb->SenseInfoBuffer);
1476 if (Srb->DataBuffer)
1477 ExFreePool(Srb->DataBuffer);
1478 ExFreePool(Srb);
1479
1480 if (Irp->MdlAddress != NULL)
1481 IoFreeMdl(Irp->MdlAddress);
1482
1483 IoFreeIrp(Irp);
1484
1485 /* Call the StartIo routine again */
1486 CdromClassStartIo (DeviceObject,
1487 OrigIrp);
1488
1489 return STATUS_MORE_PROCESSING_REQUIRED;
1490 }
1491
1492 DPRINT ("Status %lx\n", Status);
1493 }
1494
1495 if (NT_SUCCESS (Status))
1496 {
1497 switch (OrigCurrentIrpStack->Parameters.DeviceIoControl.IoControlCode)
1498 {
1499 case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
1500 {
1501 PREAD_CAPACITY_DATA CapacityBuffer;
1502 ULONG LastSector;
1503 ULONG SectorSize;
1504
1505 DPRINT ("CdromClassControlCompletion: IOCTL_CDROM_GET_DRIVE_GEOMETRY\n");
1506
1507 CapacityBuffer = (PREAD_CAPACITY_DATA)Srb->DataBuffer;
1508 SectorSize = (((PUCHAR)&CapacityBuffer->BytesPerBlock)[0] << 24) |
1509 (((PUCHAR)&CapacityBuffer->BytesPerBlock)[1] << 16) |
1510 (((PUCHAR)&CapacityBuffer->BytesPerBlock)[2] << 8) |
1511 ((PUCHAR)&CapacityBuffer->BytesPerBlock)[3];
1512
1513 LastSector = (((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[0] << 24) |
1514 (((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[1] << 16) |
1515 (((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[2] << 8) |
1516 ((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[3];
1517
1518 if (SectorSize == 0)
1519 SectorSize = 2048;
1520 DeviceExtension->DiskGeometry->BytesPerSector = SectorSize;
1521
1522 DeviceExtension->PartitionLength.QuadPart = (LONGLONG)(LastSector + 1);
1523 WHICH_BIT(DeviceExtension->DiskGeometry->BytesPerSector,
1524 DeviceExtension->SectorShift);
1525 DeviceExtension->PartitionLength.QuadPart =
1526 (DeviceExtension->PartitionLength.QuadPart << DeviceExtension->SectorShift);
1527
1528 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
1529 {
1530 DeviceExtension->DiskGeometry->MediaType = RemovableMedia;
1531 }
1532 else
1533 {
1534 DeviceExtension->DiskGeometry->MediaType = FixedMedia;
1535 }
1536 DeviceExtension->DiskGeometry->Cylinders.QuadPart =
1537 (LONGLONG)((LastSector + 1)/(32 * 64));
1538 DeviceExtension->DiskGeometry->SectorsPerTrack = 32;
1539 DeviceExtension->DiskGeometry->TracksPerCylinder = 64;
1540
1541 RtlCopyMemory (OrigIrp->AssociatedIrp.SystemBuffer,
1542 DeviceExtension->DiskGeometry,
1543 sizeof(DISK_GEOMETRY));
1544 OrigIrp->IoStatus.Information = sizeof(DISK_GEOMETRY);
1545 }
1546 break;
1547
1548 case IOCTL_CDROM_CHECK_VERIFY:
1549 DPRINT ("CdromDeviceControlCompletion: IOCTL_CDROM_CHECK_VERIFY\n");
1550 if (OrigCurrentIrpStack->Parameters.DeviceIoControl.OutputBufferLength != 0)
1551 {
1552 /* Return the media change counter */
1553 *((PULONG)(OrigIrp->AssociatedIrp.SystemBuffer)) =
1554 PhysicalExtension->MediaChangeCount;
1555 OrigIrp->IoStatus.Information = sizeof(ULONG);
1556 }
1557 else
1558 {
1559 OrigIrp->IoStatus.Information = 0;
1560 }
1561 break;
1562
1563 default:
1564 OrigIrp->IoStatus.Information = 0;
1565 Status = STATUS_INVALID_DEVICE_REQUEST;
1566 break;
1567 }
1568 }
1569
1570 /* Release the SRB and associated buffers */
1571 if (Srb != NULL)
1572 {
1573 DPRINT("Srb %p\n", Srb);
1574
1575 if (Srb->DataBuffer != NULL)
1576 ExFreePool (Srb->DataBuffer);
1577
1578 if (Srb->SenseInfoBuffer != NULL)
1579 ExFreePool (Srb->SenseInfoBuffer);
1580
1581 ExFreePool (Srb);
1582 }
1583
1584 if (OrigIrp->PendingReturned)
1585 {
1586 IoMarkIrpPending (OrigIrp);
1587 }
1588
1589 /* Release the MDL */
1590 if (Irp->MdlAddress != NULL)
1591 {
1592 IoFreeMdl (Irp->MdlAddress);
1593 }
1594
1595 /* Release the sub irp */
1596 IoFreeIrp (Irp);
1597
1598 /* Set io status information */
1599 OrigIrp->IoStatus.Status = Status;
1600 if (!NT_SUCCESS(Status) && IoIsErrorUserInduced (Status))
1601 {
1602 IoSetHardErrorOrVerifyDevice (OrigIrp,
1603 DeviceObject);
1604 OrigIrp->IoStatus.Information = 0;
1605 }
1606
1607 /* Complete the original IRP */
1608 IoCompleteRequest (OrigIrp,
1609 IO_DISK_INCREMENT);
1610 IoStartNextPacket (DeviceObject,
1611 FALSE);
1612
1613 DPRINT ("CdromDeviceControlCompletion() done\n");
1614
1615 return STATUS_MORE_PROCESSING_REQUIRED;
1616 }
1617
1618
1619 VOID STDCALL
1620 CdromTimerRoutine(IN PDEVICE_OBJECT DeviceObject,
1621 IN PVOID Context)
1622 {
1623 PIO_WORKITEM WorkItem;
1624
1625 DPRINT ("CdromTimerRoutine() called\n");
1626 WorkItem = IoAllocateWorkItem(DeviceObject);
1627 if (!WorkItem)
1628 {
1629 return;
1630 }
1631
1632 IoQueueWorkItem(WorkItem,
1633 CdromWorkItem,
1634 DelayedWorkQueue,
1635 WorkItem);
1636 }
1637
1638
1639 VOID STDCALL
1640 CdromWorkItem(IN PDEVICE_OBJECT DeviceObject,
1641 IN PVOID Context)
1642 {
1643 PIRP Irp;
1644 KEVENT Event;
1645 IO_STATUS_BLOCK IoStatus;
1646 NTSTATUS Status;
1647
1648 DPRINT("CdromWorkItem() called\n");
1649
1650 IoFreeWorkItem((PIO_WORKITEM) Context);
1651
1652 KeInitializeEvent(&Event,
1653 NotificationEvent,
1654 FALSE);
1655
1656 Irp = IoBuildDeviceIoControlRequest(IOCTL_CDROM_CHECK_VERIFY,
1657 DeviceObject,
1658 NULL,
1659 0,
1660 NULL,
1661 0,
1662 FALSE,
1663 &Event,
1664 &IoStatus);
1665 if (Irp == NULL)
1666 {
1667 DPRINT("IoBuildDeviceIoControlRequest failed\n");
1668 return;
1669 }
1670
1671 Status = IoCallDriver(DeviceObject, Irp);
1672 DPRINT("Status: %x\n", Status);
1673
1674 if (Status == STATUS_PENDING)
1675 {
1676 KeWaitForSingleObject(&Event,
1677 Suspended,
1678 KernelMode,
1679 FALSE,
1680 NULL);
1681 }
1682 }
1683
1684 /* EOF */