defc10ef4bd08ff07810e3570e5b6e1db05b1231
[reactos.git] / reactos / drivers / storage / class / cdrom / cdrom.c
1 /*
2 * PROJECT: ReactOS Storage Stack
3 * LICENSE: DDK - see license.txt in the root dir
4 * FILE: drivers/storage/cdrom/cdrom.c
5 * PURPOSE: CDROM driver
6 * PROGRAMMERS: Based on a source code sample from Microsoft NT4 DDK
7 */
8
9 #include <ntddk.h>
10 #include <scsi.h>
11 #include <ntddscsi.h>
12 #include <ntdddisk.h>
13 #include <ntddcdrm.h>
14 #include <include/class2.h>
15 #include <stdio.h>
16
17 //#define NDEBUG
18 #include <debug.h>
19
20 #define CDB12GENERIC_LENGTH 12
21
22 typedef struct _XA_CONTEXT {
23
24 //
25 // Pointer to the device object.
26 //
27
28 PDEVICE_OBJECT DeviceObject;
29
30 //
31 // Pointer to the original request when
32 // a mode select must be sent.
33 //
34
35 PIRP OriginalRequest;
36
37 //
38 // Pointer to the mode select srb.
39 //
40
41 PSCSI_REQUEST_BLOCK Srb;
42 } XA_CONTEXT, *PXA_CONTEXT;
43
44 typedef struct _ERROR_RECOVERY_DATA {
45 MODE_PARAMETER_HEADER Header;
46 MODE_PARAMETER_BLOCK BlockDescriptor;
47 MODE_READ_RECOVERY_PAGE ReadRecoveryPage;
48 } ERROR_RECOVERY_DATA, *PERROR_RECOVERY_DATA;
49
50 typedef struct _ERROR_RECOVERY_DATA10 {
51 MODE_PARAMETER_HEADER10 Header10;
52 MODE_PARAMETER_BLOCK BlockDescriptor10;
53 MODE_READ_RECOVERY_PAGE ReadRecoveryPage10;
54 } ERROR_RECOVERY_DATA10, *PERROR_RECOVERY_DATA10;
55
56 //
57 // CdRom specific addition to device extension.
58 //
59
60 typedef struct _CDROM_DATA {
61
62 //
63 // Indicates whether an audio play operation
64 // is currently being performed.
65 //
66
67 BOOLEAN PlayActive;
68
69 //
70 // Indicates whether the blocksize used for user data
71 // is 2048 or 2352.
72 //
73
74 BOOLEAN RawAccess;
75
76 //
77 // Indicates whether 6 or 10 byte mode sense/select
78 // should be used.
79 //
80
81 USHORT XAFlags;
82
83 //
84 // Storage for the error recovery page. This is used
85 // as an easy method to switch block sizes.
86 //
87
88 union {
89 ERROR_RECOVERY_DATA u1;
90 ERROR_RECOVERY_DATA10 u2;
91 };
92
93
94 //
95 // Pointer to the original irp for the raw read.
96 //
97
98 PIRP SavedReadIrp;
99
100 //
101 // Used to protect accesses to the RawAccess flag.
102 //
103
104 KSPIN_LOCK FormSpinLock;
105
106 //
107 // Even if media change support is requested, there are some devices
108 // that are not supported. This flag will indicate that such a device
109 // is present when it is FALSE.
110 //
111
112 BOOLEAN MediaChangeSupported;
113
114 //
115 // The media change event is being supported. The media change timer
116 // should be running whenever this is true.
117 //
118
119 BOOLEAN MediaChange;
120
121 //
122 // The timer value to support media change events. This is a countdown
123 // value used to determine when to poll the device for a media change.
124 // The max value for the timer is 255 seconds.
125 //
126
127 UCHAR MediaChangeCountDown;
128
129 #ifdef DBG
130 //
131 // Second timer to keep track of how long the media change IRP has been
132 // in use. If this value exceeds the timeout (#defined) then we should
133 // print out a message to the user and set the MediaChangeIrpLost flag
134 //
135
136 SHORT MediaChangeIrpTimeInUse;
137
138 //
139 // Set by CdRomTickHandler when we determine that the media change irp has
140 // been lost
141 //
142
143 BOOLEAN MediaChangeIrpLost;
144 #endif
145
146 UCHAR PadReserve; // use this for new flags.
147
148 //
149 // An IRP is allocated and kept for the duration that media change
150 // detection is in effect. If this is NULL and MediaChange is TRUE,
151 // the detection is in progress. This should always be NULL when
152 // MediaChange is FALSE.
153 //
154
155 PIRP MediaChangeIrp;
156
157 //
158 // The timer work list is a collection of IRPS that are prepared for
159 // submission, but need to allow some time to pass before they are
160 // run.
161 //
162
163 LIST_ENTRY TimerIrpList;
164 KSPIN_LOCK TimerIrpSpinLock;
165
166 } CDROM_DATA, *PCDROM_DATA;
167
168 #define DEVICE_EXTENSION_SIZE sizeof(DEVICE_EXTENSION) + sizeof(CDROM_DATA)
169 #define SCSI_CDROM_TIMEOUT 10
170 #define SCSI_CHANGER_BONUS_TIMEOUT 10
171 #define HITACHI_MODE_DATA_SIZE 12
172 #define MODE_DATA_SIZE 64
173 #define RAW_SECTOR_SIZE 2352
174 #define COOKED_SECTOR_SIZE 2048
175 #define MEDIA_CHANGE_DEFAULT_TIME 4
176 #define CDROM_SRB_LIST_SIZE 4
177
178
179 #ifdef DBG
180
181 //
182 // Used to detect the loss of the autorun irp. The driver prints out a message
183 // (debug level 0) if this timeout ever occurs
184 //
185 #define MEDIA_CHANGE_TIMEOUT_TIME 300
186
187 #endif
188
189 #define PLAY_ACTIVE(DeviceExtension) (((PCDROM_DATA)(DeviceExtension + 1))->PlayActive)
190
191 #define MSF_TO_LBA(Minutes,Seconds,Frames) \
192 (ULONG)((60 * 75 * (Minutes)) + (75 * (Seconds)) + ((Frames) - 150))
193
194 #define LBA_TO_MSF(Lba,Minutes,Seconds,Frames) \
195 { \
196 (Minutes) = (UCHAR)(Lba / (60 * 75)); \
197 (Seconds) = (UCHAR)((Lba % (60 * 75)) / 75); \
198 (Frames) = (UCHAR)((Lba % (60 * 75)) % 75); \
199 }
200
201 #define DEC_TO_BCD(x) (((x / 10) << 4) + (x % 10))
202
203 //
204 // Define flags for XA, CDDA, and Mode Select/Sense
205 //
206
207 #define XA_USE_6_BYTE 0x01
208 #define XA_USE_10_BYTE 0x02
209 #define XA_USE_READ_CD 0x04
210 #define XA_NOT_SUPPORTED 0x08
211
212 #define PLEXTOR_CDDA 0x10
213 #define NEC_CDDA 0x20
214
215 //
216 // Sector types for READ_CD
217 //
218
219 #define ANY_SECTOR 0
220 #define CD_DA_SECTOR 1
221 #define YELLOW_MODE1_SECTOR 2
222 #define YELLOW_MODE2_SECTOR 3
223 #define FORM2_MODE1_SECTOR 4
224 #define FORM2_MODE2_SECTOR 5
225
226
227 #ifdef POOL_TAGGING
228 #ifdef ExAllocatePool
229 #undef ExAllocatePool
230 #endif
231 #define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'CscS')
232 #endif
233
234 NTSTATUS
235 NTAPI
236 DriverEntry(
237 IN PDRIVER_OBJECT DriverObject,
238 IN PUNICODE_STRING RegistryPath
239 );
240
241 BOOLEAN
242 NTAPI
243 ScsiCdRomFindDevices(
244 IN PDRIVER_OBJECT DriverObject,
245 IN PUNICODE_STRING RegistryPath,
246 IN PCLASS_INIT_DATA InitializationData,
247 IN PDEVICE_OBJECT PortDeviceObject,
248 IN ULONG PortNumber
249 );
250
251 NTSTATUS
252 NTAPI
253 ScsiCdRomOpenClose(
254 IN PDEVICE_OBJECT DeviceObject,
255 IN PIRP Irp
256 );
257
258 NTSTATUS
259 NTAPI
260 ScsiCdRomReadVerification(
261 IN PDEVICE_OBJECT DeviceObject,
262 IN PIRP Irp
263 );
264
265 NTSTATUS
266 NTAPI
267 ScsiCdRomSwitchMode(
268 IN PDEVICE_OBJECT DeviceObject,
269 IN ULONG SectorSize,
270 IN PIRP OriginalRequest
271 );
272
273 NTSTATUS
274 NTAPI
275 CdRomDeviceControl(
276 IN PDEVICE_OBJECT DeviceObject,
277 IN PIRP Irp
278 );
279
280 IO_COMPLETION_ROUTINE CdRomDeviceControlCompletion;
281 NTSTATUS
282 NTAPI
283 CdRomDeviceControlCompletion(
284 IN PDEVICE_OBJECT DeviceObject,
285 IN PIRP Irp,
286 IN PVOID Context
287 );
288
289 IO_COMPLETION_ROUTINE CdRomSetVolumeIntermediateCompletion;
290 NTSTATUS
291 NTAPI
292 CdRomSetVolumeIntermediateCompletion(
293 IN PDEVICE_OBJECT DeviceObject,
294 IN PIRP Irp,
295 IN PVOID Context
296 );
297
298 IO_COMPLETION_ROUTINE CdRomSwitchModeCompletion;
299 NTSTATUS
300 NTAPI
301 CdRomSwitchModeCompletion(
302 IN PDEVICE_OBJECT DeviceObject,
303 IN PIRP Irp,
304 IN PVOID Context
305 );
306
307 IO_COMPLETION_ROUTINE CdRomXACompletion;
308 NTSTATUS
309 NTAPI
310 CdRomXACompletion(
311 IN PDEVICE_OBJECT DeviceObject,
312 IN PIRP Irp,
313 IN PVOID Context
314 );
315
316 IO_COMPLETION_ROUTINE CdRomClassIoctlCompletion;
317 NTSTATUS
318 NTAPI
319 CdRomClassIoctlCompletion(
320 IN PDEVICE_OBJECT DeviceObject,
321 IN PIRP Irp,
322 IN PVOID Context
323 );
324
325 VOID
326 NTAPI
327 ScsiCdRomStartIo(
328 IN PDEVICE_OBJECT DeviceObject,
329 IN PIRP Irp
330 );
331
332 VOID
333 NTAPI
334 CdRomTickHandler(
335 IN PDEVICE_OBJECT DeviceObject,
336 IN PVOID Context
337 );
338
339 BOOLEAN
340 NTAPI
341 CdRomCheckRegistryForMediaChangeValue(
342 IN PUNICODE_STRING RegistryPath,
343 IN ULONG DeviceNumber
344 );
345
346 NTSTATUS
347 NTAPI
348 CdRomUpdateCapacity(
349 IN PDEVICE_EXTENSION DeviceExtension,
350 IN PIRP IrpToComplete,
351 IN OPTIONAL PKEVENT IoctlEvent
352 );
353
354 NTSTATUS
355 NTAPI
356 CreateCdRomDeviceObject(
357 IN PDRIVER_OBJECT DriverObject,
358 IN PDEVICE_OBJECT PortDeviceObject,
359 IN ULONG PortNumber,
360 IN PULONG DeviceCount,
361 PIO_SCSI_CAPABILITIES PortCapabilities,
362 IN PSCSI_INQUIRY_DATA LunInfo,
363 IN PCLASS_INIT_DATA InitializationData,
364 IN PUNICODE_STRING RegistryPath
365 );
366
367 VOID
368 NTAPI
369 ScanForSpecial(
370 PDEVICE_OBJECT DeviceObject,
371 PINQUIRYDATA InquiryData,
372 PIO_SCSI_CAPABILITIES PortCapabilities
373 );
374
375 BOOLEAN
376 NTAPI
377 CdRomIsPlayActive(
378 IN PDEVICE_OBJECT DeviceObject
379 );
380
381 VOID
382 NTAPI
383 HitachProcessError(
384 PDEVICE_OBJECT DeviceObject,
385 PSCSI_REQUEST_BLOCK Srb,
386 NTSTATUS *Status,
387 BOOLEAN *Retry
388 );
389
390 IO_COMPLETION_ROUTINE ToshibaProcessErrorCompletion;
391 VOID
392 NTAPI
393 ToshibaProcessError(
394 PDEVICE_OBJECT DeviceObject,
395 PSCSI_REQUEST_BLOCK Srb,
396 NTSTATUS *Status,
397 BOOLEAN *Retry
398 );
399
400 BOOLEAN
401 NTAPI
402 IsThisAnAtapiChanger(
403 IN PDEVICE_OBJECT DeviceObject,
404 OUT PULONG DiscsPresent
405 );
406
407 BOOLEAN
408 NTAPI
409 IsThisASanyo(
410 IN PDEVICE_OBJECT DeviceObject,
411 IN UCHAR PathId,
412 IN UCHAR TargetId
413 );
414
415 BOOLEAN
416 NTAPI
417 IsThisAMultiLunDevice(
418 IN PDEVICE_OBJECT DeviceObject,
419 IN PDEVICE_OBJECT PortDeviceObject
420 );
421
422 VOID
423 NTAPI
424 CdRomCreateNamedEvent(
425 IN PDEVICE_EXTENSION DeviceExtension,
426 IN ULONG DeviceNumber
427 );
428
429 #ifdef _PPC_
430 NTSTATUS
431 FindScsiAdapter (
432 IN HANDLE KeyHandle,
433 IN UNICODE_STRING ScsiUnicodeString[],
434 OUT PUCHAR IntermediateController
435 );
436 #endif
437
438 #ifdef ALLOC_PRAGMA
439 #pragma alloc_text(PAGE, DriverEntry)
440 #pragma alloc_text(PAGE, ScsiCdRomFindDevices)
441 #pragma alloc_text(PAGE, CreateCdRomDeviceObject)
442 #pragma alloc_text(PAGE, ScanForSpecial)
443 //#pragma alloc_text(PAGE, CdRomDeviceControl)
444 #pragma alloc_text(PAGE, HitachProcessError)
445 #pragma alloc_text(PAGE, CdRomIsPlayActive)
446 #pragma alloc_text(PAGE, ScsiCdRomReadVerification)
447 #pragma alloc_text(INIT, CdRomCheckRegistryForMediaChangeValue)
448 #pragma alloc_text(INIT, IsThisAnAtapiChanger)
449 #pragma alloc_text(INIT, IsThisASanyo)
450 #pragma alloc_text(INIT, IsThisAMultiLunDevice)
451 #pragma alloc_text(INIT, CdRomCreateNamedEvent)
452 #ifdef _PPC_
453 #pragma alloc_text(PAGE, FindScsiAdapter)
454 #endif
455 #endif
456
457 ULONG NoLoad = 0;
458
459 NTSTATUS
460 NTAPI
461 DriverEntry(
462 IN PDRIVER_OBJECT DriverObject,
463 IN PUNICODE_STRING RegistryPath
464 )
465
466 /*++
467
468 Routine Description:
469
470 This routine initializes the cdrom class driver.
471
472 Arguments:
473
474 DriverObject - Pointer to driver object created by system.
475
476 RegistryPath - Pointer to the name of the services node for this driver.
477
478 Return Value:
479
480 The function value is the final status from the initialization operation.
481
482 --*/
483
484 {
485 CLASS_INIT_DATA InitializationData;
486
487 if(NoLoad) {
488 return STATUS_NO_SUCH_DEVICE;
489 }
490
491 //
492 // Zero InitData
493 //
494
495 RtlZeroMemory (&InitializationData, sizeof(CLASS_INIT_DATA));
496
497 //
498 // Set sizes
499 //
500
501 InitializationData.InitializationDataSize = sizeof(CLASS_INIT_DATA);
502 InitializationData.DeviceExtensionSize = DEVICE_EXTENSION_SIZE;
503
504 InitializationData.DeviceType = FILE_DEVICE_CD_ROM;
505 InitializationData.DeviceCharacteristics = FILE_REMOVABLE_MEDIA | FILE_READ_ONLY_DEVICE;
506
507 //
508 // Set entry points
509 //
510
511 InitializationData.ClassReadWriteVerification = ScsiCdRomReadVerification;
512 InitializationData.ClassDeviceControl = CdRomDeviceControl;
513 InitializationData.ClassFindDevices = ScsiCdRomFindDevices;
514 InitializationData.ClassShutdownFlush = NULL;
515 InitializationData.ClassCreateClose = NULL;
516 InitializationData.ClassStartIo = ScsiCdRomStartIo;
517
518 //
519 // Call the class init routine
520 //
521
522 return ScsiClassInitialize( DriverObject, RegistryPath, &InitializationData);
523
524 } // end DriverEntry()
525
526 BOOLEAN
527 NTAPI
528 ScsiCdRomFindDevices(
529 IN PDRIVER_OBJECT DriverObject,
530 IN PUNICODE_STRING RegistryPath,
531 IN PCLASS_INIT_DATA InitializationData,
532 IN PDEVICE_OBJECT PortDeviceObject,
533 IN ULONG PortNumber
534 )
535
536 /*++
537
538 Routine Description:
539
540 Connect to SCSI port driver. Get adapter capabilities and
541 SCSI bus configuration information. Search inquiry data
542 for CDROM devices to process.
543
544 Arguments:
545
546 DriverObject - CDROM class driver object.
547 PortDeviceObject - SCSI port driver device object.
548 PortNumber - The system ordinal for this scsi adapter.
549
550 Return Value:
551
552 TRUE if CDROM device present on this SCSI adapter.
553
554 --*/
555
556 {
557 PIO_SCSI_CAPABILITIES portCapabilities;
558 PULONG cdRomCount;
559 PCHAR buffer;
560 PSCSI_INQUIRY_DATA lunInfo;
561 PSCSI_ADAPTER_BUS_INFO adapterInfo;
562 PINQUIRYDATA inquiryData;
563 ULONG scsiBus;
564 NTSTATUS status;
565 BOOLEAN foundDevice = FALSE;
566
567 //
568 // Call port driver to get adapter capabilities.
569 //
570
571 status = ScsiClassGetCapabilities(PortDeviceObject, &portCapabilities);
572
573 if (!NT_SUCCESS(status)) {
574 DebugPrint((1,"FindScsiDevices: ScsiClassGetCapabilities failed\n"));
575 return foundDevice;
576 }
577
578 //
579 // Call port driver to get inquiry information to find cdroms.
580 //
581
582 status = ScsiClassGetInquiryData(PortDeviceObject, (PSCSI_ADAPTER_BUS_INFO *) &buffer);
583
584 if (!NT_SUCCESS(status)) {
585 DebugPrint((1,"FindScsiDevices: ScsiClassGetInquiryData failed\n"));
586 return foundDevice;
587 }
588
589 //
590 // Get the address of the count of the number of cdroms already initialized.
591 //
592
593 cdRomCount = &IoGetConfigurationInformation()->CdRomCount;
594 adapterInfo = (PVOID) buffer;
595
596 //
597 // For each SCSI bus this adapter supports ...
598 //
599
600 for (scsiBus=0; scsiBus < adapterInfo->NumberOfBuses; scsiBus++) {
601
602 //
603 // Get the SCSI bus scan data for this bus.
604 //
605
606 lunInfo = (PVOID) (buffer + adapterInfo->BusData[scsiBus].InquiryDataOffset);
607
608 //
609 // Search list for unclaimed disk devices.
610 //
611
612 while (adapterInfo->BusData[scsiBus].InquiryDataOffset) {
613
614 inquiryData = (PVOID)lunInfo->InquiryData;
615
616 if ((inquiryData->DeviceType == READ_ONLY_DIRECT_ACCESS_DEVICE) &&
617 (inquiryData->DeviceTypeQualifier == 0) &&
618 (!lunInfo->DeviceClaimed)) {
619
620 DebugPrint((1,"FindScsiDevices: Vendor string is %.24s\n",
621 inquiryData->VendorId));
622
623 //
624 // Create device objects for cdrom
625 //
626
627 status = CreateCdRomDeviceObject(DriverObject,
628 PortDeviceObject,
629 PortNumber,
630 cdRomCount,
631 portCapabilities,
632 lunInfo,
633 InitializationData,
634 RegistryPath);
635
636 if (NT_SUCCESS(status)) {
637
638 //
639 // Increment system cdrom device count.
640 //
641
642 (*cdRomCount)++;
643
644 //
645 // Indicate that a cdrom device was found.
646 //
647
648 foundDevice = TRUE;
649 }
650 }
651
652 //
653 // Get next LunInfo.
654 //
655
656 if (lunInfo->NextInquiryDataOffset == 0) {
657 break;
658 }
659
660 lunInfo = (PVOID) (buffer + lunInfo->NextInquiryDataOffset);
661 }
662 }
663
664 ExFreePool(buffer);
665
666
667 return foundDevice;
668
669 } // end FindScsiCdRoms()
670
671 VOID
672 NTAPI
673 CdRomCreateNamedEvent(
674 IN PDEVICE_EXTENSION DeviceExtension,
675 IN ULONG DeviceNumber
676 )
677
678 /*++
679
680 Routine Description:
681
682 Create the named synchronization event for notification of media change
683 events to the system. The event is reset before this function returns.
684
685 Arguments:
686
687 DeviceExtension - the device extension pointer for storage of the event pointer.
688
689 Return Value:
690
691 None.
692
693 --*/
694
695 {
696 UNICODE_STRING unicodeString;
697 OBJECT_ATTRIBUTES objectAttributes;
698 CCHAR eventNameBuffer[MAXIMUM_FILENAME_LENGTH];
699 STRING eventNameString;
700 HANDLE handle;
701 NTSTATUS status;
702
703
704 sprintf(eventNameBuffer,"\\Device\\MediaChangeEvent%ld",
705 DeviceNumber);
706
707 RtlInitString(&eventNameString,
708 eventNameBuffer);
709
710 status = RtlAnsiStringToUnicodeString(&unicodeString,
711 &eventNameString,
712 TRUE);
713
714 if (!NT_SUCCESS(status)) {
715 return;
716 }
717
718 InitializeObjectAttributes(&objectAttributes,
719 &unicodeString,
720 OBJ_PERMANENT | OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
721 NULL,
722 NULL);
723
724 DeviceExtension->MediaChangeEvent = IoCreateSynchronizationEvent(&unicodeString,
725 &handle);
726 DeviceExtension->MediaChangeEventHandle = handle;
727
728 KeClearEvent(DeviceExtension->MediaChangeEvent);
729
730 RtlFreeUnicodeString(&unicodeString);
731 }
732
733 NTSTATUS
734 NTAPI
735 CreateCdRomDeviceObject(
736 IN PDRIVER_OBJECT DriverObject,
737 IN PDEVICE_OBJECT PortDeviceObject,
738 IN ULONG PortNumber,
739 IN PULONG DeviceCount,
740 IN PIO_SCSI_CAPABILITIES PortCapabilities,
741 IN PSCSI_INQUIRY_DATA LunInfo,
742 IN PCLASS_INIT_DATA InitializationData,
743 IN PUNICODE_STRING RegistryPath
744 )
745
746 /*++
747
748 Routine Description:
749
750 This routine creates an object for the device and then calls the
751 SCSI port driver for media capacity and sector size.
752
753 Arguments:
754
755 DriverObject - Pointer to driver object created by system.
756 PortDeviceObject - to connect to SCSI port driver.
757 DeviceCount - Number of previously installed CDROMs.
758 PortCapabilities - Pointer to structure returned by SCSI port
759 driver describing adapter capabilites (and limitations).
760 LunInfo - Pointer to configuration information for this device.
761
762 Return Value:
763
764 NTSTATUS
765
766 --*/
767 {
768 CHAR ntNameBuffer[64];
769 NTSTATUS status;
770 BOOLEAN changerDevice;
771 SCSI_REQUEST_BLOCK srb;
772 ULONG length;
773 PCDROM_DATA cddata;
774 PCDB cdb;
775 PVOID senseData = NULL;
776 PDEVICE_OBJECT deviceObject = NULL;
777 PDEVICE_EXTENSION deviceExtension = NULL;
778 PUCHAR buffer;
779 ULONG bps;
780 ULONG lastBit;
781 ULONG timeOut;
782 BOOLEAN srbListInitialized = FALSE;
783
784 //
785 // Claim the device. Note that any errors after this
786 // will goto the generic handler, where the device will
787 // be released.
788 //
789
790 status = ScsiClassClaimDevice(PortDeviceObject,
791 LunInfo,
792 FALSE,
793 &PortDeviceObject);
794
795 if (!NT_SUCCESS(status)) {
796 return(status);
797 }
798
799 //
800 // Create device object for this device.
801 //
802
803 sprintf(ntNameBuffer,
804 "\\Device\\CdRom%lu",
805 *DeviceCount);
806
807 status = ScsiClassCreateDeviceObject(DriverObject,
808 ntNameBuffer,
809 NULL,
810 &deviceObject,
811 InitializationData);
812
813 if (!NT_SUCCESS(status)) {
814 DebugPrint((1,"CreateCdRomDeviceObjects: Can not create device %s\n",
815 ntNameBuffer));
816
817 goto CreateCdRomDeviceObjectExit;
818 }
819
820 //
821 // Indicate that IRPs should include MDLs.
822 //
823
824 deviceObject->Flags |= DO_DIRECT_IO;
825
826 //
827 // Set up required stack size in device object.
828 //
829
830 deviceObject->StackSize = PortDeviceObject->StackSize + 2;
831
832 deviceExtension = deviceObject->DeviceExtension;
833
834 //
835 // Allocate spinlock for split request completion.
836 //
837
838 KeInitializeSpinLock(&deviceExtension->SplitRequestSpinLock);
839
840 //
841 // This is the physical device.
842 //
843
844 deviceExtension->PhysicalDevice = deviceObject;
845
846 //
847 // Initialize lock count to zero. The lock count is used to
848 // disable the ejection mechanism when media is mounted.
849 //
850
851 deviceExtension->LockCount = 0;
852
853 //
854 // Save system cdrom number
855 //
856
857 deviceExtension->DeviceNumber = *DeviceCount;
858
859 //
860 // Copy port device object to device extension.
861 //
862
863 deviceExtension->PortDeviceObject = PortDeviceObject;
864
865 //
866 // Set the alignment requirements for the device based on the
867 // host adapter requirements
868 //
869
870 if (PortDeviceObject->AlignmentRequirement > deviceObject->AlignmentRequirement) {
871 deviceObject->AlignmentRequirement = PortDeviceObject->AlignmentRequirement;
872 }
873
874 //
875 // Save address of port driver capabilities.
876 //
877
878 deviceExtension->PortCapabilities = PortCapabilities;
879
880 //
881 // Clear SRB flags.
882 //
883
884 deviceExtension->SrbFlags = 0;
885 deviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
886
887 //
888 // Allocate request sense buffer.
889 //
890
891 senseData = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE);
892
893 if (senseData == NULL) {
894
895 //
896 // The buffer cannot be allocated.
897 //
898
899 status = STATUS_INSUFFICIENT_RESOURCES;
900 goto CreateCdRomDeviceObjectExit;
901 }
902
903 //
904 // Set the sense data pointer in the device extension.
905 //
906
907 deviceExtension->SenseData = senseData;
908
909 //
910 // CDROMs are not partitionable so starting offset is 0.
911 //
912
913 deviceExtension->StartingOffset.LowPart = 0;
914 deviceExtension->StartingOffset.HighPart = 0;
915
916 //
917 // Path/TargetId/LUN describes a device location on the SCSI bus.
918 // This information comes from the LunInfo buffer.
919 //
920
921 deviceExtension->PortNumber = (UCHAR)PortNumber;
922 deviceExtension->PathId = LunInfo->PathId;
923 deviceExtension->TargetId = LunInfo->TargetId;
924 deviceExtension->Lun = LunInfo->Lun;
925
926 //
927 // Set timeout value in seconds.
928 //
929
930 timeOut = ScsiClassQueryTimeOutRegistryValue(RegistryPath);
931 if (timeOut) {
932 deviceExtension->TimeOutValue = timeOut;
933 } else {
934 deviceExtension->TimeOutValue = SCSI_CDROM_TIMEOUT;
935 }
936
937 //
938 // Build the lookaside list for srb's for the physical disk. Should only
939 // need a couple.
940 //
941
942 ScsiClassInitializeSrbLookasideList(deviceExtension,
943 CDROM_SRB_LIST_SIZE);
944
945 srbListInitialized = TRUE;
946
947 //
948 // Back pointer to device object.
949 //
950
951 deviceExtension->DeviceObject = deviceObject;
952
953 //
954 // Allocate buffer for drive geometry.
955 //
956
957 deviceExtension->DiskGeometry =
958 ExAllocatePool(NonPagedPool, sizeof(DISK_GEOMETRY));
959
960 if (deviceExtension->DiskGeometry == NULL) {
961
962 status = STATUS_INSUFFICIENT_RESOURCES;
963 goto CreateCdRomDeviceObjectExit;
964 }
965
966 //
967 // Set up media change support defaults.
968 //
969
970 cddata = (PCDROM_DATA)(deviceExtension + 1);
971
972 KeInitializeSpinLock(&cddata->FormSpinLock);
973 KeInitializeSpinLock(&cddata->TimerIrpSpinLock);
974 InitializeListHead(&cddata->TimerIrpList);
975
976 cddata->MediaChangeCountDown = MEDIA_CHANGE_DEFAULT_TIME;
977 cddata->MediaChangeSupported = FALSE;
978 cddata->MediaChange = FALSE;
979
980 //
981 // Assume that there is initially no media in the device
982 // only notify upper layers if there is something there
983 //
984
985 deviceExtension->MediaChangeNoMedia = TRUE;
986 cddata->MediaChangeIrp = NULL;
987 #ifdef DBG
988 cddata->MediaChangeIrpTimeInUse = 0;
989 cddata->MediaChangeIrpLost = FALSE;
990 #endif
991
992 //
993 // Scan for Scsi controllers that require special processing.
994 //
995
996 ScanForSpecial(deviceObject,
997 (PINQUIRYDATA) LunInfo->InquiryData,
998 PortCapabilities);
999
1000 //
1001 // Do READ CAPACITY. This SCSI command
1002 // returns the last sector address on the device
1003 // and the bytes per sector.
1004 // These are used to calculate the drive capacity
1005 // in bytes.
1006 //
1007
1008 status = ScsiClassReadDriveCapacity(deviceObject);
1009 bps = deviceExtension->DiskGeometry->BytesPerSector;
1010
1011 if (!NT_SUCCESS(status) || !bps) {
1012
1013 DebugPrint((1,
1014 "CreateCdRomDeviceObjects: Can't read capacity for device %s\n",
1015 ntNameBuffer));
1016
1017 //
1018 // Set disk geometry to default values (per ISO 9660).
1019 //
1020
1021 bps = 2048;
1022 deviceExtension->SectorShift = 11;
1023 deviceExtension->PartitionLength.QuadPart = (LONGLONG)(0x7fffffff);
1024 } else {
1025
1026 //
1027 // Insure that bytes per sector is a power of 2
1028 // This corrects a problem with the HP 4020i CDR where it
1029 // returns an incorrect number for bytes per sector.
1030 //
1031
1032 lastBit = (ULONG) -1;
1033 while (bps) {
1034 lastBit++;
1035 bps = bps >> 1;
1036 }
1037
1038 bps = 1 << lastBit;
1039 }
1040 deviceExtension->DiskGeometry->BytesPerSector = bps;
1041 DebugPrint((2, "CreateCdRomDeviceObject: Calc'd bps = %x\n", bps));
1042
1043 //
1044 // Check to see if this is some sort of changer device
1045 //
1046
1047 changerDevice = FALSE;
1048
1049 //
1050 // Search for devices that have special requirements for media
1051 // change support.
1052 //
1053
1054 if (deviceExtension->Lun > 0) {
1055 changerDevice = TRUE;
1056 }
1057
1058 if (!changerDevice) {
1059 changerDevice = IsThisASanyo(deviceObject, deviceExtension->PathId,
1060 deviceExtension->TargetId);
1061 }
1062
1063 if (!changerDevice) {
1064 ULONG tmp;
1065 changerDevice = IsThisAnAtapiChanger(deviceObject, &tmp);
1066 }
1067
1068 if (!changerDevice) {
1069 changerDevice = IsThisAMultiLunDevice(deviceObject, PortDeviceObject);
1070 }
1071
1072 //
1073 // If it is a changer device, increment the timeout to take platter-swapping
1074 // time into account
1075 //
1076
1077 if(changerDevice) {
1078 deviceExtension->TimeOutValue += SCSI_CHANGER_BONUS_TIMEOUT;
1079 }
1080
1081 //
1082 // Create the media change named event. If this succeeds then continue
1083 // initializing the media change support data items.
1084 //
1085
1086 CdRomCreateNamedEvent(deviceExtension,*DeviceCount);
1087 if (deviceExtension->MediaChangeEvent) {
1088
1089 //
1090 // If this is not a changer, get an IRP for the timer request
1091 // and initialize the timer.
1092 //
1093
1094 if (!changerDevice) {
1095
1096 //
1097 // Not a changer device - continue with media change initialization.
1098 // Determine if the user actually wants media change events.
1099 //
1100
1101 if (CdRomCheckRegistryForMediaChangeValue(RegistryPath, *DeviceCount)) {
1102 PIO_STACK_LOCATION irpStack;
1103 PSCSI_REQUEST_BLOCK srb;
1104 PIRP irp;
1105
1106 //
1107 // User wants it - preallocate IRP and SRB.
1108 //
1109
1110 irp = IoAllocateIrp((CCHAR)(deviceObject->StackSize+1),
1111 FALSE);
1112 if (irp) {
1113 PVOID buffer;
1114
1115 srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK));
1116 buffer = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE);
1117
1118 if (srb && buffer) {
1119 PCDB cdb;
1120
1121 //
1122 // All resources have been allocated set up the IRP.
1123 //
1124
1125 IoSetNextIrpStackLocation(irp);
1126 irpStack = IoGetCurrentIrpStackLocation(irp);
1127 irpStack->DeviceObject = deviceObject;
1128 irpStack = IoGetNextIrpStackLocation(irp);
1129 cddata->MediaChangeIrp = irp;
1130 irpStack->Parameters.Scsi.Srb = srb;
1131
1132 //
1133 // Initialize the SRB
1134 //
1135
1136 RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
1137
1138 srb->CdbLength = 6;
1139 srb->TimeOutValue = deviceExtension->TimeOutValue * 2;
1140 srb->QueueTag = SP_UNTAGGED;
1141 srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
1142 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
1143 srb->PathId = deviceExtension->PathId;
1144 srb->TargetId = deviceExtension->TargetId;
1145 srb->Lun = deviceExtension->Lun;
1146 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1147
1148 //
1149 // Initialize and set up the sense information buffer
1150 //
1151
1152 RtlZeroMemory(buffer, SENSE_BUFFER_SIZE);
1153 srb->SenseInfoBuffer = buffer;
1154 srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
1155
1156 //
1157 // Initialize the CDB
1158 //
1159
1160 cdb = (PCDB)&srb->Cdb[0];
1161 cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
1162 cdb->CDB6GENERIC.LogicalUnitNumber = deviceExtension->Lun;
1163
1164 //
1165 // It is ok to support media change events on this device.
1166 //
1167
1168 cddata->MediaChangeSupported = TRUE;
1169 cddata->MediaChange = TRUE;
1170
1171 } else {
1172
1173 if (srb) {
1174 ExFreePool(srb);
1175 }
1176 if (buffer) {
1177 ExFreePool(buffer);
1178 }
1179 IoFreeIrp(irp);
1180 }
1181 }
1182 } else {
1183 deviceExtension->MediaChangeEvent = NULL;
1184 }
1185 } else {
1186 deviceExtension->MediaChangeEvent = NULL;
1187 }
1188 }
1189
1190 //
1191 // Assume use of 6-byte mode sense/select for now.
1192 //
1193
1194 cddata->XAFlags |= XA_USE_6_BYTE;
1195
1196 //
1197 // Build and issue mode sense with Read error recovery page. This will be used to change
1198 // block size in case of any raw reads (Mode 2, Form 2).
1199 //
1200
1201 length = (sizeof(MODE_READ_RECOVERY_PAGE) + MODE_BLOCK_DESC_LENGTH + MODE_HEADER_LENGTH);
1202
1203 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
1204
1205 srb.CdbLength = 6;
1206 cdb = (PCDB)srb.Cdb;
1207
1208 //
1209 // Set timeout value from device extension.
1210 //
1211
1212 srb.TimeOutValue = deviceExtension->TimeOutValue;
1213
1214 //
1215 // Build the MODE SENSE CDB. The data returned will be kept in the device extension
1216 // and used to set block size.
1217 //
1218
1219 cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
1220 cdb->MODE_SENSE.PageCode = 0x1;
1221 cdb->MODE_SENSE.AllocationLength = (UCHAR)length;
1222
1223 buffer = ExAllocatePool(NonPagedPoolCacheAligned, (sizeof(MODE_READ_RECOVERY_PAGE) + MODE_BLOCK_DESC_LENGTH + MODE_HEADER_LENGTH10));
1224 if (!buffer) {
1225 status = STATUS_INSUFFICIENT_RESOURCES;
1226 goto CreateCdRomDeviceObjectExit;
1227 }
1228
1229 status = ScsiClassSendSrbSynchronous(deviceObject,
1230 &srb,
1231 buffer,
1232 length,
1233 FALSE);
1234 if (!NT_SUCCESS(status)) {
1235
1236 //
1237 // May be Atapi, try 10-byte.
1238 //
1239
1240 length = (sizeof(MODE_READ_RECOVERY_PAGE) + MODE_BLOCK_DESC_LENGTH + MODE_HEADER_LENGTH10);
1241
1242 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
1243
1244 //
1245 // Build the MODE SENSE CDB.
1246 //
1247
1248 srb.CdbLength = 10;
1249 cdb = (PCDB)srb.Cdb;
1250
1251 //
1252 // Set timeout value from device extension.
1253 //
1254
1255 srb.TimeOutValue = deviceExtension->TimeOutValue;
1256
1257 cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
1258 cdb->MODE_SENSE10.PageCode = 0x1;
1259
1260 cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(length >> 8);
1261 cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(length & 0xFF);
1262
1263 status = ScsiClassSendSrbSynchronous(deviceObject,
1264 &srb,
1265 buffer,
1266 length,
1267 FALSE);
1268 if (status == STATUS_DATA_OVERRUN) {
1269
1270 //
1271 // Build and issue the ReadCd command to ensure that this device supports it.
1272 //
1273
1274 RtlZeroMemory(cdb, 12);
1275
1276 cdb->READ_CD.OperationCode = SCSIOP_READ_CD;
1277
1278 status = ScsiClassSendSrbSynchronous(deviceObject,
1279 &srb,
1280 NULL,
1281 0,
1282 FALSE);
1283
1284 //
1285 // If the command wasn't rejected then support the READ_CD.
1286 //
1287
1288 if (NT_SUCCESS(status) || (status == STATUS_NO_MEDIA_IN_DEVICE)) {
1289
1290 //
1291 // Using Read CD precludes issueing a mode select to
1292 // set the user data size. So, no buffer copy is
1293 // necessary.
1294 //
1295
1296 cddata->XAFlags &= ~XA_USE_6_BYTE;
1297 cddata->XAFlags = XA_USE_READ_CD | XA_USE_10_BYTE;
1298 } else {
1299
1300 RtlCopyMemory(&cddata->u1.Header, buffer, sizeof(ERROR_RECOVERY_DATA10));
1301 cddata->u1.Header.ModeDataLength = 0;
1302
1303 cddata->XAFlags &= ~XA_USE_6_BYTE;
1304 cddata->XAFlags |= XA_USE_10_BYTE;
1305 }
1306
1307 } else if (NT_SUCCESS(status)) {
1308
1309 RtlCopyMemory(&cddata->u1.Header, buffer, sizeof(ERROR_RECOVERY_DATA10));
1310 cddata->u1.Header.ModeDataLength = 0;
1311
1312 cddata->XAFlags &= ~XA_USE_6_BYTE;
1313 cddata->XAFlags |= XA_USE_10_BYTE;
1314
1315 } else {
1316 cddata->XAFlags |= XA_NOT_SUPPORTED;
1317 }
1318 } else {
1319 RtlCopyMemory(&cddata->u1.Header, buffer, sizeof(ERROR_RECOVERY_DATA));
1320 cddata->u1.Header.ModeDataLength = 0;
1321 }
1322
1323 ExFreePool(buffer);
1324
1325 //
1326 // Start the timer now regardless of if Autorun is enabled.
1327 // The timer must run forever since IoStopTimer faults.
1328 //
1329
1330 IoInitializeTimer(deviceObject, CdRomTickHandler, NULL);
1331 IoStartTimer(deviceObject);
1332
1333 return(STATUS_SUCCESS);
1334
1335 CreateCdRomDeviceObjectExit:
1336
1337 //
1338 // Release the device since an error occured.
1339 //
1340
1341 ScsiClassClaimDevice(PortDeviceObject,
1342 LunInfo,
1343 TRUE,
1344 NULL);
1345
1346 if (senseData != NULL) {
1347 ExFreePool(senseData);
1348 }
1349
1350 if (deviceExtension->DiskGeometry != NULL) {
1351 ExFreePool(deviceExtension->DiskGeometry);
1352 }
1353
1354 if (deviceObject != NULL) {
1355 if (srbListInitialized) {
1356 ExDeleteNPagedLookasideList(&deviceExtension->SrbLookasideListHead);
1357 }
1358 IoDeleteDevice(deviceObject);
1359 }
1360
1361
1362 return status;
1363
1364 } // end CreateCdRomDeviceObject()
1365
1366 VOID
1367 NTAPI
1368 ScsiCdRomStartIo(
1369 IN PDEVICE_OBJECT DeviceObject,
1370 IN PIRP Irp
1371 )
1372 {
1373
1374 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
1375 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
1376 PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
1377 PIO_STACK_LOCATION irpStack;
1378 PIRP irp2 = NULL;
1379 ULONG transferPages;
1380 ULONG transferByteCount = currentIrpStack->Parameters.Read.Length;
1381 ULONG maximumTransferLength = deviceExtension->PortCapabilities->MaximumTransferLength;
1382 PCDROM_DATA cdData;
1383 PSCSI_REQUEST_BLOCK srb = NULL;
1384 PCDB cdb;
1385 PUCHAR senseBuffer = NULL;
1386 PVOID dataBuffer;
1387 NTSTATUS status;
1388 BOOLEAN use6Byte;
1389
1390 //
1391 // Mark IRP with status pending.
1392 //
1393
1394 IoMarkIrpPending(Irp);
1395
1396 //
1397 // If the flag is set in the device object, force a verify.
1398 //
1399
1400 if (DeviceObject->Flags & DO_VERIFY_VOLUME) {
1401 DebugPrint((2, "ScsiCdRomStartIo: [%lx] Volume needs verified\n", Irp));
1402 if (!(currentIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME)) {
1403
1404 if (Irp->Tail.Overlay.Thread) {
1405 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
1406 }
1407
1408 Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
1409
1410 DebugPrint((2, "ScsiCdRomStartIo: [%lx] Calling UpdateCapcity - "
1411 "ioctl event = %lx\n",
1412 Irp,
1413 nextIrpStack->Parameters.Others.Argument1
1414 ));
1415
1416 //
1417 // our device control dispatch routine stores an event in the next
1418 // stack location to signal when startio has completed. We need to
1419 // pass this in so that the update capacity completion routine can
1420 // set it rather than completing the Irp.
1421 //
1422
1423 status = CdRomUpdateCapacity(deviceExtension,
1424 Irp,
1425 nextIrpStack->Parameters.Others.Argument1
1426 );
1427
1428 DebugPrint((2, "ScsiCdRomStartIo: [%lx] UpdateCapacity returned %lx\n", Irp, status));
1429 ASSERT(status == STATUS_PENDING);
1430 return;
1431 }
1432 }
1433
1434 cdData = (PCDROM_DATA)(deviceExtension + 1);
1435 use6Byte = cdData->XAFlags & XA_USE_6_BYTE;
1436
1437 if (currentIrpStack->MajorFunction == IRP_MJ_READ) {
1438
1439 //
1440 // Add partition byte offset to make starting byte relative to
1441 // beginning of disk. In addition, add in skew for DM Driver, if any.
1442 //
1443
1444 currentIrpStack->Parameters.Read.ByteOffset.QuadPart += (deviceExtension->StartingOffset.QuadPart);
1445
1446 //
1447 // Calculate number of pages in this transfer.
1448 //
1449
1450 transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp->MdlAddress),
1451 currentIrpStack->Parameters.Read.Length);
1452
1453 //
1454 // Check if request length is greater than the maximum number of
1455 // bytes that the hardware can transfer.
1456 //
1457
1458 if (cdData->RawAccess) {
1459
1460 ASSERT(!(cdData->XAFlags & XA_USE_READ_CD));
1461
1462 //
1463 // Fire off a mode select to switch back to cooked sectors.
1464 //
1465
1466 irp2 = IoAllocateIrp((CCHAR)(deviceExtension->DeviceObject->StackSize+1),
1467 FALSE);
1468
1469 if (!irp2) {
1470 Irp->IoStatus.Information = 0;
1471 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1472 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1473 IoStartNextPacket(DeviceObject, FALSE);
1474 return;
1475 }
1476
1477 srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK));
1478 if (!srb) {
1479 Irp->IoStatus.Information = 0;
1480 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1481 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1482 IoFreeIrp(irp2);
1483 IoStartNextPacket(DeviceObject, FALSE);
1484 return;
1485 }
1486
1487 RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
1488
1489 cdb = (PCDB)srb->Cdb;
1490
1491 //
1492 // Allocate sense buffer.
1493 //
1494
1495 senseBuffer = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE);
1496
1497 if (!senseBuffer) {
1498 Irp->IoStatus.Information = 0;
1499 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1500 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1501 ExFreePool(srb);
1502 IoFreeIrp(irp2);
1503 IoStartNextPacket(DeviceObject, FALSE);
1504 return;
1505 }
1506
1507 //
1508 // Set up the irp.
1509 //
1510
1511 IoSetNextIrpStackLocation(irp2);
1512 irp2->IoStatus.Status = STATUS_SUCCESS;
1513 irp2->IoStatus.Information = 0;
1514 irp2->Flags = 0;
1515 irp2->UserBuffer = NULL;
1516
1517 //
1518 // Save the device object and irp in a private stack location.
1519 //
1520
1521 irpStack = IoGetCurrentIrpStackLocation(irp2);
1522 irpStack->DeviceObject = deviceExtension->DeviceObject;
1523 irpStack->Parameters.Others.Argument2 = (PVOID) Irp;
1524
1525 //
1526 // The retry count will be in the real Irp, as the retry logic will
1527 // recreate our private irp.
1528 //
1529
1530 if (!(nextIrpStack->Parameters.Others.Argument1)) {
1531
1532 //
1533 // Only jam this in if it doesn't exist. The completion routines can
1534 // call StartIo directly in the case of retries and resetting it will
1535 // cause infinite loops.
1536 //
1537
1538 nextIrpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES;
1539 }
1540
1541 //
1542 // Construct the IRP stack for the lower level driver.
1543 //
1544
1545 irpStack = IoGetNextIrpStackLocation(irp2);
1546 irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
1547 irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
1548 irpStack->Parameters.Scsi.Srb = srb;
1549
1550 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
1551 srb->PathId = deviceExtension->PathId;
1552 srb->TargetId = deviceExtension->TargetId;
1553 srb->Lun = deviceExtension->Lun;
1554 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1555 srb->Cdb[1] |= deviceExtension->Lun << 5;
1556 srb->SrbStatus = srb->ScsiStatus = 0;
1557 srb->NextSrb = 0;
1558 srb->OriginalRequest = irp2;
1559 srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
1560 srb->SenseInfoBuffer = senseBuffer;
1561
1562 transferByteCount = (use6Byte) ? sizeof(ERROR_RECOVERY_DATA) : sizeof(ERROR_RECOVERY_DATA10);
1563 dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned, transferByteCount );
1564 if (!dataBuffer) {
1565 Irp->IoStatus.Information = 0;
1566 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1567 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1568 ExFreePool(senseBuffer);
1569 ExFreePool(srb);
1570 IoFreeIrp(irp2);
1571 IoStartNextPacket(DeviceObject, FALSE);
1572 return;
1573
1574 }
1575
1576 irp2->MdlAddress = IoAllocateMdl(dataBuffer,
1577 transferByteCount,
1578 FALSE,
1579 FALSE,
1580 (PIRP) NULL);
1581
1582 if (!irp2->MdlAddress) {
1583 Irp->IoStatus.Information = 0;
1584 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1585 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1586 ExFreePool(senseBuffer);
1587 ExFreePool(srb);
1588 ExFreePool(dataBuffer);
1589 IoFreeIrp(irp2);
1590 IoStartNextPacket(DeviceObject, FALSE);
1591 return;
1592 }
1593
1594 //
1595 // Prepare the MDL
1596 //
1597
1598 MmBuildMdlForNonPagedPool(irp2->MdlAddress);
1599
1600 srb->DataBuffer = dataBuffer;
1601
1602 //
1603 // Set the new block size in the descriptor.
1604 //
1605
1606 cdData->u1.BlockDescriptor.BlockLength[0] = (UCHAR)(COOKED_SECTOR_SIZE >> 16) & 0xFF;
1607 cdData->u1.BlockDescriptor.BlockLength[1] = (UCHAR)(COOKED_SECTOR_SIZE >> 8) & 0xFF;
1608 cdData->u1.BlockDescriptor.BlockLength[2] = (UCHAR)(COOKED_SECTOR_SIZE & 0xFF);
1609
1610 //
1611 // Move error page into dataBuffer.
1612 //
1613
1614 RtlCopyMemory(srb->DataBuffer, &cdData->u1.Header, transferByteCount);
1615
1616 //
1617 // Build and send a mode select to switch into raw mode.
1618 //
1619
1620 srb->SrbFlags = deviceExtension->SrbFlags;
1621 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_OUT);
1622 srb->DataTransferLength = transferByteCount;
1623 srb->TimeOutValue = deviceExtension->TimeOutValue * 2;
1624
1625 if (use6Byte) {
1626 srb->CdbLength = 6;
1627 cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
1628 cdb->MODE_SELECT.PFBit = 1;
1629 cdb->MODE_SELECT.ParameterListLength = (UCHAR)transferByteCount;
1630 } else {
1631
1632 srb->CdbLength = 10;
1633 cdb->MODE_SELECT10.OperationCode = SCSIOP_MODE_SELECT10;
1634 cdb->MODE_SELECT10.PFBit = 1;
1635 cdb->MODE_SELECT10.ParameterListLength[0] = (UCHAR)(transferByteCount >> 8);
1636 cdb->MODE_SELECT10.ParameterListLength[1] = (UCHAR)(transferByteCount & 0xFF);
1637 }
1638
1639 //
1640 // Update completion routine.
1641 //
1642
1643 IoSetCompletionRoutine(irp2,
1644 CdRomSwitchModeCompletion,
1645 srb,
1646 TRUE,
1647 TRUE,
1648 TRUE);
1649
1650 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
1651 return;
1652 }
1653
1654 if ((currentIrpStack->Parameters.Read.Length > maximumTransferLength) ||
1655 (transferPages >
1656 deviceExtension->PortCapabilities->MaximumPhysicalPages)) {
1657
1658 //
1659 // Request needs to be split. Completion of each portion of the
1660 // request will fire off the next portion. The final request will
1661 // signal Io to send a new request.
1662 //
1663
1664 transferPages =
1665 deviceExtension->PortCapabilities->MaximumPhysicalPages - 1;
1666
1667 if(maximumTransferLength > transferPages << PAGE_SHIFT) {
1668 maximumTransferLength = transferPages << PAGE_SHIFT;
1669 }
1670
1671 //
1672 // Check that the maximum transfer size is not zero
1673 //
1674
1675 if(maximumTransferLength == 0) {
1676 maximumTransferLength = PAGE_SIZE;
1677 }
1678
1679 ScsiClassSplitRequest(DeviceObject, Irp, maximumTransferLength);
1680 return;
1681
1682 } else {
1683
1684 //
1685 // Build SRB and CDB for this IRP.
1686 //
1687
1688 ScsiClassBuildRequest(DeviceObject, Irp);
1689
1690 }
1691
1692
1693 } else if (currentIrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) {
1694
1695 //
1696 // Allocate an irp, srb and associated structures.
1697 //
1698
1699 irp2 = IoAllocateIrp((CCHAR)(deviceExtension->DeviceObject->StackSize+1),
1700 FALSE);
1701
1702 if (!irp2) {
1703 Irp->IoStatus.Information = 0;
1704 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1705 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1706 IoStartNextPacket(DeviceObject, FALSE);
1707 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp, Irp->IoStatus.Status, __LINE__));
1708 return;
1709 }
1710
1711 srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK));
1712 if (!srb) {
1713 Irp->IoStatus.Information = 0;
1714 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1715 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1716 IoFreeIrp(irp2);
1717 IoStartNextPacket(DeviceObject, FALSE);
1718 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp, Irp->IoStatus.Status, __LINE__));
1719 return;
1720 }
1721
1722 RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
1723
1724 cdb = (PCDB)srb->Cdb;
1725
1726 //
1727 // Allocate sense buffer.
1728 //
1729
1730 senseBuffer = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE);
1731
1732 if (!senseBuffer) {
1733 Irp->IoStatus.Information = 0;
1734 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1735 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1736 ExFreePool(srb);
1737 IoFreeIrp(irp2);
1738 IoStartNextPacket(DeviceObject, FALSE);
1739 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp, Irp->IoStatus.Status, __LINE__));
1740 return;
1741 }
1742
1743 //
1744 // Set up the irp.
1745 //
1746
1747 IoSetNextIrpStackLocation(irp2);
1748 irp2->IoStatus.Status = STATUS_SUCCESS;
1749 irp2->IoStatus.Information = 0;
1750 irp2->Flags = 0;
1751 irp2->UserBuffer = NULL;
1752
1753 //
1754 // Save the device object and irp in a private stack location.
1755 //
1756
1757 irpStack = IoGetCurrentIrpStackLocation(irp2);
1758 irpStack->DeviceObject = deviceExtension->DeviceObject;
1759 irpStack->Parameters.Others.Argument2 = (PVOID) Irp;
1760
1761 //
1762 // The retry count will be in the real Irp, as the retry logic will
1763 // recreate our private irp.
1764 //
1765
1766 if (!(nextIrpStack->Parameters.Others.Argument1)) {
1767
1768 //
1769 // Only jam this in if it doesn't exist. The completion routines can
1770 // call StartIo directly in the case of retries and resetting it will
1771 // cause infinite loops.
1772 //
1773
1774 nextIrpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES;
1775 }
1776
1777 //
1778 // Construct the IRP stack for the lower level driver.
1779 //
1780
1781 irpStack = IoGetNextIrpStackLocation(irp2);
1782 irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
1783 irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
1784 irpStack->Parameters.Scsi.Srb = srb;
1785
1786 IoSetCompletionRoutine(irp2,
1787 CdRomDeviceControlCompletion,
1788 srb,
1789 TRUE,
1790 TRUE,
1791 TRUE);
1792 //
1793 // Setup those fields that are generic to all requests.
1794 //
1795
1796 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
1797 srb->PathId = deviceExtension->PathId;
1798 srb->TargetId = deviceExtension->TargetId;
1799 srb->Lun = deviceExtension->Lun;
1800 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1801 srb->Cdb[1] |= deviceExtension->Lun << 5;
1802 srb->SrbStatus = srb->ScsiStatus = 0;
1803 srb->NextSrb = 0;
1804 srb->OriginalRequest = irp2;
1805 srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
1806 srb->SenseInfoBuffer = senseBuffer;
1807
1808 switch (currentIrpStack->Parameters.DeviceIoControl.IoControlCode) {
1809
1810 case IOCTL_CDROM_RAW_READ: {
1811
1812 //
1813 // Determine whether the drive is currently in raw or cooked mode,
1814 // and which command to use to read the data.
1815 //
1816
1817 if (!(cdData->XAFlags & XA_USE_READ_CD)) {
1818
1819 PRAW_READ_INFO rawReadInfo =
1820 (PRAW_READ_INFO)currentIrpStack->Parameters.DeviceIoControl.Type3InputBuffer;
1821 ULONG maximumTransferLength;
1822 ULONG transferPages;
1823
1824 if (cdData->RawAccess) {
1825
1826 ULONG startingSector;
1827
1828 //
1829 // Free the recently allocated irp, as we don't need it.
1830 //
1831
1832 IoFreeIrp(irp2);
1833
1834 cdb = (PCDB)srb->Cdb;
1835 RtlZeroMemory(cdb, 12);
1836
1837 //
1838 // Calculate starting offset.
1839 //
1840
1841 startingSector = (ULONG)(rawReadInfo->DiskOffset.QuadPart >> deviceExtension->SectorShift);
1842 transferByteCount = rawReadInfo->SectorCount * RAW_SECTOR_SIZE;
1843 maximumTransferLength = deviceExtension->PortCapabilities->MaximumTransferLength;
1844 transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp->MdlAddress),
1845 transferByteCount);
1846
1847 //
1848 // Determine if request is within limits imposed by miniport.
1849 //
1850
1851 if (transferByteCount > maximumTransferLength ||
1852 transferPages > deviceExtension->PortCapabilities->MaximumPhysicalPages) {
1853
1854 //
1855 // The claim is that this won't happen, and is backed up by
1856 // ActiveMovie usage, which does unbuffered XA reads of 0x18000, yet
1857 // we get only 4 sector requests.
1858 //
1859
1860
1861 Irp->IoStatus.Information = 0;
1862 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
1863 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1864 ExFreePool(senseBuffer);
1865 ExFreePool(srb);
1866 IoStartNextPacket(DeviceObject, FALSE);
1867 return;
1868
1869 }
1870
1871 srb->OriginalRequest = Irp;
1872 srb->SrbFlags = deviceExtension->SrbFlags;
1873 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN);
1874 srb->DataTransferLength = transferByteCount;
1875 srb->TimeOutValue = deviceExtension->TimeOutValue;
1876 srb->CdbLength = 10;
1877 srb->DataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
1878
1879 if (rawReadInfo->TrackMode == CDDA) {
1880 if (cdData->XAFlags & PLEXTOR_CDDA) {
1881
1882 srb->CdbLength = 12;
1883
1884 cdb->PLXTR_READ_CDDA.LogicalUnitNumber = deviceExtension->Lun;
1885 cdb->PLXTR_READ_CDDA.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF);
1886 cdb->PLXTR_READ_CDDA.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF);
1887 cdb->PLXTR_READ_CDDA.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF);
1888 cdb->PLXTR_READ_CDDA.LogicalBlockByte0 = (UCHAR) ((startingSector >> 24) & 0xFF);
1889
1890 cdb->PLXTR_READ_CDDA.TransferBlockByte3 = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
1891 cdb->PLXTR_READ_CDDA.TransferBlockByte2 = (UCHAR) (rawReadInfo->SectorCount >> 8);
1892 cdb->PLXTR_READ_CDDA.TransferBlockByte1 = 0;
1893 cdb->PLXTR_READ_CDDA.TransferBlockByte0 = 0;
1894
1895 cdb->PLXTR_READ_CDDA.SubCode = 0;
1896 cdb->PLXTR_READ_CDDA.OperationCode = 0xD8;
1897
1898 } else if (cdData->XAFlags & NEC_CDDA) {
1899
1900 cdb->NEC_READ_CDDA.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF);
1901 cdb->NEC_READ_CDDA.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF);
1902 cdb->NEC_READ_CDDA.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF);
1903 cdb->NEC_READ_CDDA.LogicalBlockByte0 = (UCHAR) ((startingSector >> 24) & 0xFF);
1904
1905 cdb->NEC_READ_CDDA.TransferBlockByte1 = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
1906 cdb->NEC_READ_CDDA.TransferBlockByte0 = (UCHAR) (rawReadInfo->SectorCount >> 8);
1907
1908 cdb->NEC_READ_CDDA.OperationCode = 0xD4;
1909 }
1910 } else {
1911
1912 cdb->CDB10.LogicalUnitNumber = deviceExtension->Lun;
1913
1914 cdb->CDB10.TransferBlocksMsb = (UCHAR) (rawReadInfo->SectorCount >> 8);
1915 cdb->CDB10.TransferBlocksLsb = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
1916
1917 cdb->CDB10.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF);
1918 cdb->CDB10.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF);
1919 cdb->CDB10.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF);
1920 cdb->CDB10.LogicalBlockByte0 = (UCHAR) ((startingSector >> 24) & 0xFF);
1921
1922 cdb->CDB10.OperationCode = SCSIOP_READ;
1923 }
1924
1925 srb->SrbStatus = srb->ScsiStatus = 0;
1926
1927 nextIrpStack->MajorFunction = IRP_MJ_SCSI;
1928 nextIrpStack->Parameters.Scsi.Srb = srb;
1929
1930 if (!(nextIrpStack->Parameters.Others.Argument1)) {
1931
1932 //
1933 // Only jam this in if it doesn't exist. The completion routines can
1934 // call StartIo directly in the case of retries and resetting it will
1935 // cause infinite loops.
1936 //
1937
1938 nextIrpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES;
1939 }
1940
1941 //
1942 // Set up IoCompletion routine address.
1943 //
1944
1945 IoSetCompletionRoutine(Irp,
1946 CdRomXACompletion,
1947 srb,
1948 TRUE,
1949 TRUE,
1950 TRUE);
1951
1952 IoCallDriver(deviceExtension->PortDeviceObject, Irp);
1953 return;
1954
1955 } else {
1956
1957 transferByteCount = (use6Byte) ? sizeof(ERROR_RECOVERY_DATA) : sizeof(ERROR_RECOVERY_DATA10);
1958 dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned, transferByteCount );
1959 if (!dataBuffer) {
1960 Irp->IoStatus.Information = 0;
1961 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1962 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1963 ExFreePool(senseBuffer);
1964 ExFreePool(srb);
1965 IoFreeIrp(irp2);
1966 IoStartNextPacket(DeviceObject, FALSE);
1967 return;
1968
1969 }
1970
1971 irp2->MdlAddress = IoAllocateMdl(dataBuffer,
1972 transferByteCount,
1973 FALSE,
1974 FALSE,
1975 (PIRP) NULL);
1976
1977 if (!irp2->MdlAddress) {
1978 Irp->IoStatus.Information = 0;
1979 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1980 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1981 ExFreePool(senseBuffer);
1982 ExFreePool(srb);
1983 ExFreePool(dataBuffer);
1984 IoFreeIrp(irp2);
1985 IoStartNextPacket(DeviceObject, FALSE);
1986 return;
1987 }
1988
1989 //
1990 // Prepare the MDL
1991 //
1992
1993 MmBuildMdlForNonPagedPool(irp2->MdlAddress);
1994
1995 srb->DataBuffer = dataBuffer;
1996
1997 //
1998 // Set the new block size in the descriptor.
1999 //
2000
2001 cdData->u1.BlockDescriptor.BlockLength[0] = (UCHAR)(RAW_SECTOR_SIZE >> 16) & 0xFF;
2002 cdData->u1.BlockDescriptor.BlockLength[1] = (UCHAR)(RAW_SECTOR_SIZE >> 8) & 0xFF;
2003 cdData->u1.BlockDescriptor.BlockLength[2] = (UCHAR)(RAW_SECTOR_SIZE & 0xFF);
2004
2005
2006 //
2007 // TODO: Set density code, based on operation
2008 //
2009
2010 cdData->u1.BlockDescriptor.DensityCode = 0;
2011
2012
2013 //
2014 // Move error page into dataBuffer.
2015 //
2016
2017 RtlCopyMemory(srb->DataBuffer, &cdData->u1.Header, transferByteCount);
2018
2019
2020 //
2021 // Build and send a mode select to switch into raw mode.
2022 //
2023
2024 srb->SrbFlags = deviceExtension->SrbFlags;
2025 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_OUT);
2026 srb->DataTransferLength = transferByteCount;
2027 srb->TimeOutValue = deviceExtension->TimeOutValue * 2;
2028
2029 if (use6Byte) {
2030 srb->CdbLength = 6;
2031 cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
2032 cdb->MODE_SELECT.PFBit = 1;
2033 cdb->MODE_SELECT.ParameterListLength = (UCHAR)transferByteCount;
2034 } else {
2035
2036 srb->CdbLength = 10;
2037 cdb->MODE_SELECT10.OperationCode = SCSIOP_MODE_SELECT10;
2038 cdb->MODE_SELECT10.PFBit = 1;
2039 cdb->MODE_SELECT10.ParameterListLength[0] = (UCHAR)(transferByteCount >> 8);
2040 cdb->MODE_SELECT10.ParameterListLength[1] = (UCHAR)(transferByteCount & 0xFF);
2041 }
2042
2043 //
2044 // Update completion routine.
2045 //
2046
2047 IoSetCompletionRoutine(irp2,
2048 CdRomSwitchModeCompletion,
2049 srb,
2050 TRUE,
2051 TRUE,
2052 TRUE);
2053
2054 }
2055
2056 } else {
2057
2058 PRAW_READ_INFO rawReadInfo =
2059 (PRAW_READ_INFO)currentIrpStack->Parameters.DeviceIoControl.Type3InputBuffer;
2060 ULONG startingSector;
2061
2062 //
2063 // Free the recently allocated irp, as we don't need it.
2064 //
2065
2066 IoFreeIrp(irp2);
2067
2068 cdb = (PCDB)srb->Cdb;
2069 RtlZeroMemory(cdb, 12);
2070
2071
2072 //
2073 // Calculate starting offset.
2074 //
2075
2076 startingSector = (ULONG)(rawReadInfo->DiskOffset.QuadPart >> deviceExtension->SectorShift);
2077 transferByteCount = rawReadInfo->SectorCount * RAW_SECTOR_SIZE;
2078
2079
2080 srb->OriginalRequest = Irp;
2081 srb->SrbFlags = deviceExtension->SrbFlags;
2082 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN);
2083 srb->DataTransferLength = transferByteCount;
2084 srb->TimeOutValue = deviceExtension->TimeOutValue;
2085 srb->DataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
2086 srb->CdbLength = 12;
2087 srb->SrbStatus = srb->ScsiStatus = 0;
2088
2089 //
2090 // Fill in CDB fields.
2091 //
2092
2093 cdb = (PCDB)srb->Cdb;
2094
2095
2096 cdb->READ_CD.TransferBlocks[2] = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
2097 cdb->READ_CD.TransferBlocks[1] = (UCHAR) (rawReadInfo->SectorCount >> 8 );
2098 cdb->READ_CD.TransferBlocks[0] = (UCHAR) (rawReadInfo->SectorCount >> 16);
2099
2100
2101 cdb->READ_CD.StartingLBA[3] = (UCHAR) (startingSector & 0xFF);
2102 cdb->READ_CD.StartingLBA[2] = (UCHAR) ((startingSector >> 8));
2103 cdb->READ_CD.StartingLBA[1] = (UCHAR) ((startingSector >> 16));
2104 cdb->READ_CD.StartingLBA[0] = (UCHAR) ((startingSector >> 24));
2105
2106 //
2107 // Setup cdb depending upon the sector type we want.
2108 //
2109
2110 switch (rawReadInfo->TrackMode) {
2111 case CDDA:
2112
2113 cdb->READ_CD.ExpectedSectorType = CD_DA_SECTOR;
2114 cdb->READ_CD.IncludeUserData = 1;
2115 cdb->READ_CD.HeaderCode = 3;
2116 cdb->READ_CD.IncludeSyncData = 1;
2117 break;
2118
2119 case YellowMode2:
2120
2121 cdb->READ_CD.ExpectedSectorType = YELLOW_MODE2_SECTOR;
2122 cdb->READ_CD.IncludeUserData = 1;
2123 cdb->READ_CD.HeaderCode = 1;
2124 cdb->READ_CD.IncludeSyncData = 1;
2125 break;
2126
2127 case XAForm2:
2128
2129 cdb->READ_CD.ExpectedSectorType = FORM2_MODE2_SECTOR;
2130 cdb->READ_CD.IncludeUserData = 1;
2131 cdb->READ_CD.HeaderCode = 3;
2132 cdb->READ_CD.IncludeSyncData = 1;
2133 break;
2134
2135 default:
2136 Irp->IoStatus.Information = 0;
2137 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
2138 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2139 ExFreePool(senseBuffer);
2140 ExFreePool(srb);
2141 IoFreeIrp(irp2);
2142 IoStartNextPacket(DeviceObject, FALSE);
2143 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp, Irp->IoStatus.Status, __LINE__));
2144 return;
2145 }
2146
2147 cdb->READ_CD.OperationCode = SCSIOP_READ_CD;
2148
2149 nextIrpStack->MajorFunction = IRP_MJ_SCSI;
2150 nextIrpStack->Parameters.Scsi.Srb = srb;
2151
2152 if (!(nextIrpStack->Parameters.Others.Argument1)) {
2153
2154 //
2155 // Only jam this in if it doesn't exist. The completion routines can
2156 // call StartIo directly in the case of retries and resetting it will
2157 // cause infinite loops.
2158 //
2159
2160 nextIrpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES;
2161 }
2162
2163 //
2164 // Set up IoCompletion routine address.
2165 //
2166
2167 IoSetCompletionRoutine(Irp,
2168 CdRomXACompletion,
2169 srb,
2170 TRUE,
2171 TRUE,
2172 TRUE);
2173
2174 IoCallDriver(deviceExtension->PortDeviceObject, Irp);
2175 return;
2176
2177 }
2178
2179 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2180 return;
2181 }
2182
2183 case IOCTL_CDROM_GET_DRIVE_GEOMETRY: {
2184
2185 //
2186 // Issue ReadCapacity to update device extension
2187 // with information for current media.
2188 //
2189
2190 DebugPrint((3,
2191 "CdRomStartIo: Get drive capacity\n"));
2192
2193 //
2194 // setup remaining srb and cdb parameters.
2195 //
2196
2197 srb->SrbFlags = deviceExtension->SrbFlags;
2198 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN);
2199 srb->DataTransferLength = sizeof(READ_CAPACITY_DATA);
2200 srb->CdbLength = 10;
2201 srb->TimeOutValue = deviceExtension->TimeOutValue;
2202
2203 dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned, sizeof(READ_CAPACITY_DATA));
2204 if (!dataBuffer) {
2205 Irp->IoStatus.Information = 0;
2206 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2207 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2208 ExFreePool(senseBuffer);
2209 ExFreePool(srb);
2210 IoFreeIrp(irp2);
2211 IoStartNextPacket(DeviceObject, FALSE);
2212 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp, Irp->IoStatus.Status, __LINE__));
2213 return;
2214
2215 }
2216
2217 irp2->MdlAddress = IoAllocateMdl(dataBuffer,
2218 sizeof(READ_CAPACITY_DATA),
2219 FALSE,
2220 FALSE,
2221 (PIRP) NULL);
2222
2223 if (!irp2->MdlAddress) {
2224 Irp->IoStatus.Information = 0;
2225 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2226 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2227 ExFreePool(senseBuffer);
2228 ExFreePool(srb);
2229 ExFreePool(dataBuffer);
2230 IoFreeIrp(irp2);
2231 IoStartNextPacket(DeviceObject, FALSE);
2232 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp, Irp->IoStatus.Status, __LINE__));
2233 return;
2234 }
2235
2236 //
2237 // Prepare the MDL
2238 //
2239
2240 MmBuildMdlForNonPagedPool(irp2->MdlAddress);
2241
2242 srb->DataBuffer = dataBuffer;
2243 cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
2244
2245 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2246 return;
2247 }
2248
2249 case IOCTL_CDROM_CHECK_VERIFY: {
2250
2251 //
2252 // Since a test unit ready is about to be performed, reset the timer
2253 // value to decrease the opportunities for it to race with this code.
2254 //
2255
2256 cdData->MediaChangeCountDown = MEDIA_CHANGE_DEFAULT_TIME;
2257
2258 //
2259 // Set up the SRB/CDB
2260 //
2261
2262 srb->CdbLength = 6;
2263 cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
2264 srb->TimeOutValue = deviceExtension->TimeOutValue * 2;
2265 srb->SrbFlags = deviceExtension->SrbFlags;
2266 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_DATA_TRANSFER);
2267
2268 DebugPrint((2, "ScsiCdRomStartIo: [%lx] Sending CHECK_VERIFY irp %lx\n", Irp, irp2));
2269 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2270 return;
2271 }
2272
2273 case IOCTL_CDROM_GET_LAST_SESSION:
2274
2275 //
2276 // Set format to return first and last session numbers.
2277 //
2278
2279 cdb->READ_TOC.Format = GET_LAST_SESSION;
2280
2281 //
2282 // Fall through to READ TOC code.
2283 //
2284
2285 case IOCTL_CDROM_READ_TOC: {
2286
2287
2288 if (currentIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_READ_TOC) {
2289
2290 //
2291 // Use MSF addressing if not request for session information.
2292 //
2293
2294 cdb->READ_TOC.Msf = CDB_USE_MSF;
2295 }
2296
2297 //
2298 // Set size of TOC structure.
2299 //
2300
2301 transferByteCount =
2302 currentIrpStack->Parameters.Read.Length >
2303 sizeof(CDROM_TOC) ? sizeof(CDROM_TOC):
2304 currentIrpStack->Parameters.Read.Length;
2305
2306 cdb->READ_TOC.AllocationLength[0] = (UCHAR) (transferByteCount >> 8);
2307 cdb->READ_TOC.AllocationLength[1] = (UCHAR) (transferByteCount & 0xFF);
2308
2309 cdb->READ_TOC.Control = 0;
2310
2311 //
2312 // Start at beginning of disc.
2313 //
2314
2315 cdb->READ_TOC.StartingTrack = 0;
2316
2317 //
2318 // setup remaining srb and cdb parameters.
2319 //
2320
2321 srb->SrbFlags = deviceExtension->SrbFlags;
2322 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN);
2323 srb->DataTransferLength = transferByteCount;
2324 srb->CdbLength = 10;
2325 srb->TimeOutValue = deviceExtension->TimeOutValue;
2326
2327 dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned, transferByteCount);
2328 if (!dataBuffer) {
2329 Irp->IoStatus.Information = 0;
2330 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2331 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2332 ExFreePool(senseBuffer);
2333 ExFreePool(srb);
2334 IoFreeIrp(irp2);
2335 IoStartNextPacket(DeviceObject, FALSE);
2336 return;
2337
2338 }
2339
2340 irp2->MdlAddress = IoAllocateMdl(dataBuffer,
2341 transferByteCount,
2342 FALSE,
2343 FALSE,
2344 (PIRP) NULL);
2345
2346 if (!irp2->MdlAddress) {
2347 Irp->IoStatus.Information = 0;
2348 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2349 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2350 ExFreePool(senseBuffer);
2351 ExFreePool(srb);
2352 ExFreePool(dataBuffer);
2353 IoFreeIrp(irp2);
2354 IoStartNextPacket(DeviceObject, FALSE);
2355 return;
2356 }
2357
2358 //
2359 // Prepare the MDL
2360 //
2361
2362 MmBuildMdlForNonPagedPool(irp2->MdlAddress);
2363
2364 srb->DataBuffer = dataBuffer;
2365 cdb->READ_TOC.OperationCode = SCSIOP_READ_TOC;
2366
2367 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2368 return;
2369
2370 }
2371
2372 case IOCTL_CDROM_PLAY_AUDIO_MSF: {
2373
2374 PCDROM_PLAY_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
2375
2376 //
2377 // Set up the SRB/CDB
2378 //
2379
2380 srb->CdbLength = 10;
2381 cdb->PLAY_AUDIO_MSF.OperationCode = SCSIOP_PLAY_AUDIO_MSF;
2382
2383 cdb->PLAY_AUDIO_MSF.StartingM = inputBuffer->StartingM;
2384 cdb->PLAY_AUDIO_MSF.StartingS = inputBuffer->StartingS;
2385 cdb->PLAY_AUDIO_MSF.StartingF = inputBuffer->StartingF;
2386
2387 cdb->PLAY_AUDIO_MSF.EndingM = inputBuffer->EndingM;
2388 cdb->PLAY_AUDIO_MSF.EndingS = inputBuffer->EndingS;
2389 cdb->PLAY_AUDIO_MSF.EndingF = inputBuffer->EndingF;
2390
2391 srb->TimeOutValue = deviceExtension->TimeOutValue;
2392 srb->SrbFlags = deviceExtension->SrbFlags;
2393 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_DATA_TRANSFER);
2394
2395 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2396 return;
2397
2398 }
2399
2400 case IOCTL_CDROM_READ_Q_CHANNEL: {
2401
2402 PCDROM_SUB_Q_DATA_FORMAT inputBuffer =
2403 Irp->AssociatedIrp.SystemBuffer;
2404
2405 //
2406 // Allocate buffer for subq channel information.
2407 //
2408
2409 dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
2410 sizeof(SUB_Q_CHANNEL_DATA));
2411
2412 if (!dataBuffer) {
2413 Irp->IoStatus.Information = 0;
2414 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2415 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2416 ExFreePool(senseBuffer);
2417 ExFreePool(srb);
2418 IoFreeIrp(irp2);
2419 IoStartNextPacket(DeviceObject, FALSE);
2420 return;
2421
2422 }
2423
2424 irp2->MdlAddress = IoAllocateMdl(dataBuffer,
2425 transferByteCount,
2426 FALSE,
2427 FALSE,
2428 (PIRP) NULL);
2429
2430 if (!irp2->MdlAddress) {
2431 Irp->IoStatus.Information = 0;
2432 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2433 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2434 ExFreePool(senseBuffer);
2435 ExFreePool(srb);
2436 ExFreePool(dataBuffer);
2437 IoFreeIrp(irp2);
2438 IoStartNextPacket(DeviceObject, FALSE);
2439 return;
2440 }
2441
2442 //
2443 // Prepare the MDL
2444 //
2445
2446 MmBuildMdlForNonPagedPool(irp2->MdlAddress);
2447
2448 srb->DataBuffer = dataBuffer;
2449
2450 //
2451 // Always logical unit 0, but only use MSF addressing
2452 // for IOCTL_CDROM_CURRENT_POSITION
2453 //
2454
2455 if (inputBuffer->Format==IOCTL_CDROM_CURRENT_POSITION)
2456 cdb->SUBCHANNEL.Msf = CDB_USE_MSF;
2457
2458 //
2459 // Return subchannel data
2460 //
2461
2462 cdb->SUBCHANNEL.SubQ = CDB_SUBCHANNEL_BLOCK;
2463
2464 //
2465 // Specify format of informatin to return
2466 //
2467
2468 cdb->SUBCHANNEL.Format = inputBuffer->Format;
2469
2470 //
2471 // Specify which track to access (only used by Track ISRC reads)
2472 //
2473
2474 if (inputBuffer->Format==IOCTL_CDROM_TRACK_ISRC) {
2475 cdb->SUBCHANNEL.TrackNumber = inputBuffer->Track;
2476 }
2477
2478 //
2479 // Set size of channel data -- however, this is dependent on
2480 // what information we are requesting (which Format)
2481 //
2482
2483 switch( inputBuffer->Format ) {
2484
2485 case IOCTL_CDROM_CURRENT_POSITION:
2486 transferByteCount = sizeof(SUB_Q_CURRENT_POSITION);
2487 break;
2488
2489 case IOCTL_CDROM_MEDIA_CATALOG:
2490 transferByteCount = sizeof(SUB_Q_MEDIA_CATALOG_NUMBER);
2491 break;
2492
2493 case IOCTL_CDROM_TRACK_ISRC:
2494 transferByteCount = sizeof(SUB_Q_TRACK_ISRC);
2495 break;
2496 }
2497
2498 cdb->SUBCHANNEL.AllocationLength[0] = (UCHAR) (transferByteCount >> 8);
2499 cdb->SUBCHANNEL.AllocationLength[1] = (UCHAR) (transferByteCount & 0xFF);
2500 cdb->SUBCHANNEL.OperationCode = SCSIOP_READ_SUB_CHANNEL;
2501 srb->SrbFlags = deviceExtension->SrbFlags;
2502 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN);
2503 srb->DataTransferLength = transferByteCount;
2504 srb->CdbLength = 10;
2505 srb->TimeOutValue = deviceExtension->TimeOutValue;
2506
2507 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2508 return;
2509
2510 }
2511
2512 case IOCTL_CDROM_PAUSE_AUDIO: {
2513
2514 cdb->PAUSE_RESUME.OperationCode = SCSIOP_PAUSE_RESUME;
2515 cdb->PAUSE_RESUME.Action = CDB_AUDIO_PAUSE;
2516
2517 srb->CdbLength = 10;
2518 srb->TimeOutValue = deviceExtension->TimeOutValue;
2519 srb->SrbFlags = deviceExtension->SrbFlags;
2520 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_DATA_TRANSFER);
2521
2522 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2523 return;
2524 }
2525
2526 case IOCTL_CDROM_RESUME_AUDIO: {
2527
2528 cdb->PAUSE_RESUME.OperationCode = SCSIOP_PAUSE_RESUME;
2529 cdb->PAUSE_RESUME.Action = CDB_AUDIO_RESUME;
2530
2531 srb->CdbLength = 10;
2532 srb->TimeOutValue = deviceExtension->TimeOutValue;
2533 srb->SrbFlags = deviceExtension->SrbFlags;
2534 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_DATA_TRANSFER);
2535
2536 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2537 return;
2538 }
2539
2540 case IOCTL_CDROM_SEEK_AUDIO_MSF: {
2541
2542 PCDROM_SEEK_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
2543 ULONG logicalBlockAddress;
2544
2545 logicalBlockAddress = MSF_TO_LBA(inputBuffer->M, inputBuffer->S, inputBuffer->F);
2546
2547 cdb->SEEK.OperationCode = SCSIOP_SEEK;
2548 cdb->SEEK.LogicalBlockAddress[0] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte3;
2549 cdb->SEEK.LogicalBlockAddress[1] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte2;
2550 cdb->SEEK.LogicalBlockAddress[2] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte1;
2551 cdb->SEEK.LogicalBlockAddress[3] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte0;
2552
2553 srb->CdbLength = 10;
2554 srb->TimeOutValue = deviceExtension->TimeOutValue;
2555 srb->SrbFlags = deviceExtension->SrbFlags;
2556 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_DATA_TRANSFER);
2557
2558 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2559 return;
2560
2561 }
2562
2563 case IOCTL_CDROM_STOP_AUDIO: {
2564
2565 cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
2566 cdb->START_STOP.Immediate = 1;
2567 cdb->START_STOP.Start = 0;
2568 cdb->START_STOP.LoadEject = 0;
2569
2570 srb->CdbLength = 6;
2571 srb->TimeOutValue = deviceExtension->TimeOutValue;
2572
2573 srb->SrbFlags = deviceExtension->SrbFlags;
2574 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_DATA_TRANSFER);
2575
2576 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2577 return;
2578 }
2579
2580 case IOCTL_CDROM_GET_CONTROL: {
2581 //
2582 // Allocate buffer for volume control information.
2583 //
2584
2585 dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
2586 MODE_DATA_SIZE);
2587
2588 if (!dataBuffer) {
2589 Irp->IoStatus.Information = 0;
2590 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2591 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2592 ExFreePool(senseBuffer);
2593 ExFreePool(srb);
2594 IoFreeIrp(irp2);
2595 IoStartNextPacket(DeviceObject, FALSE);
2596 return;
2597
2598 }
2599
2600 irp2->MdlAddress = IoAllocateMdl(dataBuffer,
2601 MODE_DATA_SIZE,
2602 FALSE,
2603 FALSE,
2604 (PIRP) NULL);
2605
2606 if (!irp2->MdlAddress) {
2607 Irp->IoStatus.Information = 0;
2608 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2609 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2610 ExFreePool(senseBuffer);
2611 ExFreePool(srb);
2612 ExFreePool(dataBuffer);
2613 IoFreeIrp(irp2);
2614 IoStartNextPacket(DeviceObject, FALSE);
2615 return;
2616 }
2617
2618 //
2619 // Prepare the MDL
2620 //
2621
2622 MmBuildMdlForNonPagedPool(irp2->MdlAddress);
2623 srb->DataBuffer = dataBuffer;
2624
2625 RtlZeroMemory(dataBuffer, MODE_DATA_SIZE);
2626
2627 //
2628 // Setup for either 6 or 10 byte CDBs.
2629 //
2630
2631 if (use6Byte) {
2632
2633 cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
2634 cdb->MODE_SENSE.PageCode = CDROM_AUDIO_CONTROL_PAGE;
2635 cdb->MODE_SENSE.AllocationLength = MODE_DATA_SIZE;
2636
2637 //
2638 // Disable block descriptors.
2639 //
2640
2641 cdb->MODE_SENSE.Dbd = TRUE;
2642
2643 srb->CdbLength = 6;
2644 } else {
2645
2646 cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
2647 cdb->MODE_SENSE10.PageCode = CDROM_AUDIO_CONTROL_PAGE;
2648 cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(MODE_DATA_SIZE >> 8);
2649 cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(MODE_DATA_SIZE & 0xFF);
2650
2651 //
2652 // Disable block descriptors.
2653 //
2654
2655 cdb->MODE_SENSE10.Dbd = TRUE;
2656
2657 srb->CdbLength = 10;
2658 }
2659
2660 srb->TimeOutValue = deviceExtension->TimeOutValue;
2661 srb->DataTransferLength = MODE_DATA_SIZE;
2662 srb->SrbFlags = deviceExtension->SrbFlags;
2663 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN);
2664
2665 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2666 return;
2667
2668 }
2669
2670 case IOCTL_CDROM_GET_VOLUME:
2671 case IOCTL_CDROM_SET_VOLUME: {
2672
2673 dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
2674 MODE_DATA_SIZE);
2675
2676 if (!dataBuffer) {
2677 Irp->IoStatus.Information = 0;
2678 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2679 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2680 ExFreePool(senseBuffer);
2681 ExFreePool(srb);
2682 IoFreeIrp(irp2);
2683 IoStartNextPacket(DeviceObject, FALSE);
2684 return;
2685 }
2686
2687 irp2->MdlAddress = IoAllocateMdl(dataBuffer,
2688 MODE_DATA_SIZE,
2689 FALSE,
2690 FALSE,
2691 (PIRP) NULL);
2692
2693 if (!irp2->MdlAddress) {
2694 Irp->IoStatus.Information = 0;
2695 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2696 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2697 ExFreePool(senseBuffer);
2698 ExFreePool(srb);
2699 ExFreePool(dataBuffer);
2700 IoFreeIrp(irp2);
2701 IoStartNextPacket(DeviceObject, FALSE);
2702 return;
2703 }
2704
2705 //
2706 // Prepare the MDL
2707 //
2708
2709 MmBuildMdlForNonPagedPool(irp2->MdlAddress);
2710 srb->DataBuffer = dataBuffer;
2711
2712 RtlZeroMemory(dataBuffer, MODE_DATA_SIZE);
2713
2714
2715 if (use6Byte) {
2716 cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
2717 cdb->MODE_SENSE.PageCode = CDROM_AUDIO_CONTROL_PAGE;
2718 cdb->MODE_SENSE.AllocationLength = MODE_DATA_SIZE;
2719
2720 srb->CdbLength = 6;
2721
2722 } else {
2723
2724 cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
2725 cdb->MODE_SENSE10.PageCode = CDROM_AUDIO_CONTROL_PAGE;
2726 cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(MODE_DATA_SIZE >> 8);
2727 cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(MODE_DATA_SIZE & 0xFF);
2728
2729 srb->CdbLength = 10;
2730 }
2731
2732 srb->TimeOutValue = deviceExtension->TimeOutValue;
2733 srb->DataTransferLength = MODE_DATA_SIZE;
2734 srb->SrbFlags = deviceExtension->SrbFlags;
2735 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN);
2736
2737 if (currentIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_SET_VOLUME) {
2738
2739 //
2740 // Setup a different completion routine as the mode sense data is needed in order
2741 // to send the mode select.
2742 //
2743
2744 IoSetCompletionRoutine(irp2,
2745 CdRomSetVolumeIntermediateCompletion,
2746 srb,
2747 TRUE,
2748 TRUE,
2749 TRUE);
2750
2751 }
2752
2753 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2754 return;
2755
2756 }
2757
2758 default:
2759
2760 //
2761 // Just complete the request - CdRomClassIoctlCompletion will take
2762 // care of it for us
2763 //
2764
2765 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2766 return;
2767
2768 } // end switch()
2769 }
2770
2771 //
2772 // If a read or an unhandled IRP_MJ_XX, end up here. The unhandled IRP_MJ's
2773 // are expected and composed of AutoRun Irps, at present.
2774 //
2775
2776 IoCallDriver(deviceExtension->PortDeviceObject, Irp);
2777 return;
2778 }
2779
2780
2781 NTSTATUS
2782 NTAPI
2783 ScsiCdRomReadVerification(
2784 IN PDEVICE_OBJECT DeviceObject,
2785 IN PIRP Irp
2786 )
2787
2788 /*++
2789
2790 Routine Description:
2791
2792 This is the entry called by the I/O system for read requests.
2793 It builds the SRB and sends it to the port driver.
2794
2795 Arguments:
2796
2797 DeviceObject - the system object for the device.
2798 Irp - IRP involved.
2799
2800 Return Value:
2801
2802 NT Status
2803
2804 --*/
2805
2806 {
2807 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
2808 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
2809 ULONG transferByteCount = currentIrpStack->Parameters.Read.Length;
2810 LARGE_INTEGER startingOffset = currentIrpStack->Parameters.Read.ByteOffset;
2811
2812 //
2813 // If the cd is playing music then reject this request.
2814 //
2815
2816 if (PLAY_ACTIVE(deviceExtension)) {
2817 Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
2818 return STATUS_DEVICE_BUSY;
2819 }
2820
2821 //
2822 // Verify parameters of this request.
2823 // Check that ending sector is on disc and
2824 // that number of bytes to transfer is a multiple of
2825 // the sector size.
2826 //
2827
2828 startingOffset.QuadPart = currentIrpStack->Parameters.Read.ByteOffset.QuadPart +
2829 transferByteCount;
2830
2831 if (!deviceExtension->DiskGeometry->BytesPerSector) {
2832 deviceExtension->DiskGeometry->BytesPerSector = 2048;
2833 }
2834
2835 if ((startingOffset.QuadPart > deviceExtension->PartitionLength.QuadPart) ||
2836 (transferByteCount & (deviceExtension->DiskGeometry->BytesPerSector - 1))) {
2837
2838 DebugPrint((1,"ScsiCdRomRead: Invalid I/O parameters\n"));
2839 DebugPrint((1, "\toffset %x:%x, Length %x:%x\n",
2840 startingOffset.u.HighPart,
2841 startingOffset.u.LowPart,
2842 deviceExtension->PartitionLength.u.HighPart,
2843 deviceExtension->PartitionLength.u.LowPart));
2844 DebugPrint((1, "\tbps %x\n", deviceExtension->DiskGeometry->BytesPerSector));
2845
2846 //
2847 // Fail request with status of invalid parameters.
2848 //
2849
2850 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
2851
2852 return STATUS_INVALID_PARAMETER;
2853 }
2854
2855
2856 return STATUS_SUCCESS;
2857
2858 } // end ScsiCdRomReadVerification()
2859
2860
2861 NTSTATUS
2862 NTAPI
2863 CdRomDeviceControlCompletion(
2864 IN PDEVICE_OBJECT DeviceObject,
2865 IN PIRP Irp,
2866 IN PVOID Context
2867 )
2868 {
2869 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
2870 PDEVICE_EXTENSION physicalExtension = deviceExtension->PhysicalDevice->DeviceExtension;
2871 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
2872 PCDROM_DATA cdData = (PCDROM_DATA)(deviceExtension + 1);
2873 BOOLEAN use6Byte = cdData->XAFlags & XA_USE_6_BYTE;
2874 PIO_STACK_LOCATION realIrpStack;
2875 PIO_STACK_LOCATION realIrpNextStack;
2876 PSCSI_REQUEST_BLOCK srb = Context;
2877 PIRP realIrp = NULL;
2878 NTSTATUS status;
2879 BOOLEAN retry;
2880
2881 //
2882 // Extract the 'real' irp from the irpstack.
2883 //
2884
2885 realIrp = (PIRP) irpStack->Parameters.Others.Argument2;
2886 realIrpStack = IoGetCurrentIrpStackLocation(realIrp);
2887 realIrpNextStack = IoGetNextIrpStackLocation(realIrp);
2888
2889 //
2890 // Check SRB status for success of completing request.
2891 //
2892
2893 if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
2894
2895 DebugPrint((2,
2896 "CdRomDeviceControlCompletion: Irp %lx, Srb %lx Real Irp %lx Status %lx\n",
2897 Irp,
2898 srb,
2899 realIrp,
2900 srb->SrbStatus));
2901
2902 //
2903 // Release the queue if it is frozen.
2904 //
2905
2906 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
2907 DebugPrint((2, "CdRomDeviceControlCompletion: Releasing Queue\n"));
2908 ScsiClassReleaseQueue(DeviceObject);
2909 }
2910
2911
2912 retry = ScsiClassInterpretSenseInfo(DeviceObject,
2913 srb,
2914 irpStack->MajorFunction,
2915 irpStack->Parameters.DeviceIoControl.IoControlCode,
2916 MAXIMUM_RETRIES - ((ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1),
2917 &status);
2918
2919 DebugPrint((2, "CdRomDeviceControlCompletion: IRP will %sbe retried\n",
2920 (retry ? "" : "not ")));
2921
2922 //
2923 // Some of the Device Controls need special cases on non-Success status's.
2924 //
2925
2926 if (realIrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) {
2927 if ((realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_GET_LAST_SESSION) ||
2928 (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_READ_TOC) ||
2929 (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_GET_CONTROL) ||
2930 (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_GET_VOLUME)) {
2931
2932 if (status == STATUS_DATA_OVERRUN) {
2933 status = STATUS_SUCCESS;
2934 retry = FALSE;
2935 }
2936 }
2937
2938 if (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_READ_Q_CHANNEL) {
2939 PLAY_ACTIVE(deviceExtension) = FALSE;
2940 }
2941 }
2942
2943 //
2944 // If the status is verified required and the this request
2945 // should bypass verify required then retry the request.
2946 //
2947
2948 if (realIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME &&
2949 status == STATUS_VERIFY_REQUIRED) {
2950
2951 if (((realIrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) ||
2952 (realIrpStack->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL)) &&
2953 (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_CHECK_VERIFY)) {
2954
2955 //
2956 // Update the geometry information, as the media could have changed.
2957 // The completion routine for this will complete the real irp and start
2958 // the next packet.
2959 //
2960
2961 status = CdRomUpdateCapacity(deviceExtension,realIrp, NULL);
2962 DebugPrint((2, "CdRomDeviceControlCompletion: [%lx] CdRomUpdateCapacity completed with status %lx\n", realIrp, status));
2963 ASSERT(status == STATUS_PENDING);
2964
2965 return STATUS_MORE_PROCESSING_REQUIRED;
2966
2967 } else {
2968
2969 status = STATUS_IO_DEVICE_ERROR;
2970 retry = TRUE;
2971 }
2972
2973 }
2974
2975 if (retry && (realIrpNextStack->Parameters.Others.Argument1 = (PVOID)((ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1-1))) {
2976
2977
2978 if (((ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1)) {
2979
2980 //
2981 // Retry request.
2982 //
2983
2984 DebugPrint((1, "Retry request %lx - Calling StartIo\n", Irp));
2985
2986
2987 ExFreePool(srb->SenseInfoBuffer);
2988 if (srb->DataBuffer) {
2989 ExFreePool(srb->DataBuffer);
2990 }
2991 ExFreePool(srb);
2992 if (Irp->MdlAddress) {
2993 IoFreeMdl(Irp->MdlAddress);
2994 }
2995
2996 IoFreeIrp(Irp);
2997
2998 //
2999 // Call StartIo directly since IoStartNextPacket hasn't been called,
3000 // the serialisation is still intact.
3001 //
3002
3003 ScsiCdRomStartIo(DeviceObject, realIrp);
3004 return STATUS_MORE_PROCESSING_REQUIRED;
3005
3006 }
3007
3008 //
3009 // Exhausted retries. Fall through and complete the request with the appropriate status.
3010 //
3011
3012 }
3013 } else {
3014
3015 //
3016 // Set status for successful request.
3017 //
3018
3019 status = STATUS_SUCCESS;
3020 }
3021
3022 if (NT_SUCCESS(status)) {
3023
3024 switch (realIrpStack->Parameters.DeviceIoControl.IoControlCode) {
3025
3026 case IOCTL_CDROM_GET_DRIVE_GEOMETRY: {
3027
3028 PREAD_CAPACITY_DATA readCapacityBuffer = srb->DataBuffer;
3029 ULONG lastSector;
3030 ULONG bps;
3031 ULONG lastBit;
3032 ULONG tmp;
3033
3034 //
3035 // Swizzle bytes from Read Capacity and translate into
3036 // the necessary geometry information in the device extension.
3037 //
3038
3039 tmp = readCapacityBuffer->BytesPerBlock;
3040 ((PFOUR_BYTE)&bps)->Byte0 = ((PFOUR_BYTE)&tmp)->Byte3;
3041 ((PFOUR_BYTE)&bps)->Byte1 = ((PFOUR_BYTE)&tmp)->Byte2;
3042 ((PFOUR_BYTE)&bps)->Byte2 = ((PFOUR_BYTE)&tmp)->Byte1;
3043 ((PFOUR_BYTE)&bps)->Byte3 = ((PFOUR_BYTE)&tmp)->Byte0;
3044
3045 //
3046 // Insure that bps is a power of 2.
3047 // This corrects a problem with the HP 4020i CDR where it
3048 // returns an incorrect number for bytes per sector.
3049 //
3050
3051 if (!bps) {
3052 bps = 2048;
3053 } else {
3054 lastBit = (ULONG) -1;
3055 while (bps) {
3056 lastBit++;
3057 bps = bps >> 1;
3058 }
3059
3060 bps = 1 << lastBit;
3061 }
3062 deviceExtension->DiskGeometry->BytesPerSector = bps;
3063
3064 DebugPrint((2,
3065 "CdRomDeviceControlCompletion: Calculated bps %#x\n",
3066 deviceExtension->DiskGeometry->BytesPerSector));
3067
3068 //
3069 // Copy last sector in reverse byte order.
3070 //
3071
3072 tmp = readCapacityBuffer->LogicalBlockAddress;
3073 ((PFOUR_BYTE)&lastSector)->Byte0 = ((PFOUR_BYTE)&tmp)->Byte3;
3074 ((PFOUR_BYTE)&lastSector)->Byte1 = ((PFOUR_BYTE)&tmp)->Byte2;
3075 ((PFOUR_BYTE)&lastSector)->Byte2 = ((PFOUR_BYTE)&tmp)->Byte1;
3076 ((PFOUR_BYTE)&lastSector)->Byte3 = ((PFOUR_BYTE)&tmp)->Byte0;
3077
3078 //
3079 // Calculate sector to byte shift.
3080 //
3081
3082 WHICH_BIT(bps, deviceExtension->SectorShift);
3083
3084 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Sector size is %d\n",
3085 deviceExtension->DiskGeometry->BytesPerSector));
3086
3087 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Number of Sectors is %d\n",
3088 lastSector + 1));
3089
3090 //
3091 // Calculate media capacity in bytes.
3092 //
3093
3094 deviceExtension->PartitionLength.QuadPart = (LONGLONG)(lastSector + 1);
3095
3096 //
3097 // Calculate number of cylinders.
3098 //
3099
3100 deviceExtension->DiskGeometry->Cylinders.QuadPart = (LONGLONG)((lastSector + 1)/(32 * 64));
3101
3102 deviceExtension->PartitionLength.QuadPart =
3103 (deviceExtension->PartitionLength.QuadPart << deviceExtension->SectorShift);
3104
3105 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
3106
3107 //
3108 // This device supports removable media.
3109 //
3110
3111 deviceExtension->DiskGeometry->MediaType = RemovableMedia;
3112
3113 } else {
3114
3115 //
3116 // Assume media type is fixed disk.
3117 //
3118
3119 deviceExtension->DiskGeometry->MediaType = FixedMedia;
3120 }
3121
3122 //
3123 // Assume sectors per track are 32;
3124 //
3125
3126 deviceExtension->DiskGeometry->SectorsPerTrack = 32;
3127
3128 //
3129 // Assume tracks per cylinder (number of heads) is 64.
3130 //
3131
3132 deviceExtension->DiskGeometry->TracksPerCylinder = 64;
3133
3134 //
3135 // Copy the device extension's geometry info into the user buffer.
3136 //
3137
3138 RtlMoveMemory(realIrp->AssociatedIrp.SystemBuffer,
3139 deviceExtension->DiskGeometry,
3140 sizeof(DISK_GEOMETRY));
3141
3142 //
3143 // update information field.
3144 //
3145
3146 realIrp->IoStatus.Information = sizeof(DISK_GEOMETRY);
3147 break;
3148 }
3149
3150 case IOCTL_CDROM_CHECK_VERIFY:
3151
3152 if((realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_CHECK_VERIFY) &&
3153 (realIrpStack->Parameters.DeviceIoControl.OutputBufferLength)) {
3154
3155 *((PULONG)realIrp->AssociatedIrp.SystemBuffer) =
3156 physicalExtension->MediaChangeCount;
3157 realIrp->IoStatus.Information = sizeof(ULONG);
3158 } else {
3159 realIrp->IoStatus.Information = 0;
3160 }
3161
3162 DebugPrint((2, "CdRomDeviceControlCompletion: [%lx] completing CHECK_VERIFY buddy irp %lx\n", realIrp, Irp));
3163 break;
3164
3165 case IOCTL_CDROM_GET_LAST_SESSION:
3166 case IOCTL_CDROM_READ_TOC: {
3167
3168 PCDROM_TOC toc = srb->DataBuffer;
3169
3170 //
3171 // Copy the device extension's geometry info into the user buffer.
3172 //
3173
3174 RtlMoveMemory(realIrp->AssociatedIrp.SystemBuffer,
3175 toc,
3176 srb->DataTransferLength);
3177
3178 //
3179 // update information field.
3180 //
3181
3182 realIrp->IoStatus.Information = srb->DataTransferLength;
3183 break;
3184 }
3185
3186 case IOCTL_CDROM_PLAY_AUDIO_MSF:
3187
3188 PLAY_ACTIVE(deviceExtension) = TRUE;
3189
3190 break;
3191
3192 case IOCTL_CDROM_READ_Q_CHANNEL: {
3193
3194 PSUB_Q_CHANNEL_DATA userChannelData = realIrp->AssociatedIrp.SystemBuffer;
3195 #if DBG
3196 PCDROM_SUB_Q_DATA_FORMAT inputBuffer = realIrp->AssociatedIrp.SystemBuffer;
3197 #endif
3198 PSUB_Q_CHANNEL_DATA subQPtr = srb->DataBuffer;
3199
3200 #if DBG
3201 switch( inputBuffer->Format ) {
3202
3203 case IOCTL_CDROM_CURRENT_POSITION:
3204 DebugPrint((2,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr->CurrentPosition.Header.AudioStatus ));
3205 DebugPrint((2,"CdRomDeviceControlCompletion: ADR = 0x%x\n", subQPtr->CurrentPosition.ADR ));
3206 DebugPrint((2,"CdRomDeviceControlCompletion: Control = 0x%x\n", subQPtr->CurrentPosition.Control ));
3207 DebugPrint((2,"CdRomDeviceControlCompletion: Track = %u\n", subQPtr->CurrentPosition.TrackNumber ));
3208 DebugPrint((2,"CdRomDeviceControlCompletion: Index = %u\n", subQPtr->CurrentPosition.IndexNumber ));
3209 DebugPrint((2,"CdRomDeviceControlCompletion: Absolute Address = %x\n", *((PULONG)subQPtr->CurrentPosition.AbsoluteAddress) ));
3210 DebugPrint((2,"CdRomDeviceControlCompletion: Relative Address = %x\n", *((PULONG)subQPtr->CurrentPosition.TrackRelativeAddress) ));
3211 break;
3212
3213 case IOCTL_CDROM_MEDIA_CATALOG:
3214 DebugPrint((2,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr->MediaCatalog.Header.AudioStatus ));
3215 DebugPrint((2,"CdRomDeviceControlCompletion: Mcval is %u\n", subQPtr->MediaCatalog.Mcval ));
3216 break;
3217
3218 case IOCTL_CDROM_TRACK_ISRC:
3219 DebugPrint((2,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr->TrackIsrc.Header.AudioStatus ));
3220 DebugPrint((2,"CdRomDeviceControlCompletion: Tcval is %u\n", subQPtr->TrackIsrc.Tcval ));
3221 break;
3222
3223 }
3224 #endif
3225
3226 //
3227 // Update the play active status.
3228 //
3229
3230 if (subQPtr->CurrentPosition.Header.AudioStatus == AUDIO_STATUS_IN_PROGRESS) {
3231
3232 PLAY_ACTIVE(deviceExtension) = TRUE;
3233
3234 } else {
3235
3236 PLAY_ACTIVE(deviceExtension) = FALSE;
3237
3238 }
3239
3240 //
3241 // Check if output buffer is large enough to contain
3242 // the data.
3243 //
3244
3245 if (realIrpStack->Parameters.DeviceIoControl.OutputBufferLength <
3246 srb->DataTransferLength) {
3247
3248 srb->DataTransferLength =
3249 realIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
3250 }
3251
3252 //
3253 // Copy our buffer into users.
3254 //
3255
3256 RtlMoveMemory(userChannelData,
3257 subQPtr,
3258 srb->DataTransferLength);
3259
3260 realIrp->IoStatus.Information = srb->DataTransferLength;
3261 break;
3262 }
3263
3264 case IOCTL_CDROM_PAUSE_AUDIO:
3265
3266 PLAY_ACTIVE(deviceExtension) = FALSE;
3267 realIrp->IoStatus.Information = 0;
3268 break;
3269
3270 case IOCTL_CDROM_RESUME_AUDIO:
3271
3272 realIrp->IoStatus.Information = 0;
3273 break;
3274
3275 case IOCTL_CDROM_SEEK_AUDIO_MSF:
3276
3277 realIrp->IoStatus.Information = 0;
3278 break;
3279
3280 case IOCTL_CDROM_STOP_AUDIO:
3281
3282 PLAY_ACTIVE(deviceExtension) = FALSE;
3283
3284 realIrp->IoStatus.Information = 0;
3285 break;
3286
3287 case IOCTL_CDROM_GET_CONTROL: {
3288
3289 PCDROM_AUDIO_CONTROL audioControl = srb->DataBuffer;
3290 PAUDIO_OUTPUT audioOutput;
3291 ULONG bytesTransferred;
3292
3293 audioOutput = ScsiClassFindModePage((PCHAR)audioControl,
3294 srb->DataTransferLength,
3295 CDROM_AUDIO_CONTROL_PAGE,
3296 use6Byte);
3297 //
3298 // Verify the page is as big as expected.
3299 //
3300
3301 bytesTransferred = (PCHAR) audioOutput - (PCHAR) audioControl +
3302 sizeof(AUDIO_OUTPUT);
3303
3304 if (audioOutput != NULL &&
3305 srb->DataTransferLength >= bytesTransferred) {
3306
3307 audioControl->LbaFormat = audioOutput->LbaFormat;
3308
3309 audioControl->LogicalBlocksPerSecond =
3310 (audioOutput->LogicalBlocksPerSecond[0] << (UCHAR)8) |
3311 audioOutput->LogicalBlocksPerSecond[1];
3312
3313 realIrp->IoStatus.Information = sizeof(CDROM_AUDIO_CONTROL);
3314
3315 } else {
3316 realIrp->IoStatus.Information = 0;
3317 status = STATUS_INVALID_DEVICE_REQUEST;
3318 }
3319 break;
3320 }
3321
3322 case IOCTL_CDROM_GET_VOLUME: {
3323
3324 PAUDIO_OUTPUT audioOutput;
3325 PVOLUME_CONTROL volumeControl = srb->DataBuffer;
3326 ULONG i,bytesTransferred;
3327
3328 audioOutput = ScsiClassFindModePage((PCHAR)volumeControl,
3329 srb->DataTransferLength,
3330 CDROM_AUDIO_CONTROL_PAGE,
3331 use6Byte);
3332
3333 //
3334 // Verify the page is as big as expected.
3335 //
3336
3337 bytesTransferred = (PCHAR) audioOutput - (PCHAR) volumeControl +
3338 sizeof(AUDIO_OUTPUT);
3339
3340 if (audioOutput != NULL &&
3341 srb->DataTransferLength >= bytesTransferred) {
3342
3343 for (i=0; i<4; i++) {
3344 volumeControl->PortVolume[i] =
3345 audioOutput->PortOutput[i].Volume;
3346 }
3347
3348 //
3349 // Set bytes transferred in IRP.
3350 //
3351
3352 realIrp->IoStatus.Information = sizeof(VOLUME_CONTROL);
3353
3354 } else {
3355 realIrp->IoStatus.Information = 0;
3356 status = STATUS_INVALID_DEVICE_REQUEST;
3357 }
3358
3359 break;
3360 }
3361
3362 case IOCTL_CDROM_SET_VOLUME:
3363
3364 realIrp->IoStatus.Information = sizeof(VOLUME_CONTROL);
3365 break;
3366
3367 default:
3368
3369 ASSERT(FALSE);
3370 realIrp->IoStatus.Information = 0;
3371 status = STATUS_INVALID_DEVICE_REQUEST;
3372
3373 } // end switch()
3374 }
3375
3376 //
3377 // Deallocate srb and sense buffer.
3378 //
3379
3380 if (srb) {
3381 if (srb->DataBuffer) {
3382 ExFreePool(srb->DataBuffer);
3383 }
3384 if (srb->SenseInfoBuffer) {
3385 ExFreePool(srb->SenseInfoBuffer);
3386 }
3387 ExFreePool(srb);
3388 }
3389
3390 if (realIrp->PendingReturned) {
3391 IoMarkIrpPending(realIrp);
3392 }
3393
3394 if (Irp->MdlAddress) {
3395 IoFreeMdl(Irp->MdlAddress);
3396 }
3397
3398 IoFreeIrp(Irp);
3399
3400 //
3401 // Set status in completing IRP.
3402 //
3403
3404 realIrp->IoStatus.Status = status;
3405
3406 //
3407 // Set the hard error if necessary.
3408 //
3409
3410 if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
3411
3412 //
3413 // Store DeviceObject for filesystem, and clear
3414 // in IoStatus.Information field.
3415 //
3416
3417 DebugPrint((1, "CdRomDeviceCompletion - Setting Hard Error on realIrp %lx\n",
3418 realIrp));
3419 IoSetHardErrorOrVerifyDevice(realIrp, DeviceObject);
3420 realIrp->IoStatus.Information = 0;
3421 }
3422
3423 IoCompleteRequest(realIrp, IO_DISK_INCREMENT);
3424
3425 IoStartNextPacket(DeviceObject, FALSE);
3426
3427 return STATUS_MORE_PROCESSING_REQUIRED;
3428 }
3429
3430 NTSTATUS
3431 NTAPI
3432 CdRomSetVolumeIntermediateCompletion(
3433 IN PDEVICE_OBJECT DeviceObject,
3434 IN PIRP Irp,
3435 IN PVOID Context
3436 )
3437 {
3438 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
3439 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
3440 PCDROM_DATA cdData = (PCDROM_DATA)(deviceExtension + 1);
3441 BOOLEAN use6Byte = cdData->XAFlags & XA_USE_6_BYTE;
3442 PIO_STACK_LOCATION realIrpStack;
3443 PIO_STACK_LOCATION realIrpNextStack;
3444 PSCSI_REQUEST_BLOCK srb = Context;
3445 PIRP realIrp = NULL;
3446 NTSTATUS status;
3447 BOOLEAN retry;
3448
3449 //
3450 // Extract the 'real' irp from the irpstack.
3451 //
3452
3453 realIrp = (PIRP) irpStack->Parameters.Others.Argument2;
3454 realIrpStack = IoGetCurrentIrpStackLocation(realIrp);
3455 realIrpNextStack = IoGetNextIrpStackLocation(realIrp);
3456
3457 //
3458 // Check SRB status for success of completing request.
3459 //
3460
3461 if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
3462
3463 DebugPrint((2,
3464 "CdRomSetVolumeIntermediateCompletion: Irp %lx, Srb %lx Real Irp\n",
3465 Irp,
3466 srb,
3467 realIrp));
3468
3469 //
3470 // Release the queue if it is frozen.
3471 //
3472
3473 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
3474 ScsiClassReleaseQueue(DeviceObject);
3475 }
3476
3477
3478 retry = ScsiClassInterpretSenseInfo(DeviceObject,
3479 srb,
3480 irpStack->MajorFunction,
3481 irpStack->Parameters.DeviceIoControl.IoControlCode,
3482 MAXIMUM_RETRIES - ((ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1),
3483 &status);
3484
3485 if (status == STATUS_DATA_OVERRUN) {
3486 status = STATUS_SUCCESS;
3487 retry = FALSE;
3488 }
3489
3490 //
3491 // If the status is verified required and the this request
3492 // should bypass verify required then retry the request.
3493 //
3494
3495 if (realIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME &&
3496 status == STATUS_VERIFY_REQUIRED) {
3497
3498 status = STATUS_IO_DEVICE_ERROR;
3499 retry = TRUE;
3500 }
3501
3502 if (retry && (realIrpNextStack->Parameters.Others.Argument1 = (PVOID)((ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1-1))) {
3503
3504 if (((ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1)) {
3505
3506 //
3507 // Retry request.
3508 //
3509
3510 DebugPrint((1, "Retry request %lx - Calling StartIo\n", Irp));
3511
3512
3513 ExFreePool(srb->SenseInfoBuffer);
3514 ExFreePool(srb->DataBuffer);
3515 ExFreePool(srb);
3516 if (Irp->MdlAddress) {
3517 IoFreeMdl(Irp->MdlAddress);
3518 }
3519
3520 IoFreeIrp(Irp);
3521
3522 //
3523 // Call StartIo directly since IoStartNextPacket hasn't been called,
3524 // the serialisation is still intact.
3525 //
3526 ScsiCdRomStartIo(DeviceObject, realIrp);
3527 return STATUS_MORE_PROCESSING_REQUIRED;
3528
3529 }
3530
3531 //
3532 // Exhausted retries. Fall through and complete the request with the appropriate status.
3533 //
3534
3535 }
3536 } else {
3537
3538 //
3539 // Set status for successful request.
3540 //
3541
3542 status = STATUS_SUCCESS;
3543 }
3544
3545 if (NT_SUCCESS(status)) {
3546
3547 PAUDIO_OUTPUT audioInput = NULL;
3548 PAUDIO_OUTPUT audioOutput;
3549 PVOLUME_CONTROL volumeControl = realIrp->AssociatedIrp.SystemBuffer;
3550 ULONG i,bytesTransferred,headerLength;
3551 PVOID dataBuffer;
3552 PCDB cdb;
3553
3554 audioInput = ScsiClassFindModePage((PCHAR)srb->DataBuffer,
3555 srb->DataTransferLength,
3556 CDROM_AUDIO_CONTROL_PAGE,
3557 use6Byte);
3558
3559 //
3560 // Check to make sure the mode sense data is valid before we go on
3561 //
3562
3563 if(audioInput == NULL) {
3564
3565 DebugPrint((1, "Mode Sense Page %d not found\n",
3566 CDROM_AUDIO_CONTROL_PAGE));
3567
3568 realIrp->IoStatus.Information = 0;
3569 realIrp->IoStatus.Status = STATUS_IO_DEVICE_ERROR;
3570 IoCompleteRequest(realIrp, IO_DISK_INCREMENT);
3571 ExFreePool(srb->SenseInfoBuffer);
3572 ExFreePool(srb);
3573 IoFreeMdl(Irp->MdlAddress);
3574 IoFreeIrp(Irp);
3575 return STATUS_MORE_PROCESSING_REQUIRED;
3576 }
3577
3578 if (use6Byte) {
3579 headerLength = sizeof(MODE_PARAMETER_HEADER);
3580 } else {
3581 headerLength = sizeof(MODE_PARAMETER_HEADER10);
3582 }
3583
3584 bytesTransferred = sizeof(AUDIO_OUTPUT) + headerLength;
3585
3586 //
3587 // Allocate a new buffer for the mode select.
3588 //
3589
3590 dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned, bytesTransferred);
3591
3592 if (!dataBuffer) {
3593 realIrp->IoStatus.Information = 0;
3594 realIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
3595 IoCompleteRequest(realIrp, IO_DISK_INCREMENT);
3596 ExFreePool(srb->SenseInfoBuffer);
3597 ExFreePool(srb);
3598 IoFreeMdl(Irp->MdlAddress);
3599 IoFreeIrp(Irp);
3600 return STATUS_MORE_PROCESSING_REQUIRED;
3601 }
3602
3603 RtlZeroMemory(dataBuffer, bytesTransferred);
3604
3605 //
3606 // Rebuild the data buffer to include the user requested values.
3607 //
3608
3609 audioOutput = (PAUDIO_OUTPUT) ((PCHAR) dataBuffer + headerLength);
3610
3611 for (i=0; i<4; i++) {
3612 audioOutput->PortOutput[i].Volume =
3613 volumeControl->PortVolume[i];
3614 audioOutput->PortOutput[i].ChannelSelection =
3615 audioInput->PortOutput[i].ChannelSelection;
3616 }
3617
3618 audioOutput->CodePage = CDROM_AUDIO_CONTROL_PAGE;
3619 audioOutput->ParameterLength = sizeof(AUDIO_OUTPUT) - 2;
3620 audioOutput->Immediate = MODE_SELECT_IMMEDIATE;
3621
3622 //
3623 // Free the old data buffer, mdl.
3624 //
3625
3626 ExFreePool(srb->DataBuffer);
3627 IoFreeMdl(Irp->MdlAddress);
3628
3629 //
3630 // rebuild the srb.
3631 //
3632
3633 cdb = (PCDB)srb->Cdb;
3634 RtlZeroMemory(cdb, CDB12GENERIC_LENGTH);
3635
3636 srb->SrbStatus = srb->ScsiStatus = 0;
3637 srb->SrbFlags = deviceExtension->SrbFlags;
3638 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_OUT);
3639 srb->DataTransferLength = bytesTransferred;
3640
3641 if (use6Byte) {
3642
3643 cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
3644 cdb->MODE_SELECT.ParameterListLength = (UCHAR) bytesTransferred;
3645 cdb->MODE_SELECT.PFBit = 1;
3646 srb->CdbLength = 6;
3647 } else {
3648
3649 cdb->MODE_SELECT10.OperationCode = SCSIOP_MODE_SELECT10;
3650 cdb->MODE_SELECT10.ParameterListLength[0] = (UCHAR) (bytesTransferred >> 8);
3651 cdb->MODE_SELECT10.ParameterListLength[1] = (UCHAR) (bytesTransferred & 0xFF);
3652 cdb->MODE_SELECT10.PFBit = 1;
3653 srb->CdbLength = 10;
3654 }
3655
3656 //
3657 // Prepare the MDL
3658 //
3659
3660 Irp->MdlAddress = IoAllocateMdl(dataBuffer,
3661 bytesTransferred,
3662 FALSE,
3663 FALSE,
3664 (PIRP) NULL);
3665
3666 if (!Irp->MdlAddress) {
3667 realIrp->IoStatus.Information = 0;
3668 realIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
3669 IoCompleteRequest(realIrp, IO_DISK_INCREMENT);
3670 ExFreePool(srb->SenseInfoBuffer);
3671 ExFreePool(srb);
3672 ExFreePool(dataBuffer);
3673 IoFreeIrp(Irp);
3674 return STATUS_MORE_PROCESSING_REQUIRED;
3675
3676 }
3677
3678 MmBuildMdlForNonPagedPool(Irp->MdlAddress);
3679 srb->DataBuffer = dataBuffer;
3680
3681 irpStack = IoGetNextIrpStackLocation(Irp);
3682 irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
3683 irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
3684 irpStack->Parameters.Scsi.Srb = srb;
3685
3686 //
3687 // reset the irp completion.
3688 //
3689
3690 IoSetCompletionRoutine(Irp,
3691 CdRomDeviceControlCompletion,
3692 srb,
3693 TRUE,
3694 TRUE,
3695 TRUE);
3696 //
3697 // Call the port driver.
3698 //
3699
3700 IoCallDriver(deviceExtension->PortDeviceObject, Irp);
3701
3702 return STATUS_MORE_PROCESSING_REQUIRED;
3703 }
3704
3705 //
3706 // Deallocate srb and sense buffer.
3707 //
3708
3709 if (srb) {
3710 if (srb->DataBuffer) {
3711 ExFreePool(srb->DataBuffer);
3712 }
3713 if (srb->SenseInfoBuffer) {
3714 ExFreePool(srb->SenseInfoBuffer);
3715 }
3716 ExFreePool(srb);
3717 }
3718
3719 if (Irp->PendingReturned) {
3720 IoMarkIrpPending(Irp);
3721 }
3722
3723 if (realIrp->PendingReturned) {
3724 IoMarkIrpPending(realIrp);
3725 }
3726
3727 if (Irp->MdlAddress) {
3728 IoFreeMdl(Irp->MdlAddress);
3729 }
3730
3731 IoFreeIrp(Irp);
3732
3733 //
3734 // Set status in completing IRP.
3735 //
3736
3737 realIrp->IoStatus.Status = status;
3738
3739 //
3740 // Set the hard error if necessary.
3741 //
3742
3743 if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
3744
3745 //
3746 // Store DeviceObject for filesystem, and clear
3747 // in IoStatus.Information field.
3748 //
3749
3750 IoSetHardErrorOrVerifyDevice(realIrp, DeviceObject);
3751 realIrp->IoStatus.Information = 0;
3752 }
3753
3754 IoCompleteRequest(realIrp, IO_DISK_INCREMENT);
3755
3756 IoStartNextPacket(DeviceObject, FALSE);
3757
3758 return STATUS_MORE_PROCESSING_REQUIRED;
3759 }
3760
3761
3762 NTSTATUS
3763 NTAPI
3764 CdRomSwitchModeCompletion(
3765 IN PDEVICE_OBJECT DeviceObject,
3766 IN PIRP Irp,
3767 IN PVOID Context
3768 )
3769 {
3770 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
3771 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
3772 PCDROM_DATA cdData = (PCDROM_DATA)(deviceExtension + 1);
3773 PIO_STACK_LOCATION realIrpStack;
3774 PIO_STACK_LOCATION realIrpNextStack;
3775 PSCSI_REQUEST_BLOCK srb = Context;
3776 PIRP realIrp = NULL;
3777 NTSTATUS status;
3778 BOOLEAN retry;
3779
3780 //
3781 // Extract the 'real' irp from the irpstack.
3782 //
3783
3784 realIrp = (PIRP) irpStack->Parameters.Others.Argument2;
3785 realIrpStack = IoGetCurrentIrpStackLocation(realIrp);
3786 realIrpNextStack = IoGetNextIrpStackLocation(realIrp);
3787
3788 //
3789 // Check SRB status for success of completing request.
3790 //
3791
3792 if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
3793
3794 DebugPrint((2,
3795 "CdRomSetVolumeIntermediateCompletion: Irp %lx, Srb %lx Real Irp\n",
3796 Irp,
3797 srb,
3798 realIrp));
3799
3800 //
3801 // Release the queue if it is frozen.
3802 //
3803
3804 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
3805 ScsiClassReleaseQueue(DeviceObject);
3806 }
3807
3808
3809 retry = ScsiClassInterpretSenseInfo(DeviceObject,
3810 srb,
3811 irpStack->MajorFunction,
3812 irpStack->Parameters.DeviceIoControl.IoControlCode,
3813 MAXIMUM_RETRIES - ((ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1),
3814 &status);
3815
3816 //
3817 // If the status is verified required and the this request
3818 // should bypass verify required then retry the request.
3819 //
3820
3821 if (realIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME &&
3822 status == STATUS_VERIFY_REQUIRED) {
3823
3824 status = STATUS_IO_DEVICE_ERROR;
3825 retry = TRUE;
3826 }
3827
3828 if (retry && (realIrpNextStack->Parameters.Others.Argument1 = (PVOID)((ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1-1))) {
3829
3830 if (((ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1)) {
3831
3832 //
3833 // Retry request.
3834 //
3835
3836 DebugPrint((1, "Retry request %lx - Calling StartIo\n", Irp));
3837
3838
3839 ExFreePool(srb->SenseInfoBuffer);
3840 ExFreePool(srb->DataBuffer);
3841 ExFreePool(srb);
3842 if (Irp->MdlAddress) {
3843 IoFreeMdl(Irp->MdlAddress);
3844 }
3845
3846 IoFreeIrp(Irp);
3847
3848 //
3849 // Call StartIo directly since IoStartNextPacket hasn't been called,
3850 // the serialisation is still intact.
3851 //
3852
3853 ScsiCdRomStartIo(DeviceObject, realIrp);
3854 return STATUS_MORE_PROCESSING_REQUIRED;
3855
3856 }
3857
3858 //
3859 // Exhausted retries. Fall through and complete the request with the appropriate status.
3860 //
3861 }
3862 } else {
3863
3864 //
3865 // Set status for successful request.
3866 //
3867
3868 status = STATUS_SUCCESS;
3869 }
3870
3871 if (NT_SUCCESS(status)) {
3872
3873 ULONG sectorSize, startingSector, transferByteCount;
3874 PCDB cdb;
3875
3876 //
3877 // Update device ext. to show which mode we are currently using.
3878 //
3879
3880 sectorSize = cdData->u1.BlockDescriptor.BlockLength[0] << 16;
3881 sectorSize |= (cdData->u1.BlockDescriptor.BlockLength[1] << 8);
3882 sectorSize |= (cdData->u1.BlockDescriptor.BlockLength[2]);
3883
3884 cdData->RawAccess = (sectorSize == RAW_SECTOR_SIZE) ? TRUE : FALSE;
3885
3886 //
3887 // Free the old data buffer, mdl.
3888 //
3889
3890 ExFreePool(srb->DataBuffer);
3891 IoFreeMdl(Irp->MdlAddress);
3892 IoFreeIrp(Irp);
3893
3894 //
3895 // rebuild the srb.
3896 //
3897
3898 cdb = (PCDB)srb->Cdb;
3899 RtlZeroMemory(cdb, CDB12GENERIC_LENGTH);
3900
3901
3902 if (cdData->RawAccess) {
3903
3904 PRAW_READ_INFO rawReadInfo =
3905 (PRAW_READ_INFO)realIrpStack->Parameters.DeviceIoControl.Type3InputBuffer;
3906
3907 ULONG maximumTransferLength;
3908 ULONG transferPages;
3909
3910 //
3911 // Calculate starting offset.
3912 //
3913
3914 startingSector = (ULONG)(rawReadInfo->DiskOffset.QuadPart >> deviceExtension->SectorShift);
3915 transferByteCount = rawReadInfo->SectorCount * RAW_SECTOR_SIZE;
3916 maximumTransferLength = deviceExtension->PortCapabilities->MaximumTransferLength;
3917 transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(realIrp->MdlAddress),
3918 transferByteCount);
3919
3920 //
3921 // Determine if request is within limits imposed by miniport.
3922 // If the request is larger than the miniport's capabilities, split it.
3923 //
3924
3925 if (transferByteCount > maximumTransferLength ||
3926 transferPages > deviceExtension->PortCapabilities->MaximumPhysicalPages) {
3927
3928 realIrp->IoStatus.Information = 0;
3929 realIrp->IoStatus.Status = STATUS_INVALID_PARAMETER;
3930 IoCompleteRequest(realIrp, IO_DISK_INCREMENT);
3931
3932 ExFreePool(srb->SenseInfoBuffer);
3933 ExFreePool(srb->DataBuffer);
3934 ExFreePool(srb);
3935 IoFreeMdl(Irp->MdlAddress);
3936 IoFreeIrp(Irp);
3937
3938 IoStartNextPacket(DeviceObject, FALSE);
3939
3940 return STATUS_MORE_PROCESSING_REQUIRED;
3941 }
3942
3943 srb->OriginalRequest = realIrp;
3944 srb->SrbFlags = deviceExtension->SrbFlags;
3945 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN);
3946 srb->DataTransferLength = transferByteCount;
3947 srb->TimeOutValue = deviceExtension->TimeOutValue;
3948 srb->CdbLength = 10;
3949 srb->DataBuffer = MmGetMdlVirtualAddress(realIrp->MdlAddress);
3950
3951 if (rawReadInfo->TrackMode == CDDA) {
3952 if (cdData->XAFlags & PLEXTOR_CDDA) {
3953
3954 srb->CdbLength = 12;
3955
3956 cdb->PLXTR_READ_CDDA.LogicalUnitNumber = deviceExtension->Lun;
3957 cdb->PLXTR_READ_CDDA.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF);
3958 cdb->PLXTR_READ_CDDA.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF);
3959 cdb->PLXTR_READ_CDDA.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF);
3960 cdb->PLXTR_READ_CDDA.LogicalBlockByte0 = (UCHAR) ((startingSector >> 24) & 0xFF);
3961
3962 cdb->PLXTR_READ_CDDA.TransferBlockByte3 = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
3963 cdb->PLXTR_READ_CDDA.TransferBlockByte2 = (UCHAR) (rawReadInfo->SectorCount >> 8);
3964 cdb->PLXTR_READ_CDDA.TransferBlockByte1 = 0;
3965 cdb->PLXTR_READ_CDDA.TransferBlockByte0 = 0;
3966
3967 cdb->PLXTR_READ_CDDA.SubCode = 0;
3968 cdb->PLXTR_READ_CDDA.OperationCode = 0xD8;
3969
3970 } else if (cdData->XAFlags & NEC_CDDA) {
3971
3972 cdb->NEC_READ_CDDA.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF);
3973 cdb->NEC_READ_CDDA.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF);
3974 cdb->NEC_READ_CDDA.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF);
3975 cdb->NEC_READ_CDDA.LogicalBlockByte0 = (UCHAR) ((startingSector >> 24) & 0xFF);
3976
3977 cdb->NEC_READ_CDDA.TransferBlockByte1 = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
3978 cdb->NEC_READ_CDDA.TransferBlockByte0 = (UCHAR) (rawReadInfo->SectorCount >> 8);
3979
3980 cdb->NEC_READ_CDDA.OperationCode = 0xD4;
3981 }
3982 } else {
3983 cdb->CDB10.LogicalUnitNumber = deviceExtension->Lun;
3984
3985 cdb->CDB10.TransferBlocksMsb = (UCHAR) (rawReadInfo->SectorCount >> 8);
3986 cdb->CDB10.TransferBlocksLsb = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
3987
3988 cdb->CDB10.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF);
3989 cdb->CDB10.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF);
3990 cdb->CDB10.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF);
3991 cdb->CDB10.LogicalBlockByte0 = (UCHAR) ((startingSector >> 24) & 0xFF);
3992
3993 cdb->CDB10.OperationCode = SCSIOP_READ;
3994 }
3995
3996 srb->SrbStatus = srb->ScsiStatus = 0;
3997
3998
3999 irpStack = IoGetNextIrpStackLocation(realIrp);
4000 irpStack->MajorFunction = IRP_MJ_SCSI;
4001 irpStack->Parameters.Scsi.Srb = srb;
4002
4003 if (!(irpStack->Parameters.Others.Argument1)) {
4004
4005 //
4006 // Only jam this in if it doesn't exist. The completion routines can
4007 // call StartIo directly in the case of retries and resetting it will
4008 // cause infinite loops.
4009 //
4010
4011 irpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES;
4012 }
4013
4014 //
4015 // Set up IoCompletion routine address.
4016 //
4017
4018 IoSetCompletionRoutine(realIrp,
4019 CdRomXACompletion,
4020 srb,
4021 TRUE,
4022 TRUE,
4023 TRUE);
4024 } else {
4025
4026 ULONG maximumTransferLength = deviceExtension->PortCapabilities->MaximumTransferLength;
4027 ULONG transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(realIrp->MdlAddress),
4028 realIrpStack->Parameters.Read.Length);
4029 //
4030 // Back to cooked sectors. Build and send a normal read.
4031 // The real work for setting offsets and checking for splitrequests was
4032 // done in startio
4033 //
4034
4035 if ((realIrpStack->Parameters.Read.Length > maximumTransferLength) ||
4036 (transferPages > deviceExtension->PortCapabilities->MaximumPhysicalPages)) {
4037
4038 //
4039 // Request needs to be split. Completion of each portion of the request will
4040 // fire off the next portion. The final request will signal Io to send a new request.
4041 //
4042
4043 ScsiClassSplitRequest(DeviceObject, realIrp, maximumTransferLength);
4044 return STATUS_MORE_PROCESSING_REQUIRED;
4045
4046 } else {
4047
4048 //
4049 // Build SRB and CDB for this IRP.
4050 //
4051
4052 ScsiClassBuildRequest(DeviceObject, realIrp);
4053
4054 }
4055 }
4056
4057 //
4058 // Call the port driver.
4059 //
4060
4061 IoCallDriver(deviceExtension->PortDeviceObject, realIrp);
4062
4063 return STATUS_MORE_PROCESSING_REQUIRED;
4064 }
4065
4066 //
4067 // Update device Extension flags to indicate that XA isn't supported.
4068 //
4069
4070 cdData->XAFlags |= XA_NOT_SUPPORTED;
4071
4072 //
4073 // Deallocate srb and sense buffer.
4074 //
4075
4076 if (srb) {
4077 if (srb->DataBuffer) {
4078 ExFreePool(srb->DataBuffer);
4079 }
4080 if (srb->SenseInfoBuffer) {
4081 ExFreePool(srb->SenseInfoBuffer);
4082 }
4083 ExFreePool(srb);
4084 }
4085
4086 if (Irp->PendingReturned) {
4087 IoMarkIrpPending(Irp);
4088 }
4089
4090 if (realIrp->PendingReturned) {
4091 IoMarkIrpPending(realIrp);
4092 }
4093
4094 if (Irp->MdlAddress) {
4095 IoFreeMdl(Irp->MdlAddress);
4096 }
4097
4098 IoFreeIrp(Irp);
4099
4100 //
4101 // Set status in completing IRP.
4102 //
4103
4104 realIrp->IoStatus.Status = status;
4105
4106 //
4107 // Set the hard error if necessary.
4108 //
4109
4110 if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
4111
4112 //
4113 // Store DeviceObject for filesystem, and clear
4114 // in IoStatus.Information field.
4115 //
4116
4117 IoSetHardErrorOrVerifyDevice(realIrp, DeviceObject);
4118 realIrp->IoStatus.Information = 0;
4119 }
4120
4121 IoCompleteRequest(realIrp, IO_DISK_INCREMENT);
4122
4123 IoStartNextPacket(DeviceObject, FALSE);
4124
4125 return STATUS_MORE_PROCESSING_REQUIRED;
4126 }
4127
4128 NTSTATUS
4129 NTAPI
4130 CdRomXACompletion(
4131 IN PDEVICE_OBJECT DeviceObject,
4132 IN PIRP Irp,
4133 IN PVOID Context
4134 )
4135
4136 /*++
4137
4138 Routine Description:
4139
4140 This routine executes when the port driver has completed a request.
4141 It looks at the SRB status in the completing SRB and if not success
4142 it checks for valid request sense buffer information. If valid, the
4143 info is used to update status with more precise message of type of
4144 error. This routine deallocates the SRB.
4145
4146 Arguments:
4147
4148 DeviceObject - Supplies the device object which represents the logical
4149 unit.
4150
4151 Irp - Supplies the Irp which has completed.
4152
4153 Context - Supplies a pointer to the SRB.
4154
4155 Return Value:
4156
4157 NT status
4158
4159 --*/
4160
4161 {
4162 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
4163 PIO_STACK_LOCATION irpNextStack = IoGetNextIrpStackLocation(Irp);
4164 PSCSI_REQUEST_BLOCK srb = Context;
4165 NTSTATUS status;
4166 BOOLEAN retry;
4167
4168 //
4169 // Check SRB status for success of completing request.
4170 //
4171
4172 if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
4173
4174 DebugPrint((2,"ScsiClassIoComplete: IRP %lx, SRB %lx\n", Irp, srb));
4175
4176 //
4177 // Release the queue if it is frozen.
4178 //
4179
4180 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
4181 ScsiClassReleaseQueue(DeviceObject);
4182 }
4183
4184 retry = ScsiClassInterpretSenseInfo(
4185 DeviceObject,
4186 srb,
4187 irpStack->MajorFunction,
4188 irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL ? irpStack->Parameters.DeviceIoControl.IoControlCode : 0,
4189 MAXIMUM_RETRIES - ((ULONG_PTR)irpNextStack->Parameters.Others.Argument1),
4190 &status);
4191
4192 //
4193 // If the status is verified required and the this request
4194 // should bypass verify required then retry the request.
4195 //
4196
4197 if (irpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME &&
4198 status == STATUS_VERIFY_REQUIRED) {
4199
4200 status = STATUS_IO_DEVICE_ERROR;
4201 retry = TRUE;
4202 }
4203
4204 if (retry && (irpNextStack->Parameters.Others.Argument1 = (PVOID)((ULONG_PTR)irpNextStack->Parameters.Others.Argument1-1))) {
4205
4206 if (((ULONG_PTR)irpNextStack->Parameters.Others.Argument1)) {
4207
4208 //
4209 // Retry request.
4210 //
4211
4212 DebugPrint((1, "CdRomXACompletion: Retry request %lx - Calling StartIo\n", Irp));
4213
4214
4215 ExFreePool(srb->SenseInfoBuffer);
4216 ExFreePool(srb->DataBuffer);
4217 ExFreePool(srb);
4218
4219 //
4220 // Call StartIo directly since IoStartNextPacket hasn't been called,
4221 // the serialisation is still intact.
4222 //
4223
4224 ScsiCdRomStartIo(DeviceObject, Irp);
4225 return STATUS_MORE_PROCESSING_REQUIRED;
4226
4227 }
4228
4229 //
4230 // Exhausted retries. Fall through and complete the request with the appropriate status.
4231 //
4232 }
4233 } else {
4234
4235 //
4236 // Set status for successful request.
4237 //
4238
4239 status = STATUS_SUCCESS;
4240
4241 } // end if (SRB_STATUS(srb->SrbStatus) ...
4242
4243 //
4244 // Return SRB to nonpaged pool.
4245 //
4246
4247 ExFreePool(srb);
4248
4249 //
4250 // Set status in completing IRP.
4251 //
4252
4253 Irp->IoStatus.Status = status;
4254
4255 //
4256 // Set the hard error if necessary.
4257 //
4258
4259 if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
4260
4261 //
4262 // Store DeviceObject for filesystem, and clear
4263 // in IoStatus.Information field.
4264 //
4265
4266 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
4267 Irp->IoStatus.Information = 0;
4268 }
4269
4270 //
4271 // If pending has be returned for this irp then mark the current stack as
4272 // pending.
4273 //
4274
4275 if (Irp->PendingReturned) {
4276 IoMarkIrpPending(Irp);
4277 }
4278
4279 //IoCompleteRequest(Irp, IO_DISK_INCREMENT);
4280 IoStartNextPacket(DeviceObject, FALSE);
4281
4282 return status;
4283 }
4284
4285 NTSTATUS
4286 NTAPI
4287 CdRomDeviceControl(
4288 IN PDEVICE_OBJECT DeviceObject,
4289 IN PIRP Irp
4290 )
4291
4292 /*++
4293
4294 Routine Description:
4295
4296 This is the NT device control handler for CDROMs.
4297
4298 Arguments:
4299
4300 DeviceObject - for this CDROM
4301
4302 Irp - IO Request packet
4303
4304 Return Value:
4305
4306 NTSTATUS
4307
4308 --*/
4309
4310 {
4311 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
4312 PIO_STACK_LOCATION nextStack;
4313 PKEVENT deviceControlEvent;
4314 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
4315 PCDROM_DATA cdData = (PCDROM_DATA)(deviceExtension+1);
4316 SCSI_REQUEST_BLOCK srb;
4317 NTSTATUS status;
4318 KIRQL irql;
4319
4320 ULONG ioctlCode;
4321 ULONG baseCode;
4322 ULONG functionCode;
4323
4324 RetryControl:
4325
4326 //
4327 // Zero the SRB on stack.
4328 //
4329
4330 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
4331
4332 Irp->IoStatus.Information = 0;
4333
4334 //
4335 // if this is a class driver ioctl then we need to change the base code
4336 // to IOCTL_CDROM_BASE so that the switch statement can handle it.
4337 //
4338 // WARNING - currently the scsi class ioctl function codes are between
4339 // 0x200 & 0x300. this routine depends on that fact
4340 //
4341
4342 ioctlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
4343 baseCode = ioctlCode >> 16;
4344 functionCode = (ioctlCode & (~0xffffc003)) >> 2;
4345
4346 DebugPrint((1, "CdRomDeviceControl: Ioctl Code = %#08lx, Base Code = %#lx,"
4347 " Function Code = %#lx\n",
4348 ioctlCode,
4349 baseCode,
4350 functionCode
4351 ));
4352
4353 if((functionCode >= 0x200) && (functionCode <= 0x300)) {
4354
4355 ioctlCode = (ioctlCode & 0x0000ffff) | CTL_CODE(IOCTL_CDROM_BASE, 0, 0, 0);
4356
4357 DebugPrint((1, "CdRomDeviceControl: Class Code - new ioctl code is %#08lx\n",
4358 ioctlCode));
4359
4360 irpStack->Parameters.DeviceIoControl.IoControlCode = ioctlCode;
4361
4362 }
4363
4364 switch (ioctlCode) {
4365
4366 case IOCTL_CDROM_RAW_READ: {
4367
4368 LARGE_INTEGER startingOffset;
4369 ULONG transferBytes;
4370 ULONG startingSector;
4371 PRAW_READ_INFO rawReadInfo = (PRAW_READ_INFO)irpStack->Parameters.DeviceIoControl.Type3InputBuffer;
4372 PUCHAR userData = (PUCHAR)Irp->AssociatedIrp.SystemBuffer;
4373
4374 //
4375 // Ensure that XA reads are supported.
4376 //
4377
4378 if (cdData->XAFlags & XA_NOT_SUPPORTED) {
4379
4380 DebugPrint((1,
4381 "CdRomDeviceControl: XA Reads not supported. Flags (%x)\n",
4382 cdData->XAFlags));
4383
4384 status = STATUS_INVALID_DEVICE_REQUEST;
4385 break;
4386 }
4387
4388 //
4389 // Check that ending sector is on disc and buffers are there and of
4390 // correct size.
4391 //
4392
4393 if (rawReadInfo == NULL) {
4394
4395 //
4396 // Called from user space. Validate the buffers.
4397 //
4398
4399 rawReadInfo = (PRAW_READ_INFO)userData;
4400 irpStack->Parameters.DeviceIoControl.Type3InputBuffer = (PVOID)userData;
4401
4402 if (rawReadInfo == NULL) {
4403
4404 DebugPrint((1,"CdRomDeviceControl: Invalid I/O parameters for XA Read (No extent info\n"));
4405
4406 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
4407
4408 IoCompleteRequest(Irp, IO_NO_INCREMENT);
4409 return STATUS_INVALID_PARAMETER;
4410 }
4411
4412 if (irpStack->Parameters.DeviceIoControl.InputBufferLength != sizeof(RAW_READ_INFO)) {
4413
4414 DebugPrint((1,"CdRomDeviceControl: Invalid I/O parameters for XA Read (Invalid info buffer\n"));
4415
4416 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
4417
4418 IoCompleteRequest(Irp, IO_NO_INCREMENT);
4419 return STATUS_INVALID_PARAMETER;
4420 }
4421 }
4422
4423 startingOffset.QuadPart = rawReadInfo->DiskOffset.QuadPart;
4424 startingSector = (ULONG)(rawReadInfo->DiskOffset.QuadPart >> deviceExtension->SectorShift);
4425 transferBytes = rawReadInfo->SectorCount * RAW_SECTOR_SIZE;
4426
4427 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < transferBytes) {
4428
4429 DebugPrint((1,"CdRomDeviceControl: Invalid I/O parameters for XA Read (Bad buffer size)\n"));
4430
4431 //
4432 // Fail request with status of invalid parameters.
4433 //
4434
4435 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
4436
4437 IoCompleteRequest(Irp, IO_NO_INCREMENT);
4438 return STATUS_INVALID_PARAMETER;
4439 }
4440
4441 if ((startingOffset.QuadPart + transferBytes) > deviceExtension->PartitionLength.QuadPart) {
4442
4443 DebugPrint((1,"CdRomDeviceControl: Invalid I/O parameters for XA Read (Request Out of Bounds)\n"));
4444
4445 //
4446 // Fail request with status of invalid parameters.
4447 //
4448
4449 status = STATUS_INVALID_PARAMETER;
4450 break;
4451 }
4452
4453 IoMarkIrpPending(Irp);
4454 IoStartPacket(DeviceObject, Irp, NULL, NULL);
4455
4456 return STATUS_PENDING;
4457 }
4458
4459 case IOCTL_CDROM_GET_DRIVE_GEOMETRY: {
4460
4461 DebugPrint((2,"CdRomDeviceControl: Get drive geometry\n"));
4462
4463 if ( irpStack->Parameters.DeviceIoControl.OutputBufferLength <
4464 sizeof( DISK_GEOMETRY ) ) {
4465
4466 status = STATUS_INFO_LENGTH_MISMATCH;
4467 break;
4468 }
4469
4470 IoMarkIrpPending(Irp);
4471 IoStartPacket(DeviceObject,Irp, NULL,NULL);
4472
4473 return STATUS_PENDING;
4474 }
4475
4476 case IOCTL_CDROM_GET_LAST_SESSION:
4477 case IOCTL_CDROM_READ_TOC: {
4478
4479 //
4480 // If the cd is playing music then reject this request.
4481 //
4482
4483 if (CdRomIsPlayActive(DeviceObject)) {
4484 Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
4485 IoCompleteRequest(Irp, IO_NO_INCREMENT);
4486 return STATUS_DEVICE_BUSY;
4487 }
4488
4489 IoMarkIrpPending(Irp);
4490 IoStartPacket(DeviceObject, Irp, NULL, NULL);
4491
4492 return STATUS_PENDING;
4493 }
4494
4495 case IOCTL_CDROM_PLAY_AUDIO_MSF: {
4496
4497 //
4498 // Play Audio MSF
4499 //
4500
4501 DebugPrint((2,"CdRomDeviceControl: Play audio MSF\n"));
4502
4503 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
4504 sizeof(CDROM_PLAY_AUDIO_MSF)) {
4505
4506 //
4507 // Indicate unsuccessful status.
4508 //
4509
4510 status = STATUS_BUFFER_TOO_SMALL;
4511 break;
4512 }
4513
4514 IoMarkIrpPending(Irp);
4515 IoStartPacket(DeviceObject, Irp, NULL, NULL);
4516
4517 return STATUS_PENDING;
4518 }
4519
4520 case IOCTL_CDROM_SEEK_AUDIO_MSF: {
4521
4522
4523 //
4524 // Seek Audio MSF
4525 //
4526
4527 DebugPrint((2,"CdRomDeviceControl: Seek audio MSF\n"));
4528
4529 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
4530 sizeof(CDROM_SEEK_AUDIO_MSF)) {
4531
4532 //
4533 // Indicate unsuccessful status.
4534 //
4535
4536 status = STATUS_BUFFER_TOO_SMALL;
4537 break;
4538 } else {
4539 IoMarkIrpPending(Irp);
4540 IoStartPacket(DeviceObject, Irp, NULL, NULL);
4541
4542 return STATUS_PENDING;
4543
4544 }
4545 }
4546
4547 case IOCTL_CDROM_PAUSE_AUDIO: {
4548
4549 //
4550 // Pause audio
4551 //
4552
4553 DebugPrint((2, "CdRomDeviceControl: Pause audio\n"));
4554
4555 IoMarkIrpPending(Irp);
4556 IoStartPacket(DeviceObject, Irp, NULL, NULL);
4557
4558 return STATUS_PENDING;
4559
4560 break;
4561 }
4562
4563 case IOCTL_CDROM_RESUME_AUDIO: {
4564
4565 //
4566 // Resume audio
4567 //
4568
4569 DebugPrint((2, "CdRomDeviceControl: Resume audio\n"));
4570
4571 IoMarkIrpPending(Irp);
4572 IoStartPacket(DeviceObject, Irp, NULL, NULL);
4573
4574 return STATUS_PENDING;
4575 }
4576
4577 case IOCTL_CDROM_READ_Q_CHANNEL: {
4578
4579 if(irpStack->Parameters.DeviceIoControl.InputBufferLength <
4580 sizeof(CDROM_SUB_Q_DATA_FORMAT)) {
4581
4582 status = STATUS_BUFFER_TOO_SMALL;
4583 Irp->IoStatus.Information = 0;
4584 break;
4585 }
4586
4587 IoMarkIrpPending(Irp);
4588 IoStartPacket(DeviceObject, Irp, NULL, NULL);
4589
4590 return STATUS_PENDING;
4591 }
4592
4593 case IOCTL_CDROM_GET_CONTROL: {
4594
4595 DebugPrint((2, "CdRomDeviceControl: Get audio control\n"));
4596
4597 //
4598 // Verify user buffer is large enough for the data.
4599 //
4600
4601 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
4602 sizeof(CDROM_AUDIO_CONTROL)) {
4603
4604 //
4605 // Indicate unsuccessful status and no data transferred.
4606 //
4607
4608 status = STATUS_BUFFER_TOO_SMALL;
4609 Irp->IoStatus.Information = 0;
4610 break;
4611
4612 } else {
4613
4614 IoMarkIrpPending(Irp);
4615 IoStartPacket(DeviceObject, Irp, NULL, NULL);
4616
4617 return STATUS_PENDING;
4618 }
4619 }
4620
4621 case IOCTL_CDROM_GET_VOLUME: {
4622
4623 DebugPrint((2, "CdRomDeviceControl: Get volume control\n"));
4624
4625 //
4626 // Verify user buffer is large enough for data.
4627 //
4628
4629 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
4630 sizeof(VOLUME_CONTROL)) {
4631
4632 //
4633 // Indicate unsuccessful status and no data transferred.
4634 //
4635
4636 status = STATUS_BUFFER_TOO_SMALL;
4637 Irp->IoStatus.Information = 0;
4638 break;
4639
4640 } else {
4641 IoMarkIrpPending(Irp);
4642 IoStartPacket(DeviceObject, Irp, NULL, NULL);
4643
4644 return STATUS_PENDING;
4645 }
4646 }
4647
4648 case IOCTL_CDROM_SET_VOLUME: {
4649
4650 DebugPrint((2, "CdRomDeviceControl: Set volume control\n"));
4651
4652 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
4653 sizeof(VOLUME_CONTROL)) {
4654
4655 //
4656 // Indicate unsuccessful status.
4657 //
4658
4659 status = STATUS_BUFFER_TOO_SMALL;
4660 break;
4661 } else {
4662
4663 IoMarkIrpPending(Irp);
4664 IoStartPacket(DeviceObject, Irp, NULL, NULL);
4665
4666 return STATUS_PENDING;
4667 }
4668 }
4669
4670 case IOCTL_CDROM_STOP_AUDIO: {
4671
4672 //
4673 // Stop play.
4674 //
4675
4676 DebugPrint((2, "CdRomDeviceControl: Stop audio\n"));
4677
4678 IoMarkIrpPending(Irp);
4679 IoStartPacket(DeviceObject,Irp, NULL,NULL);
4680
4681 return STATUS_PENDING;
4682 }
4683
4684 case IOCTL_CDROM_CHECK_VERIFY: {
4685 DebugPrint((1, "CdRomDeviceControl: [%lx] Check Verify\n", Irp));
4686 IoMarkIrpPending(Irp);
4687
4688 if((irpStack->Parameters.DeviceIoControl.OutputBufferLength) &&
4689 (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG))) {
4690
4691 DebugPrint((1, "CdRomDeviceControl: Check Verify: media count "
4692 "buffer too small\n"));
4693
4694 status = STATUS_BUFFER_TOO_SMALL;
4695 break;
4696 }
4697
4698 IoStartPacket(DeviceObject,Irp, NULL,NULL);
4699
4700 return STATUS_PENDING;
4701 }
4702
4703 default: {
4704
4705 //
4706 // allocate an event and stuff it into our stack location.
4707 //
4708
4709 deviceControlEvent = ExAllocatePool(NonPagedPool, sizeof(KEVENT));
4710
4711 if(!deviceControlEvent) {
4712
4713 status = STATUS_INSUFFICIENT_RESOURCES;
4714
4715 } else {
4716
4717 PIO_STACK_LOCATION currentStack;
4718
4719 KeInitializeEvent(deviceControlEvent, NotificationEvent, FALSE);
4720
4721 currentStack = IoGetCurrentIrpStackLocation(Irp);
4722 nextStack = IoGetNextIrpStackLocation(Irp);
4723
4724 //
4725 // Copy the stack down a notch
4726 //
4727
4728 *nextStack = *currentStack;
4729
4730 IoSetCompletionRoutine(
4731 Irp,
4732 CdRomClassIoctlCompletion,
4733 deviceControlEvent,
4734 TRUE,
4735 TRUE,
4736 TRUE
4737 );
4738
4739 IoSetNextIrpStackLocation(Irp);
4740
4741 Irp->IoStatus.Status = STATUS_SUCCESS;
4742 Irp->IoStatus.Information = 0;
4743
4744 //
4745 // Override volume verifies on this stack location so that we
4746 // will be forced through the synchronization. Once this location
4747 // goes away we get the old value back
4748 //
4749
4750 nextStack->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
4751
4752 IoMarkIrpPending(Irp);
4753
4754 IoStartPacket(DeviceObject, Irp, NULL, NULL);
4755
4756 //
4757 // Wait for CdRomClassIoctlCompletion to set the event. This
4758 // ensures serialization remains intact for these unhandled device
4759 // controls.
4760 //
4761
4762 KeWaitForSingleObject(
4763 deviceControlEvent,
4764 Suspended,
4765 KernelMode,
4766 FALSE,
4767 NULL);
4768
4769 ExFreePool(deviceControlEvent);
4770
4771 DebugPrint((2, "CdRomDeviceControl: irp %#08lx synchronized\n", Irp));
4772
4773 //
4774 // If an error occured then propagate that back up - we are no longer
4775 // guaranteed synchronization and the upper layers will have to
4776 // retry.
4777 //
4778 // If no error occured, call down to the class driver directly
4779 // then start up the next request.
4780 //
4781
4782 if(Irp->IoStatus.Status == STATUS_SUCCESS) {
4783
4784 status = ScsiClassDeviceControl(DeviceObject, Irp);
4785
4786 KeRaiseIrql(DISPATCH_LEVEL, &irql);
4787
4788 IoStartNextPacket(DeviceObject, FALSE);
4789
4790 KeLowerIrql(irql);
4791 }
4792 }
4793
4794 return status;
4795 }
4796
4797 } // end switch()
4798
4799 if (status == STATUS_VERIFY_REQUIRED) {
4800
4801 //
4802 // If the status is verified required and this request
4803 // should bypass verify required then retry the request.
4804 //
4805
4806 if (irpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME) {
4807
4808 status = STATUS_IO_DEVICE_ERROR;
4809 goto RetryControl;
4810
4811 }
4812 }
4813
4814 if (IoIsErrorUserInduced(status)) {
4815
4816 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
4817
4818 }
4819
4820 //
4821 // Update IRP with completion status.
4822 //
4823
4824 Irp->IoStatus.Status = status;
4825
4826 //
4827 // Complete the request.
4828 //
4829
4830 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
4831 DebugPrint((2, "CdRomDeviceControl: Status is %lx\n", status));
4832 return status;
4833
4834 } // end ScsiCdRomDeviceControl()
4835
4836 VOID
4837 NTAPI
4838 ScanForSpecial(
4839 PDEVICE_OBJECT DeviceObject,
4840 PINQUIRYDATA InquiryData,
4841 PIO_SCSI_CAPABILITIES PortCapabilities
4842 )
4843
4844 /*++
4845
4846 Routine Description:
4847
4848 This function checks to see if an SCSI logical unit requires an special
4849 initialization or error processing.
4850
4851 Arguments:
4852
4853 DeviceObject - Supplies the device object to be tested.
4854
4855 InquiryData - Supplies the inquiry data returned by the device of interest.
4856
4857 PortCapabilities - Supplies the capabilities of the device object.
4858
4859 Return Value:
4860
4861 None.
4862
4863 --*/
4864
4865 {
4866 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
4867 PCDROM_DATA cdData = (PCDROM_DATA)(deviceExtension+1);
4868
4869 //
4870 // Look for a Hitachi CDR-1750. Read-ahead must be disabled in order
4871 // to get this cdrom drive to work on scsi adapters that use PIO.
4872 //
4873
4874 if ((strncmp((PCHAR)InquiryData->VendorId, "HITACHI CDR-1750S", strlen("HITACHI CDR-1750S")) == 0 ||
4875 strncmp((PCHAR)InquiryData->VendorId, "HITACHI CDR-3650/1650S", strlen("HITACHI CDR-3650/1650S")) == 0)
4876 && PortCapabilities->AdapterUsesPio) {
4877
4878 DebugPrint((1, "CdRom ScanForSpecial: Found Hitachi CDR-1750S.\n"));
4879
4880 //
4881 // Setup an error handler to reinitialize the cd rom after it is reset.
4882 //
4883
4884 deviceExtension->ClassError = HitachProcessError;
4885
4886 } else if (( RtlCompareMemory( InquiryData->VendorId,"FUJITSU", 7 ) == 7 ) &&
4887 (( RtlCompareMemory( InquiryData->ProductId,"FMCD-101", 8 ) == 8 ) ||
4888 ( RtlCompareMemory( InquiryData->ProductId,"FMCD-102", 8 ) == 8 ))) {
4889
4890 //
4891 // When Read command is issued to FMCD-101 or FMCD-102 and there is a music
4892 // cd in it. It takes longer time than SCSI_CDROM_TIMEOUT before returning
4893 // error status.
4894 //
4895
4896 deviceExtension->TimeOutValue = 20;
4897
4898 } else if (( RtlCompareMemory( InquiryData->VendorId,"TOSHIBA", 7) == 7) &&
4899 (( RtlCompareMemory( InquiryData->ProductId,"CD-ROM XM-34", 12) == 12))) {
4900
4901 SCSI_REQUEST_BLOCK srb;
4902 PCDB cdb;
4903 ULONG length;
4904 PUCHAR buffer;
4905 NTSTATUS status;
4906
4907 //
4908 // Set the density code and the error handler.
4909 //
4910
4911 length = (sizeof(MODE_READ_RECOVERY_PAGE) + MODE_BLOCK_DESC_LENGTH + MODE_HEADER_LENGTH);
4912
4913 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
4914
4915 //
4916 // Build the MODE SENSE CDB.
4917 //
4918
4919 srb.CdbLength = 6;
4920 cdb = (PCDB)srb.Cdb;
4921
4922 //
4923 // Set timeout value from device extension.
4924 //
4925
4926 srb.TimeOutValue = deviceExtension->TimeOutValue;
4927
4928 cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
4929 cdb->MODE_SENSE.PageCode = 0x1;
4930 cdb->MODE_SENSE.AllocationLength = (UCHAR)length;
4931
4932 buffer = ExAllocatePool(NonPagedPoolCacheAligned, (sizeof(MODE_READ_RECOVERY_PAGE) + MODE_BLOCK_DESC_LENGTH + MODE_HEADER_LENGTH));
4933 if (!buffer) {
4934 return;
4935 }
4936
4937 status = ScsiClassSendSrbSynchronous(DeviceObject,
4938 &srb,
4939 buffer,
4940 length,
4941 FALSE);
4942
4943 ((PERROR_RECOVERY_DATA)buffer)->BlockDescriptor.DensityCode = 0x83;
4944 ((PERROR_RECOVERY_DATA)buffer)->Header.ModeDataLength = 0x0;
4945
4946 RtlCopyMemory(&cdData->u1.Header, buffer, sizeof(ERROR_RECOVERY_DATA));
4947
4948 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
4949
4950 //
4951 // Build the MODE SENSE CDB.
4952 //
4953
4954 srb.CdbLength = 6;
4955 cdb = (PCDB)srb.Cdb;
4956
4957 //
4958 // Set timeout value from device extension.
4959 //
4960
4961 srb.TimeOutValue = deviceExtension->TimeOutValue;
4962
4963 cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
4964 cdb->MODE_SELECT.PFBit = 1;
4965 cdb->MODE_SELECT.ParameterListLength = (UCHAR)length;
4966
4967 status = ScsiClassSendSrbSynchronous(DeviceObject,
4968 &srb,
4969 buffer,
4970 length,
4971 TRUE);
4972
4973 if (!NT_SUCCESS(status)) {
4974 DebugPrint((1,
4975 "Cdrom.ScanForSpecial: Setting density code on Toshiba failed [%x]\n",
4976 status));
4977 }
4978
4979 deviceExtension->ClassError = ToshibaProcessError;
4980
4981 ExFreePool(buffer);
4982
4983 }
4984
4985 //
4986 // Determine special CD-DA requirements.
4987 //
4988
4989 if (RtlCompareMemory( InquiryData->VendorId,"PLEXTOR",7) == 7) {
4990 cdData->XAFlags |= PLEXTOR_CDDA;
4991 } else if (RtlCompareMemory ( InquiryData->VendorId,"NEC",3) == 3) {
4992 cdData->XAFlags |= NEC_CDDA;
4993 }
4994
4995 return;
4996 }
4997
4998 VOID
4999 NTAPI
5000 HitachProcessError(
5001 PDEVICE_OBJECT DeviceObject,
5002 PSCSI_REQUEST_BLOCK Srb,
5003 NTSTATUS *Status,
5004 BOOLEAN *Retry
5005 )
5006 /*++
5007
5008 Routine Description:
5009
5010 This routine checks the type of error. If the error indicates CD-ROM the
5011 CD-ROM needs to be reinitialized then a Mode sense command is sent to the
5012 device. This command disables read-ahead for the device.
5013
5014 Arguments:
5015
5016 DeviceObject - Supplies a pointer to the device object.
5017
5018 Srb - Supplies a pointer to the failing Srb.
5019
5020 Status - Not used.
5021
5022 Retry - Not used.
5023
5024 Return Value:
5025
5026 None.
5027
5028 --*/
5029
5030 {
5031 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
5032 PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer;
5033 LARGE_INTEGER largeInt;
5034 PUCHAR modePage;
5035 PIO_STACK_LOCATION irpStack;
5036 PIRP irp;
5037 PSCSI_REQUEST_BLOCK srb;
5038 PCOMPLETION_CONTEXT context;
5039 PCDB cdb;
5040 ULONG alignment;
5041
5042 UNREFERENCED_PARAMETER(Status);
5043 UNREFERENCED_PARAMETER(Retry);
5044
5045 largeInt.QuadPart = (LONGLONG) 1;
5046
5047 //
5048 // Check the status. The initialization command only needs to be sent
5049 // if UNIT ATTENTION is returned.
5050 //
5051
5052 if (!(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID)) {
5053
5054 //
5055 // The drive does not require reinitialization.
5056 //
5057
5058 return;
5059 }
5060
5061 //
5062 // Found a bad HITACHI cd-rom. These devices do not work with PIO
5063 // adapters when read-ahead is enabled. Read-ahead is disabled by
5064 // a mode select command. The mode select page code is zero and the
5065 // length is 6 bytes. All of the other bytes should be zero.
5066 //
5067
5068
5069 if ((senseBuffer->SenseKey & 0xf) == SCSI_SENSE_UNIT_ATTENTION) {
5070
5071 DebugPrint((1, "HitachiProcessError: Reinitializing the CD-ROM.\n"));
5072
5073 //
5074 // Send the special mode select command to disable read-ahead
5075 // on the CD-ROM reader.
5076 //
5077
5078 alignment = DeviceObject->AlignmentRequirement ?
5079 DeviceObject->AlignmentRequirement : 1;
5080
5081 context = ExAllocatePool(
5082 NonPagedPool,
5083 sizeof(COMPLETION_CONTEXT) + HITACHI_MODE_DATA_SIZE + alignment
5084 );
5085
5086 if (context == NULL) {
5087
5088 //
5089 // If there is not enough memory to fulfill this request,
5090 // simply return. A subsequent retry will fail and another
5091 // chance to start the unit.
5092 //
5093
5094 return;
5095 }
5096
5097 context->DeviceObject = DeviceObject;
5098 srb = &context->Srb;
5099
5100 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
5101
5102 //
5103 // Write length to SRB.
5104 //
5105
5106 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
5107
5108 //
5109 // Set up SCSI bus address.
5110 //
5111
5112 srb->PathId = deviceExtension->PathId;
5113 srb->TargetId = deviceExtension->TargetId;
5114 srb->Lun = deviceExtension->Lun;
5115
5116 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
5117 srb->TimeOutValue = deviceExtension->TimeOutValue;
5118
5119 //
5120 // Set the transfer length.
5121 //
5122
5123 srb->DataTransferLength = HITACHI_MODE_DATA_SIZE;
5124 srb->SrbFlags = SRB_FLAGS_DATA_OUT | SRB_FLAGS_DISABLE_AUTOSENSE | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
5125
5126 //
5127 // The data buffer must be aligned.
5128 //
5129
5130 srb->DataBuffer = (PVOID) (((ULONG_PTR) (context + 1) + (alignment - 1)) &
5131 ~(alignment - 1));
5132
5133
5134 //
5135 // Build the HITACHI read-ahead mode select CDB.
5136 //
5137
5138 srb->CdbLength = 6;
5139 cdb = (PCDB)srb->Cdb;
5140 cdb->MODE_SENSE.LogicalUnitNumber = srb->Lun;
5141 cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SELECT;
5142 cdb->MODE_SENSE.AllocationLength = HITACHI_MODE_DATA_SIZE;
5143
5144 //
5145 // Initialize the mode sense data.
5146 //
5147
5148 modePage = srb->DataBuffer;
5149
5150 RtlZeroMemory(modePage, HITACHI_MODE_DATA_SIZE);
5151
5152 //
5153 // Set the page length field to 6.
5154 //
5155
5156 modePage[5] = 6;
5157
5158 //
5159 // Build the asynchronous request to be sent to the port driver.
5160 //
5161
5162 irp = IoBuildAsynchronousFsdRequest(IRP_MJ_WRITE,
5163 DeviceObject,
5164 srb->DataBuffer,
5165 srb->DataTransferLength,
5166 &largeInt,
5167 NULL);
5168
5169 IoSetCompletionRoutine(irp,
5170 (PIO_COMPLETION_ROUTINE)ScsiClassAsynchronousCompletion,
5171 context,
5172 TRUE,
5173 TRUE,
5174 TRUE);
5175
5176 irpStack = IoGetNextIrpStackLocation(irp);
5177
5178 irpStack->MajorFunction = IRP_MJ_SCSI;
5179
5180 srb->OriginalRequest = irp;
5181
5182 //
5183 // Save SRB address in next stack for port driver.
5184 //
5185
5186 irpStack->Parameters.Scsi.Srb = (PVOID)srb;
5187
5188 //
5189 // Set up IRP Address.
5190 //
5191
5192 (VOID)IoCallDriver(deviceExtension->PortDeviceObject, irp);
5193
5194 }
5195 }
5196
5197 NTSTATUS
5198 NTAPI
5199 ToshibaProcessErrorCompletion(
5200 PDEVICE_OBJECT DeviceObject,
5201 PIRP Irp,
5202 PVOID Context
5203 )
5204
5205 /*++
5206
5207 Routine Description:
5208
5209 Completion routine for the ClassError routine to handle older Toshiba units
5210 that require setting the density code.
5211
5212 Arguments:
5213
5214 DeviceObject - Supplies a pointer to the device object.
5215
5216 Irp - Pointer to irp created to set the density code.
5217
5218 Context - Supplies a pointer to the Mode Select Srb.
5219
5220
5221 Return Value:
5222
5223 STATUS_MORE_PROCESSING_REQUIRED
5224
5225 --*/
5226
5227 {
5228
5229 PSCSI_REQUEST_BLOCK srb = Context;
5230
5231 //
5232 // Check for a frozen queue.
5233 //
5234
5235 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
5236
5237 //
5238 // Unfreeze the queue getting the device object from the context.
5239 //
5240
5241 ScsiClassReleaseQueue(DeviceObject);
5242 }
5243
5244 //
5245 // Free all of the allocations.
5246 //
5247
5248 ExFreePool(srb->DataBuffer);
5249 ExFreePool(srb);
5250 IoFreeMdl(Irp->MdlAddress);
5251 IoFreeIrp(Irp);
5252
5253 //
5254 // Indicate the I/O system should stop processing the Irp completion.
5255 //
5256
5257 return STATUS_MORE_PROCESSING_REQUIRED;
5258 }
5259
5260 VOID
5261 NTAPI
5262 ToshibaProcessError(
5263 PDEVICE_OBJECT DeviceObject,
5264 PSCSI_REQUEST_BLOCK Srb,
5265 NTSTATUS *Status,
5266 BOOLEAN *Retry
5267 )
5268
5269 /*++
5270
5271 Routine Description:
5272
5273 This routine checks the type of error. If the error indicates a unit attention,
5274 the density code needs to be set via a Mode select command.
5275
5276 Arguments:
5277
5278 DeviceObject - Supplies a pointer to the device object.
5279
5280 Srb - Supplies a pointer to the failing Srb.
5281
5282 Status - Not used.
5283
5284 Retry - Not used.
5285
5286 Return Value:
5287
5288 None.
5289
5290 --*/
5291
5292 {
5293 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
5294 PCDROM_DATA cdData = (PCDROM_DATA)(deviceExtension+1);
5295 PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer;
5296 PIO_STACK_LOCATION irpStack;
5297 PIRP irp;
5298 PSCSI_REQUEST_BLOCK srb;
5299 ULONG length;
5300 PCDB cdb;
5301 PUCHAR dataBuffer;
5302
5303
5304 if (!(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID)) {
5305 return;
5306 }
5307
5308 //
5309 // The Toshiba's require the density code to be set on power up and media changes.
5310 //
5311
5312 if ((senseBuffer->SenseKey & 0xf) == SCSI_SENSE_UNIT_ATTENTION) {
5313
5314
5315 irp = IoAllocateIrp((CCHAR)(deviceExtension->DeviceObject->StackSize+1),
5316 FALSE);
5317
5318 if (!irp) {
5319 return;
5320 }
5321
5322 srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK));
5323 if (!srb) {
5324 IoFreeIrp(irp);
5325 return;
5326 }
5327
5328
5329 length = sizeof(ERROR_RECOVERY_DATA);
5330 dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned, length);
5331 if (!dataBuffer) {
5332 ExFreePool(srb);
5333 IoFreeIrp(irp);
5334 return;
5335 }
5336
5337 irp->MdlAddress = IoAllocateMdl(dataBuffer,
5338 length,
5339 FALSE,
5340 FALSE,
5341 (PIRP) NULL);
5342
5343 if (!irp->MdlAddress) {
5344 ExFreePool(srb);
5345 ExFreePool(dataBuffer);
5346 IoFreeIrp(irp);
5347 return;
5348 }
5349
5350 //
5351 // Prepare the MDL
5352 //
5353
5354 MmBuildMdlForNonPagedPool(irp->MdlAddress);
5355
5356 RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
5357
5358 srb->DataBuffer = dataBuffer;
5359 cdb = (PCDB)srb->Cdb;
5360
5361 //
5362 // Set up the irp.
5363 //
5364
5365 IoSetNextIrpStackLocation(irp);
5366 irp->IoStatus.Status = STATUS_SUCCESS;
5367 irp->IoStatus.Information = 0;
5368 irp->Flags = 0;
5369 irp->UserBuffer = NULL;
5370
5371 //
5372 // Save the device object and irp in a private stack location.
5373 //
5374
5375 irpStack = IoGetCurrentIrpStackLocation(irp);
5376 irpStack->DeviceObject = deviceExtension->DeviceObject;
5377
5378 //
5379 // Construct the IRP stack for the lower level driver.
5380 //
5381
5382 irpStack = IoGetNextIrpStackLocation(irp);
5383 irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
5384 irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_OUT;
5385 irpStack->Parameters.Scsi.Srb = srb;
5386
5387 IoSetCompletionRoutine(irp,
5388 ToshibaProcessErrorCompletion,
5389 srb,
5390 TRUE,
5391 TRUE,
5392 TRUE);
5393
5394 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
5395 srb->PathId = deviceExtension->PathId;
5396 srb->TargetId = deviceExtension->TargetId;
5397 srb->Lun = deviceExtension->Lun;
5398 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
5399 srb->Cdb[1] |= deviceExtension->Lun << 5;
5400 srb->SrbStatus = srb->ScsiStatus = 0;
5401 srb->NextSrb = 0;
5402 srb->OriginalRequest = irp;
5403 srb->SenseInfoBufferLength = 0;
5404
5405 //
5406 // Set the transfer length.
5407 //
5408
5409 srb->DataTransferLength = length;
5410 srb->SrbFlags = SRB_FLAGS_DATA_OUT | SRB_FLAGS_DISABLE_AUTOSENSE | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
5411
5412
5413 srb->CdbLength = 6;
5414 cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
5415 cdb->MODE_SELECT.PFBit = 1;
5416 cdb->MODE_SELECT.ParameterListLength = (UCHAR)length;
5417
5418 //
5419 // Copy the Mode page into the databuffer.
5420 //
5421
5422 RtlCopyMemory(srb->DataBuffer, &cdData->u1.Header, length);
5423
5424 //
5425 // Set the density code.
5426 //
5427
5428 ((PERROR_RECOVERY_DATA)srb->DataBuffer)->BlockDescriptor.DensityCode = 0x83;
5429
5430 IoCallDriver(deviceExtension->PortDeviceObject, irp);
5431 }
5432 }
5433
5434 BOOLEAN
5435 NTAPI
5436 CdRomIsPlayActive(
5437 IN PDEVICE_OBJECT DeviceObject
5438 )
5439
5440 /*++
5441
5442 Routine Description:
5443
5444 This routine determines if the cd is currently playing music.
5445
5446 Arguments:
5447
5448 DeviceObject - Device object to test.
5449
5450 Return Value:
5451
5452 TRUE if the device is playing music.
5453
5454 --*/
5455 {
5456 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
5457 PIRP irp;
5458 IO_STATUS_BLOCK ioStatus;
5459 KEVENT event;
5460 NTSTATUS status;
5461 PSUB_Q_CURRENT_POSITION currentBuffer;
5462
5463 if (!PLAY_ACTIVE(deviceExtension)) {
5464 return(FALSE);
5465 }
5466
5467 currentBuffer = ExAllocatePool(NonPagedPoolCacheAligned, sizeof(SUB_Q_CURRENT_POSITION));
5468
5469 if (currentBuffer == NULL) {
5470 return(FALSE);
5471 }
5472
5473 ((PCDROM_SUB_Q_DATA_FORMAT) currentBuffer)->Format = IOCTL_CDROM_CURRENT_POSITION;
5474 ((PCDROM_SUB_Q_DATA_FORMAT) currentBuffer)->Track = 0;
5475
5476 //
5477 // Create notification event object to be used to signal the
5478 // request completion.
5479 //
5480
5481 KeInitializeEvent(&event, NotificationEvent, FALSE);
5482
5483 //
5484 // Build the synchronous request to be sent to the port driver
5485 // to perform the request.
5486 //
5487
5488 irp = IoBuildDeviceIoControlRequest(IOCTL_CDROM_READ_Q_CHANNEL,
5489 deviceExtension->DeviceObject,
5490 currentBuffer,
5491 sizeof(CDROM_SUB_Q_DATA_FORMAT),
5492 currentBuffer,
5493 sizeof(SUB_Q_CURRENT_POSITION),
5494 FALSE,
5495 &event,
5496 &ioStatus);
5497
5498 if (irp == NULL) {
5499 ExFreePool(currentBuffer);
5500 return FALSE;
5501 }
5502
5503 //
5504 // Pass request to port driver and wait for request to complete.
5505 //
5506
5507 status = IoCallDriver(deviceExtension->DeviceObject, irp);
5508
5509 if (status == STATUS_PENDING) {
5510 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
5511 status = ioStatus.Status;
5512 }
5513
5514 if (!NT_SUCCESS(status)) {
5515 ExFreePool(currentBuffer);
5516 return FALSE;
5517 }
5518
5519 ExFreePool(currentBuffer);
5520
5521 return(PLAY_ACTIVE(deviceExtension));
5522
5523 }
5524
5525 IO_COMPLETION_ROUTINE CdRomMediaChangeCompletion;
5526 NTSTATUS
5527 NTAPI
5528 CdRomMediaChangeCompletion(
5529 PDEVICE_OBJECT DeviceObject,
5530 PIRP Irp,
5531 PVOID Context
5532 )
5533
5534 /*++
5535
5536 Routine Description:
5537
5538 This routine handles the completion of the test unit ready irps
5539 used to determine if the media has changed. If the media has
5540 changed, this code signals the named event to wake up other
5541 system services that react to media change (aka AutoPlay).
5542
5543 Arguments:
5544
5545 DeviceObject - the object for the completion
5546 Irp - the IRP being completed
5547 Context - the SRB from the IRP
5548
5549 Return Value:
5550
5551 NTSTATUS
5552
5553 --*/
5554
5555 {
5556 PSCSI_REQUEST_BLOCK srb = (PSCSI_REQUEST_BLOCK) Context;
5557 PIO_STACK_LOCATION cdStack = IoGetCurrentIrpStackLocation(Irp);
5558 PIO_STACK_LOCATION irpNextStack = IoGetNextIrpStackLocation(Irp);
5559 PDEVICE_EXTENSION deviceExtension;
5560 PDEVICE_EXTENSION physicalExtension;
5561 PSENSE_DATA senseBuffer;
5562 PCDROM_DATA cddata;
5563
5564 ASSERT(Irp);
5565 ASSERT(cdStack);
5566 DeviceObject = cdStack->DeviceObject;
5567 ASSERT(DeviceObject);
5568
5569 deviceExtension = DeviceObject->DeviceExtension;
5570 physicalExtension = deviceExtension->PhysicalDevice->DeviceExtension;
5571 cddata = (PCDROM_DATA)(deviceExtension + 1);
5572
5573 ASSERT(cddata->MediaChangeIrp == NULL);
5574
5575 //
5576 // If the sense data field is valid, look for a media change.
5577 // otherwise this iteration of the polling will just assume nothing
5578 // changed.
5579 //
5580
5581 DebugPrint((3, "CdRomMediaChangeHandler: Completing Autorun Irp 0x%lx "
5582 "for device %d\n",
5583 Irp, deviceExtension->DeviceNumber));
5584
5585 if (srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) {
5586 if (srb->SenseInfoBufferLength >= FIELD_OFFSET(SENSE_DATA, CommandSpecificInformation)) {
5587
5588 //
5589 // See if this is a media change.
5590 //
5591
5592 senseBuffer = srb->SenseInfoBuffer;
5593 if ((senseBuffer->SenseKey & 0x0f) == SCSI_SENSE_UNIT_ATTENTION) {
5594 if (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_MEDIUM_CHANGED) {
5595
5596 DebugPrint((1, "CdRomMediaChangeCompletion: New media inserted "
5597 "into CdRom%d [irp = 0x%lx]\n",
5598 deviceExtension->DeviceNumber, Irp));
5599
5600 //
5601 // Media change event occurred - signal the named event.
5602 //
5603
5604 KeSetEvent(deviceExtension->MediaChangeEvent,
5605 (KPRIORITY) 0,
5606 FALSE);
5607
5608 deviceExtension->MediaChangeNoMedia = FALSE;
5609
5610 }
5611
5612 if (DeviceObject->Vpb->Flags & VPB_MOUNTED) {
5613
5614 //
5615 // Must remember the media changed and force the
5616 // file system to verify on next access
5617 //
5618
5619 DeviceObject->Flags |= DO_VERIFY_VOLUME;
5620 }
5621
5622 physicalExtension->MediaChangeCount++;
5623
5624 } else if(((senseBuffer->SenseKey & 0x0f) == SCSI_SENSE_NOT_READY)&&
5625 (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_NO_MEDIA_IN_DEVICE)&&
5626 (!deviceExtension->MediaChangeNoMedia)){
5627
5628 //
5629 // If there was no media in the device then signal the waiters if
5630 // we haven't already done so before.
5631 //
5632
5633 DebugPrint((1, "CdRomMediaChangeCompletion: No media in device"
5634 "CdRom%d [irp = 0x%lx]\n",
5635 deviceExtension->DeviceNumber, Irp));
5636
5637 KeSetEvent(deviceExtension->MediaChangeEvent,
5638 (KPRIORITY) 0,
5639 FALSE);
5640
5641 deviceExtension->MediaChangeNoMedia = TRUE;
5642
5643 }
5644 }
5645 } else if((srb->SrbStatus == SRB_STATUS_SUCCESS)&&
5646 (deviceExtension->MediaChangeNoMedia)) {
5647 //
5648 // We didn't have any media before and now the requests are succeeding
5649 // we probably missed the Media change somehow. Signal the change
5650 // anyway
5651 //
5652
5653 DebugPrint((1, "CdRomMediaChangeCompletion: Request completed normally"
5654 "for CdRom%d which was marked w/NoMedia [irp = 0x%lx]\n",
5655 deviceExtension->DeviceNumber, Irp));
5656
5657 KeSetEvent(deviceExtension->MediaChangeEvent,
5658 (KPRIORITY) 0,
5659 FALSE);
5660
5661 deviceExtension->MediaChangeNoMedia = FALSE;
5662
5663 }
5664
5665 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
5666 ScsiClassReleaseQueue(deviceExtension->DeviceObject);
5667 }
5668
5669 //
5670 // Remember the IRP and SRB for use the next time.
5671 //
5672
5673 irpNextStack->Parameters.Scsi.Srb = srb;
5674 cddata->MediaChangeIrp = Irp;
5675
5676 if (deviceExtension->ClassError) {
5677
5678 NTSTATUS status;
5679 BOOLEAN retry;
5680
5681 //
5682 // Throw away the status and retry values. Just give the error routine a chance
5683 // to do what it needs to.
5684 //
5685
5686 deviceExtension->ClassError(DeviceObject,
5687 srb,
5688 &status,
5689 &retry);
5690 }
5691
5692 IoStartNextPacket(DeviceObject, FALSE);
5693
5694 return STATUS_MORE_PROCESSING_REQUIRED;
5695 }
5696
5697 VOID
5698 NTAPI
5699 CdRomTickHandler(
5700 IN PDEVICE_OBJECT DeviceObject,
5701 IN PVOID Context
5702 )
5703
5704 /*++
5705
5706 Routine Description:
5707
5708 This routine handles the once per second timer provided by the
5709 Io subsystem. It is only used when the cdrom device itself is
5710 a candidate for autoplay support. It should never be called if
5711 the cdrom device is a changer device.
5712
5713 Arguments:
5714
5715 DeviceObject - what to check.
5716 Context - not used.
5717
5718 Return Value:
5719
5720 None.
5721
5722 --*/
5723
5724 {
5725 PIRP irp;
5726 PIRP heldIrpList;
5727 PIRP nextIrp;
5728 PLIST_ENTRY listEntry;
5729 PCDROM_DATA cddata;
5730 PIO_STACK_LOCATION irpStack;
5731 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
5732
5733 cddata = (PCDROM_DATA)(deviceExtension + 1);
5734
5735 if (cddata->MediaChange) {
5736 if (cddata->MediaChangeIrp != NULL) {
5737
5738 //
5739 // Media change support is active and the IRP is waiting.
5740 // Decrement the timer.
5741 // There is no MP protection on the timer counter. This
5742 // code is the only code that will manipulate the timer
5743 // and only one instance of it should be running at any
5744 // given time.
5745 //
5746
5747 cddata->MediaChangeCountDown--;
5748
5749 #ifdef DBG
5750 cddata->MediaChangeIrpTimeInUse = 0;
5751 cddata->MediaChangeIrpLost = FALSE;
5752 #endif
5753
5754 if (!cddata->MediaChangeCountDown) {
5755 PSCSI_REQUEST_BLOCK srb;
5756 PIO_STACK_LOCATION irpNextStack;
5757 PCDB cdb;
5758
5759 //
5760 // Reset the timer.
5761 //
5762
5763 cddata->MediaChangeCountDown = MEDIA_CHANGE_DEFAULT_TIME;
5764
5765 //
5766 // Prepare the IRP for the test unit ready
5767 //
5768
5769 irp = cddata->MediaChangeIrp;
5770 cddata->MediaChangeIrp = NULL;
5771
5772 irp->IoStatus.Status = STATUS_SUCCESS;
5773 irp->IoStatus.Information = 0;
5774 irp->Flags = 0;
5775 irp->UserBuffer = NULL;
5776
5777 //
5778 // If the irp is sent down when the volume needs to be
5779 // verified, CdRomUpdateGeometryCompletion won't complete
5780 // it since it's not associated with a thread. Marking
5781 // it to override the verify causes it always be sent
5782 // to the port driver
5783 //
5784
5785 irpStack = IoGetCurrentIrpStackLocation(irp);
5786 irpStack->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
5787
5788 irpNextStack = IoGetNextIrpStackLocation(irp);
5789 irpNextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
5790 irpNextStack->Parameters.DeviceIoControl.IoControlCode =
5791 IOCTL_SCSI_EXECUTE_NONE;
5792
5793 //
5794 // Prepare the SRB for execution.
5795 //
5796
5797 srb = irpNextStack->Parameters.Scsi.Srb;
5798 srb->SrbStatus = srb->ScsiStatus = 0;
5799 srb->NextSrb = 0;
5800 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
5801 srb->PathId = deviceExtension->PathId;
5802 srb->TargetId = deviceExtension->TargetId;
5803 srb->Lun = deviceExtension->Lun;
5804 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
5805 srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER |
5806 SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
5807 srb->DataTransferLength = 0;
5808 srb->OriginalRequest = irp;
5809
5810 RtlZeroMemory(srb->SenseInfoBuffer, SENSE_BUFFER_SIZE);
5811 srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
5812
5813 cdb = (PCDB) &srb->Cdb[0];
5814 cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
5815 cdb->CDB6GENERIC.LogicalUnitNumber = srb->Lun;
5816
5817 //
5818 // Setup the IRP to perform a test unit ready.
5819 //
5820
5821 IoSetCompletionRoutine(irp,
5822 CdRomMediaChangeCompletion,
5823 srb,
5824 TRUE,
5825 TRUE,
5826 TRUE);
5827
5828 //
5829 // Issue the request.
5830 //
5831
5832 IoStartPacket(DeviceObject, irp, NULL, NULL);
5833 }
5834 } else {
5835
5836 #ifdef DBG
5837 if(cddata->MediaChangeIrpLost == FALSE) {
5838 if(cddata->MediaChangeIrpTimeInUse++ >
5839 MEDIA_CHANGE_TIMEOUT_TIME) {
5840
5841 DebugPrint((0, "CdRom%d: AutoPlay has lost it's irp and "
5842 "doesn't know where to find it. Leave it "
5843 "alone and it'll come home dragging it's "
5844 "stack behind it.\n",
5845 deviceExtension->DeviceNumber));
5846 cddata->MediaChangeIrpLost = TRUE;
5847 }
5848 }
5849
5850 #endif
5851 }
5852 }
5853
5854 //
5855 // Process all generic timer IRPS in the timer list. As IRPs are pulled
5856 // off of the TimerIrpList they must be remembered in the first loop
5857 // if they are not sent to the lower driver. After all items have
5858 // been pulled off the list, it is possible to put the held IRPs back
5859 // into the TimerIrpList.
5860 //
5861
5862 heldIrpList = NULL;
5863 if (IsListEmpty(&cddata->TimerIrpList)) {
5864 listEntry = NULL;
5865 } else {
5866 listEntry = ExInterlockedRemoveHeadList(&cddata->TimerIrpList,
5867 &cddata->TimerIrpSpinLock);
5868 }
5869 while (listEntry) {
5870
5871 //
5872 // There is something in the timer list. Pick up the IRP and
5873 // see if it is ready to be submitted.
5874 //
5875
5876 irp = CONTAINING_RECORD(listEntry, IRP, Tail.Overlay.ListEntry);
5877 irpStack = IoGetCurrentIrpStackLocation(irp);
5878
5879 if (irpStack->Parameters.Others.Argument3) {
5880 ULONG_PTR count;
5881
5882 //
5883 // Decrement the countdown timer and put the IRP back in the list.
5884 //
5885
5886 count = (ULONG_PTR) irpStack->Parameters.Others.Argument3;
5887 count--;
5888 irpStack->Parameters.Others.Argument3 = (PVOID) count;
5889
5890 ASSERT(irp->AssociatedIrp.MasterIrp == NULL);
5891 if (heldIrpList) {
5892 irp->AssociatedIrp.MasterIrp = (PVOID) heldIrpList;
5893 }
5894 heldIrpList = irp;
5895
5896 } else {
5897
5898 //
5899 // Submit this IRP to the lower driver. This IRP does not
5900 // need to be remembered here. It will be handled again when
5901 // it completes.
5902 //
5903
5904 DebugPrint((1, "CdRomTickHandler: Reissuing request %lx (thread = %lx)\n", irp, irp->Tail.Overlay.Thread));
5905
5906 //
5907 // feed this to the appropriate port driver
5908 //
5909
5910 IoCallDriver (deviceExtension->PortDeviceObject, irp);
5911
5912 }
5913
5914 //
5915 // Pick up the next IRP from the timer list.
5916 //
5917
5918 listEntry = ExInterlockedRemoveHeadList(&cddata->TimerIrpList,
5919 &cddata->TimerIrpSpinLock);
5920 }
5921
5922 //
5923 // Move all held IRPs back onto the timer list.
5924 //
5925
5926 while (heldIrpList) {
5927
5928 //
5929 // Save the single list pointer before queueing this IRP.
5930 //
5931
5932 nextIrp = (PIRP) heldIrpList->AssociatedIrp.MasterIrp;
5933 heldIrpList->AssociatedIrp.MasterIrp = NULL;
5934
5935 //
5936 // Return the held IRP to the timer list.
5937 //
5938
5939 ExInterlockedInsertTailList(&cddata->TimerIrpList,
5940 &heldIrpList->Tail.Overlay.ListEntry,
5941 &cddata->TimerIrpSpinLock);
5942
5943 //
5944 // Continue processing the held IRPs
5945 //
5946
5947 heldIrpList = nextIrp;
5948 }
5949 }
5950
5951 BOOLEAN
5952 NTAPI
5953 CdRomCheckRegistryForMediaChangeValue(
5954 IN PUNICODE_STRING RegistryPath,
5955 IN ULONG DeviceNumber
5956 )
5957
5958 /*++
5959
5960 Routine Description:
5961
5962 The user must specify that AutoPlay is to run on the platform
5963 by setting the registry value HKEY_LOCAL_MACHINE\System\CurrentControlSet\
5964 Services\Cdrom\Autorun:REG_DWORD:1.
5965
5966 The user can override the global setting to enable or disable Autorun on a
5967 specific cdrom device by setting the key HKEY_LOCAL_MACHINE\System\
5968 CurrentControlSet\Services\Cdrom\Device<N>\Autorun:REG_DWORD to one or zero.
5969 (CURRENTLY UNIMPLEMENTED)
5970
5971 If this registry value does not exist or contains the value zero then
5972 the timer to check for media change does not run.
5973
5974 Arguments:
5975
5976 RegistryPath - pointer to the unicode string inside
5977 ...\CurrentControlSet\Services\Cdrom
5978 DeviceNumber - The number of the device object
5979
5980 Return Value:
5981
5982 TRUE - Autorun is enabled.
5983 FALSE - no autorun.
5984
5985 --*/
5986
5987 {
5988 #define ITEMS_TO_QUERY 2 /* always 1 greater than what is searched */
5989 PRTL_QUERY_REGISTRY_TABLE parameters = NULL;
5990 NTSTATUS status;
5991 LONG zero = 0;
5992
5993 LONG tmp = 0;
5994 LONG doRun = 0;
5995
5996 CHAR buf[32];
5997 ANSI_STRING paramNum;
5998
5999 UNICODE_STRING paramStr;
6000
6001 UNICODE_STRING paramSuffix;
6002 UNICODE_STRING paramPath;
6003 UNICODE_STRING paramDevPath;
6004
6005 //
6006 // First append \Parameters to the passed in registry path
6007 //
6008
6009 RtlInitUnicodeString(&paramStr, L"\\Parameters");
6010
6011 RtlInitUnicodeString(&paramPath, NULL);
6012
6013 paramPath.MaximumLength = RegistryPath->Length +
6014 paramStr.Length +
6015 sizeof(WCHAR);
6016
6017 paramPath.Buffer = ExAllocatePool(PagedPool, paramPath.MaximumLength);
6018
6019 if(!paramPath.Buffer) {
6020
6021 DebugPrint((1,"CdRomCheckRegAP: couldn't allocate paramPath\n"));
6022
6023 return FALSE;
6024 }
6025
6026 RtlZeroMemory(paramPath.Buffer, paramPath.MaximumLength);
6027 RtlAppendUnicodeToString(&paramPath, RegistryPath->Buffer);
6028 RtlAppendUnicodeToString(&paramPath, paramStr.Buffer);
6029
6030 DebugPrint((2, "CdRomCheckRegAP: paramPath [%d] = %ws\n",
6031 paramPath.Length,
6032 paramPath.Buffer));
6033
6034 //
6035 // build a counted ANSI string that contains
6036 // the suffix for the path
6037 //
6038
6039 sprintf(buf, "\\Device%lu", DeviceNumber);
6040 RtlInitAnsiString(&paramNum, buf);
6041
6042 //
6043 // Next convert this into a unicode string
6044 //
6045
6046 status = RtlAnsiStringToUnicodeString(&paramSuffix, &paramNum, TRUE);
6047
6048 if(!NT_SUCCESS(status)) {
6049 DebugPrint((1,"CdRomCheckRegAP: couldn't convert paramNum to paramSuffix\n"));
6050 ExFreePool(paramPath.Buffer);
6051 return FALSE;
6052 }
6053
6054 RtlInitUnicodeString(&paramDevPath, NULL);
6055
6056 //
6057 // now build the device specific path
6058 //
6059
6060 paramDevPath.MaximumLength = paramPath.Length +
6061 paramSuffix.Length +
6062 sizeof(WCHAR);
6063 paramDevPath.Buffer = ExAllocatePool(PagedPool, paramDevPath.MaximumLength);
6064
6065 if(!paramDevPath.Buffer) {
6066 RtlFreeUnicodeString(&paramSuffix);
6067 ExFreePool(paramPath.Buffer);
6068 return FALSE;
6069 }
6070
6071 RtlZeroMemory(paramDevPath.Buffer, paramDevPath.MaximumLength);
6072 RtlAppendUnicodeToString(&paramDevPath, paramPath.Buffer);
6073 RtlAppendUnicodeToString(&paramDevPath, paramSuffix.Buffer);
6074
6075 DebugPrint((2, "CdRomCheckRegAP: paramDevPath [%d] = %ws\n",
6076 paramPath.Length,
6077 paramPath.Buffer));
6078
6079 parameters = ExAllocatePool(NonPagedPool,
6080 sizeof(RTL_QUERY_REGISTRY_TABLE)*ITEMS_TO_QUERY);
6081
6082 if (parameters) {
6083
6084 //
6085 // Check for the Autorun value.
6086 //
6087
6088 RtlZeroMemory(parameters,
6089 (sizeof(RTL_QUERY_REGISTRY_TABLE)*ITEMS_TO_QUERY));
6090
6091 parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
6092 parameters[0].Name = L"Autorun";
6093 parameters[0].EntryContext = &doRun;
6094 parameters[0].DefaultType = REG_DWORD;
6095 parameters[0].DefaultData = &zero;
6096 parameters[0].DefaultLength = sizeof(ULONG);
6097
6098 status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
6099 RegistryPath->Buffer,
6100 parameters,
6101 NULL,
6102 NULL);
6103
6104 DebugPrint((2, "CdRomCheckRegAP: cdrom/Autorun flag = %d\n", doRun));
6105
6106 RtlZeroMemory(parameters,
6107 (sizeof(RTL_QUERY_REGISTRY_TABLE)*ITEMS_TO_QUERY));
6108
6109 parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
6110 parameters[0].Name = L"Autorun";
6111 parameters[0].EntryContext = &tmp;
6112 parameters[0].DefaultType = REG_DWORD;
6113 parameters[0].DefaultData = &doRun;
6114 parameters[0].DefaultLength = sizeof(ULONG);
6115
6116 status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
6117 paramPath.Buffer,
6118 parameters,
6119 NULL,
6120 NULL);
6121
6122 DebugPrint((2, "CdRomCheckRegAP: cdrom/parameters/autorun flag = %d\n", tmp));
6123
6124 RtlZeroMemory(parameters,
6125 (sizeof(RTL_QUERY_REGISTRY_TABLE) * ITEMS_TO_QUERY));
6126
6127 parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
6128 parameters[0].Name = L"Autorun";
6129 parameters[0].EntryContext = &doRun;
6130 parameters[0].DefaultType = REG_DWORD;
6131 parameters[0].DefaultData = &tmp;
6132 parameters[0].DefaultLength = sizeof(ULONG);
6133
6134 status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
6135 paramDevPath.Buffer,
6136 parameters,
6137 NULL,
6138 NULL);
6139
6140 DebugPrint((1, "CdRomCheckRegAP: cdrom/parameters/device%d/autorun flag = %d\n", DeviceNumber, doRun));
6141
6142 ExFreePool(parameters);
6143
6144 }
6145
6146 ExFreePool(paramPath.Buffer);
6147 ExFreePool(paramDevPath.Buffer);
6148 RtlFreeUnicodeString(&paramSuffix);
6149
6150 DebugPrint((1, "CdRomCheckRegAP: Autoplay for device %d is %s\n",
6151 DeviceNumber,
6152 (doRun ? "on" : "off")));
6153
6154 if(doRun) {
6155 return TRUE;
6156 }
6157
6158 return FALSE;
6159 }
6160
6161
6162 BOOLEAN
6163 NTAPI
6164 IsThisASanyo(
6165 IN PDEVICE_OBJECT DeviceObject,
6166 IN UCHAR PathId,
6167 IN UCHAR TargetId
6168 )
6169
6170 /*++
6171
6172 Routine Description:
6173
6174 This routine is called by DriverEntry to determine whether a Sanyo 3-CD
6175 changer device is present.
6176
6177 Arguments:
6178
6179 DeviceObject - Supplies the device object for the 'real' device.
6180
6181 PathId -
6182
6183 Return Value:
6184
6185 TRUE - if an Atapi changer device is found.
6186
6187 --*/
6188
6189 {
6190 KEVENT event;
6191 PIRP irp;
6192 PCHAR inquiryBuffer;
6193 IO_STATUS_BLOCK ioStatus;
6194 NTSTATUS status;
6195 PSCSI_ADAPTER_BUS_INFO adapterInfo;
6196 ULONG scsiBus;
6197 PINQUIRYDATA inquiryData;
6198 PSCSI_INQUIRY_DATA lunInfo;
6199
6200 inquiryBuffer = ExAllocatePool(NonPagedPool, 2048);
6201 KeInitializeEvent(&event, NotificationEvent, FALSE);
6202 irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_INQUIRY_DATA,
6203 DeviceObject,
6204 NULL,
6205 0,
6206 inquiryBuffer,
6207 2048,
6208 FALSE,
6209 &event,
6210 &ioStatus);
6211 if (!irp) {
6212 return FALSE;
6213 }
6214
6215 status = IoCallDriver(DeviceObject, irp);
6216
6217 if (status == STATUS_PENDING) {
6218 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
6219 status = ioStatus.Status;
6220 }
6221
6222 if (!NT_SUCCESS(status)) {
6223 return FALSE;
6224 }
6225
6226 adapterInfo = (PVOID) inquiryBuffer;
6227
6228 for (scsiBus=0; scsiBus < (ULONG)adapterInfo->NumberOfBuses; scsiBus++) {
6229
6230 //
6231 // Get the SCSI bus scan data for this bus.
6232 //
6233
6234 lunInfo = (PVOID) (inquiryBuffer + adapterInfo->BusData[scsiBus].InquiryDataOffset);
6235
6236 for (;;) {
6237
6238 if (lunInfo->PathId == PathId && lunInfo->TargetId == TargetId) {
6239
6240 inquiryData = (PVOID) lunInfo->InquiryData;
6241
6242 if (RtlCompareMemory(inquiryData->VendorId, "TORiSAN CD-ROM CDR-C", 20) == 20) {
6243 ExFreePool(inquiryBuffer);
6244 return TRUE;
6245 }
6246
6247 ExFreePool(inquiryBuffer);
6248 return FALSE;
6249 }
6250
6251 if (!lunInfo->NextInquiryDataOffset) {
6252 break;
6253 }
6254
6255 lunInfo = (PVOID) (inquiryBuffer + lunInfo->NextInquiryDataOffset);
6256 }
6257 }
6258
6259 ExFreePool(inquiryBuffer);
6260 return FALSE;
6261 }
6262
6263 BOOLEAN
6264 NTAPI
6265 IsThisAnAtapiChanger(
6266 IN PDEVICE_OBJECT DeviceObject,
6267 OUT PULONG DiscsPresent
6268 )
6269
6270 /*++
6271
6272 Routine Description:
6273
6274 This routine is called by DriverEntry to determine whether an Atapi
6275 changer device is present.
6276
6277 Arguments:
6278
6279 DeviceObject - Supplies the device object for the 'real' device.
6280
6281 DiscsPresent - Supplies a pointer to the number of Discs supported by the changer.
6282
6283 Return Value:
6284
6285 TRUE - if an Atapi changer device is found.
6286
6287 --*/
6288
6289 {
6290 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
6291 PMECHANICAL_STATUS_INFORMATION_HEADER mechanicalStatusBuffer;
6292 NTSTATUS status;
6293 SCSI_REQUEST_BLOCK srb;
6294 PCDB cdb = (PCDB) &srb.Cdb[0];
6295 BOOLEAN retVal = FALSE;
6296
6297 *DiscsPresent = 0;
6298
6299 //
6300 // Some devices can't handle 12 byte CDB's gracefully
6301 //
6302
6303 if(deviceExtension->DeviceFlags & DEV_NO_12BYTE_CDB) {
6304
6305 return FALSE;
6306
6307 }
6308
6309 //
6310 // Build and issue the mechanical status command.
6311 //
6312
6313 mechanicalStatusBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
6314 sizeof(MECHANICAL_STATUS_INFORMATION_HEADER));
6315
6316 if (!mechanicalStatusBuffer) {
6317 retVal = FALSE;
6318 } else {
6319
6320 //
6321 // Build and send the Mechanism status CDB.
6322 //
6323
6324 RtlZeroMemory(&srb, sizeof(srb));
6325
6326 srb.CdbLength = 12;
6327 srb.TimeOutValue = 20;
6328
6329 cdb->MECH_STATUS.OperationCode = SCSIOP_MECHANISM_STATUS;
6330 cdb->MECH_STATUS.AllocationLength[1] = sizeof(MECHANICAL_STATUS_INFORMATION_HEADER);
6331
6332 status = ScsiClassSendSrbSynchronous(DeviceObject,
6333 &srb,
6334 mechanicalStatusBuffer,
6335 sizeof(MECHANICAL_STATUS_INFORMATION_HEADER),
6336 FALSE);
6337
6338
6339 if (status == STATUS_SUCCESS) {
6340
6341 //
6342 // Indicate number of slots available
6343 //
6344
6345 *DiscsPresent = mechanicalStatusBuffer->NumberAvailableSlots;
6346 if (*DiscsPresent > 1) {
6347 retVal = TRUE;
6348 } else {
6349
6350 //
6351 // If only one disc, no need for this driver.
6352 //
6353
6354 retVal = FALSE;
6355 }
6356 } else {
6357
6358 //
6359 // Device doesn't support this command.
6360 //
6361
6362 retVal = FALSE;
6363 }
6364
6365 ExFreePool(mechanicalStatusBuffer);
6366 }
6367
6368 return retVal;
6369 }
6370
6371 BOOLEAN
6372 NTAPI
6373 IsThisAMultiLunDevice(
6374 IN PDEVICE_OBJECT DeviceObject,
6375 IN PDEVICE_OBJECT PortDeviceObject
6376 )
6377 /*++
6378
6379 Routine Description:
6380
6381 This routine is called to determine whether a multi-lun
6382 device is present.
6383
6384 Arguments:
6385
6386 DeviceObject - Supplies the device object for the 'real' device.
6387
6388 Return Value:
6389
6390 TRUE - if a Multi-lun device is found.
6391
6392 --*/
6393 {
6394 PCHAR buffer;
6395 PSCSI_INQUIRY_DATA lunInfo;
6396 PSCSI_ADAPTER_BUS_INFO adapterInfo;
6397 PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
6398 PINQUIRYDATA inquiryData;
6399 ULONG scsiBus;
6400 NTSTATUS status;
6401 UCHAR lunCount = 0;
6402
6403 status = ScsiClassGetInquiryData(PortDeviceObject, (PSCSI_ADAPTER_BUS_INFO *) &buffer);
6404
6405 if (!NT_SUCCESS(status)) {
6406 DebugPrint((1,"IsThisAMultiLunDevice: ScsiClassGetInquiryData failed\n"));
6407 return FALSE;
6408 }
6409
6410 adapterInfo = (PVOID) buffer;
6411
6412 //
6413 // For each SCSI bus this adapter supports ...
6414 //
6415
6416 for (scsiBus=0; scsiBus < adapterInfo->NumberOfBuses; scsiBus++) {
6417
6418 //
6419 // Get the SCSI bus scan data for this bus.
6420 //
6421
6422 lunInfo = (PVOID) (buffer + adapterInfo->BusData[scsiBus].InquiryDataOffset);
6423
6424 while (adapterInfo->BusData[scsiBus].InquiryDataOffset) {
6425
6426 inquiryData = (PVOID)lunInfo->InquiryData;
6427
6428 if ((lunInfo->PathId == deviceExtension->PathId) &&
6429 (lunInfo->TargetId == deviceExtension->TargetId) &&
6430 (inquiryData->DeviceType == READ_ONLY_DIRECT_ACCESS_DEVICE)) {
6431
6432 DebugPrint((1,"IsThisAMultiLunDevice: Vendor string is %.24s\n",
6433 inquiryData->VendorId));
6434
6435 //
6436 // If this device has more than one cdrom-type lun then we
6437 // won't support autoplay on it
6438 //
6439
6440 if (lunCount++) {
6441 ExFreePool(buffer);
6442 return TRUE;
6443 }
6444 }
6445
6446 //
6447 // Get next LunInfo.
6448 //
6449
6450 if (lunInfo->NextInquiryDataOffset == 0) {
6451 break;
6452 }
6453
6454 lunInfo = (PVOID) (buffer + lunInfo->NextInquiryDataOffset);
6455 }
6456 }
6457
6458 ExFreePool(buffer);
6459 return FALSE;
6460
6461 }
6462
6463 IO_COMPLETION_ROUTINE CdRomUpdateGeometryCompletion;
6464 NTSTATUS
6465 NTAPI
6466 CdRomUpdateGeometryCompletion(
6467 PDEVICE_OBJECT DeviceObject,
6468 PIRP Irp,
6469 PVOID Context
6470 )
6471
6472 /*++
6473
6474 Routine Description:
6475
6476 This routine andles the completion of the test unit ready irps
6477 used to determine if the media has changed. If the media has
6478 changed, this code signals the named event to wake up other
6479 system services that react to media change (aka AutoPlay).
6480
6481 Arguments:
6482
6483 DeviceObject - the object for the completion
6484 Irp - the IRP being completed
6485 Context - the SRB from the IRP
6486
6487 Return Value:
6488
6489 NTSTATUS
6490
6491 --*/
6492
6493 {
6494 PSCSI_REQUEST_BLOCK srb = (PSCSI_REQUEST_BLOCK) Context;
6495 PREAD_CAPACITY_DATA readCapacityBuffer;
6496 PDEVICE_EXTENSION deviceExtension;
6497 PIO_STACK_LOCATION irpStack;
6498 NTSTATUS status;
6499 BOOLEAN retry;
6500 ULONG_PTR retryCount;
6501 ULONG lastSector;
6502 PIRP originalIrp;
6503 PCDROM_DATA cddata;
6504
6505 //
6506 // Get items saved in the private IRP stack location.
6507 //
6508
6509 irpStack = IoGetCurrentIrpStackLocation(Irp);
6510 retryCount = (ULONG_PTR) irpStack->Parameters.Others.Argument1;
6511 originalIrp = (PIRP) irpStack->Parameters.Others.Argument2;
6512
6513 if (!DeviceObject) {
6514 DeviceObject = irpStack->DeviceObject;
6515 }
6516 ASSERT(DeviceObject);
6517
6518 deviceExtension = DeviceObject->DeviceExtension;
6519 cddata = (PCDROM_DATA) (deviceExtension + 1);
6520 readCapacityBuffer = srb->DataBuffer;
6521
6522 if ((NT_SUCCESS(Irp->IoStatus.Status)) && (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_SUCCESS)) {
6523 PFOUR_BYTE from;
6524 PFOUR_BYTE to;
6525
6526 DebugPrint((2, "CdRomUpdateCapacityCompletion: [%lx] successful completion of buddy-irp %lx\n", originalIrp, Irp));
6527 //
6528 // Copy sector size from read capacity buffer to device extension
6529 // in reverse byte order.
6530 //
6531
6532 from = (PFOUR_BYTE) &readCapacityBuffer->BytesPerBlock;
6533 to = (PFOUR_BYTE) &deviceExtension->DiskGeometry->BytesPerSector;
6534 to->Byte0 = from->Byte3;
6535 to->Byte1 = from->Byte2;
6536 to->Byte2 = from->Byte1;
6537 to->Byte3 = from->Byte0;
6538
6539 //
6540 // Using the new BytesPerBlock, calculate and store the SectorShift.
6541 //
6542
6543 WHICH_BIT(deviceExtension->DiskGeometry->BytesPerSector, deviceExtension->SectorShift);
6544
6545 //
6546 // Copy last sector in reverse byte order.
6547 //
6548
6549 from = (PFOUR_BYTE) &readCapacityBuffer->LogicalBlockAddress;
6550 to = (PFOUR_BYTE) &lastSector;
6551 to->Byte0 = from->Byte3;
6552 to->Byte1 = from->Byte2;
6553 to->Byte2 = from->Byte1;
6554 to->Byte3 = from->Byte0;
6555 deviceExtension->PartitionLength.QuadPart = (LONGLONG)(lastSector + 1);
6556
6557 //
6558 // Calculate number of cylinders.
6559 //
6560
6561 deviceExtension->DiskGeometry->Cylinders.QuadPart = (LONGLONG)((lastSector + 1)/(32 * 64));
6562 deviceExtension->PartitionLength.QuadPart =
6563 (deviceExtension->PartitionLength.QuadPart << deviceExtension->SectorShift);
6564 deviceExtension->DiskGeometry->MediaType = RemovableMedia;
6565
6566 //
6567 // Assume sectors per track are 32;
6568 //
6569
6570 deviceExtension->DiskGeometry->SectorsPerTrack = 32;
6571
6572 //
6573 // Assume tracks per cylinder (number of heads) is 64.
6574 //
6575
6576 deviceExtension->DiskGeometry->TracksPerCylinder = 64;
6577
6578 } else {
6579
6580 DebugPrint((1, "CdRomUpdateCapacityCompletion: [%lx] unsuccessful completion of buddy-irp %lx (status - %lx)\n", originalIrp, Irp, Irp->IoStatus.Status));
6581
6582 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
6583 ScsiClassReleaseQueue(DeviceObject);
6584 }
6585
6586 retry = ScsiClassInterpretSenseInfo(DeviceObject,
6587 srb,
6588 IRP_MJ_SCSI,
6589 0,
6590 retryCount,
6591 &status);
6592 if (retry) {
6593 retryCount--;
6594 if (retryCount) {
6595 PCDB cdb;
6596
6597 DebugPrint((1, "CdRomUpdateCapacityCompletion: [%lx] Retrying request %lx .. thread is %lx\n", originalIrp, Irp, Irp->Tail.Overlay.Thread));
6598 //
6599 // set up a one shot timer to get this process started over
6600 //
6601
6602 irpStack->Parameters.Others.Argument1 = (PVOID) retryCount;
6603 irpStack->Parameters.Others.Argument2 = (PVOID) originalIrp;
6604 irpStack->Parameters.Others.Argument3 = (PVOID) 2;
6605
6606 //
6607 // Setup the IRP to be submitted again in the timer routine.
6608 //
6609
6610 irpStack = IoGetNextIrpStackLocation(Irp);
6611 irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
6612 irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
6613 irpStack->Parameters.Scsi.Srb = srb;
6614 IoSetCompletionRoutine(Irp,
6615 CdRomUpdateGeometryCompletion,
6616 srb,
6617 TRUE,
6618 TRUE,
6619 TRUE);
6620
6621 //
6622 // Set up the SRB for read capacity.
6623 //
6624
6625 srb->CdbLength = 10;
6626 srb->TimeOutValue = deviceExtension->TimeOutValue;
6627 srb->SrbStatus = srb->ScsiStatus = 0;
6628 srb->NextSrb = 0;
6629 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
6630 srb->PathId = deviceExtension->PathId;
6631 srb->TargetId = deviceExtension->TargetId;
6632 srb->Lun = deviceExtension->Lun;
6633 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
6634 srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
6635 srb->DataTransferLength = sizeof(READ_CAPACITY_DATA);
6636
6637 //
6638 // Set up the CDB
6639 //
6640
6641 cdb = (PCDB) &srb->Cdb[0];
6642 cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
6643 cdb->CDB10.LogicalUnitNumber = deviceExtension->Lun;
6644
6645 //
6646 // Requests queued onto this list will be sent to the
6647 // lower level driver during CdRomTickHandler
6648 //
6649
6650 ExInterlockedInsertHeadList(&cddata->TimerIrpList,
6651 &Irp->Tail.Overlay.ListEntry,
6652 &cddata->TimerIrpSpinLock);
6653
6654 return STATUS_MORE_PROCESSING_REQUIRED;
6655 } else {
6656
6657 //
6658 // This has been bounced for a number of times. Error the
6659 // original request.
6660 //
6661
6662 originalIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
6663 RtlZeroMemory(deviceExtension->DiskGeometry, sizeof(DISK_GEOMETRY));
6664 deviceExtension->DiskGeometry->BytesPerSector = 2048;
6665 deviceExtension->SectorShift = 11;
6666 deviceExtension->PartitionLength.QuadPart = (LONGLONG)(0x7fffffff);
6667 deviceExtension->DiskGeometry->MediaType = RemovableMedia;
6668 }
6669 } else {
6670
6671 //
6672 // Set up reasonable defaults
6673 //
6674
6675 RtlZeroMemory(deviceExtension->DiskGeometry, sizeof(DISK_GEOMETRY));
6676 deviceExtension->DiskGeometry->BytesPerSector = 2048;
6677 deviceExtension->SectorShift = 11;
6678 deviceExtension->PartitionLength.QuadPart = (LONGLONG)(0x7fffffff);
6679 deviceExtension->DiskGeometry->MediaType = RemovableMedia;
6680 }
6681 }
6682
6683 //
6684 // Free resources held.
6685 //
6686
6687 ExFreePool(srb->SenseInfoBuffer);
6688 ExFreePool(srb->DataBuffer);
6689 ExFreePool(srb);
6690 if (Irp->MdlAddress) {
6691 IoFreeMdl(Irp->MdlAddress);
6692 }
6693 IoFreeIrp(Irp);
6694 if (originalIrp->Tail.Overlay.Thread) {
6695
6696 DebugPrint((2, "CdRomUpdateCapacityCompletion: [%lx] completing original IRP\n", originalIrp));
6697 IoCompleteRequest(originalIrp, IO_DISK_INCREMENT);
6698
6699 } else {
6700 DebugPrint((1, "CdRomUpdateCapacityCompletion: [%lx] original irp has "
6701 "no thread\n",
6702 originalIrp
6703 ));
6704 }
6705
6706 //
6707 // It's now safe to either start the next request or let the waiting ioctl
6708 // request continue along it's merry way
6709 //
6710
6711 IoStartNextPacket(DeviceObject, FALSE);
6712
6713 return STATUS_MORE_PROCESSING_REQUIRED;
6714 }
6715
6716 NTSTATUS
6717 NTAPI
6718 CdRomUpdateCapacity(
6719 IN PDEVICE_EXTENSION DeviceExtension,
6720 IN PIRP IrpToComplete,
6721 IN OPTIONAL PKEVENT IoctlEvent
6722 )
6723
6724 /*++
6725
6726 Routine Description:
6727
6728 This routine updates the capacity of the disk as recorded in the device extension.
6729 It also completes the IRP given with STATUS_VERIFY_REQUIRED. This routine is called
6730 when a media change has occurred and it is necessary to determine the capacity of the
6731 new media prior to the next access.
6732
6733 Arguments:
6734
6735 DeviceExtension - the device to update
6736 IrpToComplete - the request that needs to be completed when done.
6737
6738 Return Value:
6739
6740 NTSTATUS
6741
6742 --*/
6743
6744 {
6745 PCDB cdb;
6746 PIRP irp;
6747 PSCSI_REQUEST_BLOCK srb;
6748 PREAD_CAPACITY_DATA capacityBuffer;
6749 PIO_STACK_LOCATION irpStack;
6750 PUCHAR senseBuffer;
6751 NTSTATUS status;
6752
6753 irp = IoAllocateIrp((CCHAR)(DeviceExtension->DeviceObject->StackSize+1),
6754 FALSE);
6755
6756 if (irp) {
6757
6758 srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK));
6759 if (srb) {
6760 capacityBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
6761 sizeof(READ_CAPACITY_DATA));
6762
6763 if (capacityBuffer) {
6764
6765
6766 senseBuffer = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE);
6767
6768 if (senseBuffer) {
6769
6770 irp->MdlAddress = IoAllocateMdl(capacityBuffer,
6771 sizeof(READ_CAPACITY_DATA),
6772 FALSE,
6773 FALSE,
6774 (PIRP) NULL);
6775
6776 if (irp->MdlAddress) {
6777
6778 //
6779 // Have all resources. Set up the IRP to send for the capacity.
6780 //
6781
6782 IoSetNextIrpStackLocation(irp);
6783 irp->IoStatus.Status = STATUS_SUCCESS;
6784 irp->IoStatus.Information = 0;
6785 irp->Flags = 0;
6786 irp->UserBuffer = NULL;
6787
6788 //
6789 // Save the device object and retry count in a private stack location.
6790 //
6791
6792 irpStack = IoGetCurrentIrpStackLocation(irp);
6793 irpStack->DeviceObject = DeviceExtension->DeviceObject;
6794 irpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES;
6795 irpStack->Parameters.Others.Argument2 = (PVOID) IrpToComplete;
6796
6797 //
6798 // Construct the IRP stack for the lower level driver.
6799 //
6800
6801 irpStack = IoGetNextIrpStackLocation(irp);
6802 irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
6803 irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
6804 irpStack->Parameters.Scsi.Srb = srb;
6805 IoSetCompletionRoutine(irp,
6806 CdRomUpdateGeometryCompletion,
6807 srb,
6808 TRUE,
6809 TRUE,
6810 TRUE);
6811 //
6812 // Prepare the MDL
6813 //
6814
6815 MmBuildMdlForNonPagedPool(irp->MdlAddress);
6816
6817
6818 //
6819 // Set up the SRB for read capacity.
6820 //
6821
6822 RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
6823 RtlZeroMemory(senseBuffer, SENSE_BUFFER_SIZE);
6824 srb->CdbLength = 10;
6825 srb->TimeOutValue = DeviceExtension->TimeOutValue;
6826 srb->SrbStatus = srb->ScsiStatus = 0;
6827 srb->NextSrb = 0;
6828 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
6829 srb->PathId = DeviceExtension->PathId;
6830 srb->TargetId = DeviceExtension->TargetId;
6831 srb->Lun = DeviceExtension->Lun;
6832 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
6833 srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
6834 srb->DataBuffer = capacityBuffer;
6835 srb->DataTransferLength = sizeof(READ_CAPACITY_DATA);
6836 srb->OriginalRequest = irp;
6837 srb->SenseInfoBuffer = senseBuffer;
6838 srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
6839
6840 //
6841 // Set up the CDB
6842 //
6843
6844 cdb = (PCDB) &srb->Cdb[0];
6845 cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
6846 cdb->CDB10.LogicalUnitNumber = DeviceExtension->Lun;
6847
6848 //
6849 // Set the return value in the IRP that will be completed
6850 // upon completion of the read capacity.
6851 //
6852
6853 IrpToComplete->IoStatus.Status = STATUS_VERIFY_REQUIRED;
6854 IoMarkIrpPending(IrpToComplete);
6855
6856 status = IoCallDriver(DeviceExtension->PortDeviceObject, irp);
6857
6858 //
6859 // status is not checked because the completion routine for this
6860 // IRP will always get called and it will free the resources.
6861 //
6862
6863 return STATUS_PENDING;
6864
6865 } else {
6866 ExFreePool(senseBuffer);
6867 ExFreePool(capacityBuffer);
6868 ExFreePool(srb);
6869 IoFreeIrp(irp);
6870 }
6871 } else {
6872 ExFreePool(capacityBuffer);
6873 ExFreePool(srb);
6874 IoFreeIrp(irp);
6875 }
6876 } else {
6877 ExFreePool(srb);
6878 IoFreeIrp(irp);
6879 }
6880 } else {
6881 IoFreeIrp(irp);
6882 }
6883 }
6884
6885 return STATUS_INSUFFICIENT_RESOURCES;
6886 }
6887
6888 NTSTATUS
6889 NTAPI
6890 CdRomClassIoctlCompletion(
6891 IN PDEVICE_OBJECT DeviceObject,
6892 IN PIRP Irp,
6893 IN PVOID Context
6894 )
6895
6896 /*++
6897
6898 Routine Description:
6899
6900 This routine signals the event used by CdRomDeviceControl to synchronize
6901 class driver (and lower level driver) ioctls with cdrom's startio routine.
6902 The irp completion is short-circuited so that CdRomDeviceControl can
6903 reissue it once it wakes up.
6904
6905 Arguments:
6906
6907 DeviceObject - the device object
6908 Irp - the request we are synchronizing
6909 Context - a PKEVENT that we need to signal
6910
6911 Return Value:
6912
6913 NTSTATUS
6914
6915 --*/
6916
6917 {
6918 PKEVENT syncEvent = (PKEVENT) Context;
6919
6920 DebugPrint((2, "CdRomClassIoctlCompletion: setting event for irp %#08lx\n",
6921 Irp
6922 ));
6923
6924 KeSetEvent(syncEvent, IO_DISK_INCREMENT, FALSE);
6925
6926 return STATUS_MORE_PROCESSING_REQUIRED;
6927 }