- Sync up Mm interface with WinLdr branch (introduce the concept of a memory type...
[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 STDCALL
236 DriverEntry(
237 IN PDRIVER_OBJECT DriverObject,
238 IN PUNICODE_STRING RegistryPath
239 );
240
241 BOOLEAN
242 STDCALL
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 STDCALL
253 ScsiCdRomOpenClose(
254 IN PDEVICE_OBJECT DeviceObject,
255 IN PIRP Irp
256 );
257
258 NTSTATUS
259 STDCALL
260 ScsiCdRomReadVerification(
261 IN PDEVICE_OBJECT DeviceObject,
262 IN PIRP Irp
263 );
264
265 NTSTATUS
266 STDCALL
267 ScsiCdRomSwitchMode(
268 IN PDEVICE_OBJECT DeviceObject,
269 IN ULONG SectorSize,
270 IN PIRP OriginalRequest
271 );
272
273 NTSTATUS
274 STDCALL
275 CdRomDeviceControl(
276 IN PDEVICE_OBJECT DeviceObject,
277 IN PIRP Irp
278 );
279
280 IO_COMPLETION_ROUTINE CdRomDeviceControlCompletion;
281 NTSTATUS
282 STDCALL
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 STDCALL
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 STDCALL
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 STDCALL
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 STDCALL
319 CdRomClassIoctlCompletion(
320 IN PDEVICE_OBJECT DeviceObject,
321 IN PIRP Irp,
322 IN PVOID Context
323 );
324
325 VOID
326 STDCALL
327 ScsiCdRomStartIo(
328 IN PDEVICE_OBJECT DeviceObject,
329 IN PIRP Irp
330 );
331
332 VOID
333 STDCALL
334 CdRomTickHandler(
335 IN PDEVICE_OBJECT DeviceObject,
336 IN PVOID Context
337 );
338
339 BOOLEAN
340 STDCALL
341 CdRomCheckRegistryForMediaChangeValue(
342 IN PUNICODE_STRING RegistryPath,
343 IN ULONG DeviceNumber
344 );
345
346 NTSTATUS
347 STDCALL
348 CdRomUpdateCapacity(
349 IN PDEVICE_EXTENSION DeviceExtension,
350 IN PIRP IrpToComplete,
351 IN OPTIONAL PKEVENT IoctlEvent
352 );
353
354 NTSTATUS
355 STDCALL
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 STDCALL
369 ScanForSpecial(
370 PDEVICE_OBJECT DeviceObject,
371 PINQUIRYDATA InquiryData,
372 PIO_SCSI_CAPABILITIES PortCapabilities
373 );
374
375 BOOLEAN
376 STDCALL
377 CdRomIsPlayActive(
378 IN PDEVICE_OBJECT DeviceObject
379 );
380
381 VOID
382 STDCALL
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 STDCALL
393 ToshibaProcessError(
394 PDEVICE_OBJECT DeviceObject,
395 PSCSI_REQUEST_BLOCK Srb,
396 NTSTATUS *Status,
397 BOOLEAN *Retry
398 );
399
400 BOOLEAN
401 STDCALL
402 IsThisAnAtapiChanger(
403 IN PDEVICE_OBJECT DeviceObject,
404 OUT PULONG DiscsPresent
405 );
406
407 BOOLEAN
408 STDCALL
409 IsThisASanyo(
410 IN PDEVICE_OBJECT DeviceObject,
411 IN UCHAR PathId,
412 IN UCHAR TargetId
413 );
414
415 BOOLEAN
416 STDCALL
417 IsThisAMultiLunDevice(
418 IN PDEVICE_OBJECT DeviceObject,
419 IN PDEVICE_OBJECT PortDeviceObject
420 );
421
422 VOID
423 STDCALL
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 STDCALL
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 STDCALL
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 STDCALL
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 STDCALL
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 UCHAR ntNameBuffer[64];
769 UNICODE_STRING ntUnicodeString;
770 NTSTATUS status;
771 BOOLEAN changerDevice;
772 SCSI_REQUEST_BLOCK srb;
773 ULONG length;
774 PCDROM_DATA cddata;
775 PCDB cdb;
776 PVOID senseData = NULL;
777 PDEVICE_OBJECT deviceObject = NULL;
778 PDEVICE_EXTENSION deviceExtension = NULL;
779 PUCHAR buffer;
780 ULONG bps;
781 ULONG lastBit;
782 ULONG timeOut;
783 BOOLEAN srbListInitialized = FALSE;
784
785 //
786 // Claim the device. Note that any errors after this
787 // will goto the generic handler, where the device will
788 // be released.
789 //
790
791 status = ScsiClassClaimDevice(PortDeviceObject,
792 LunInfo,
793 FALSE,
794 &PortDeviceObject);
795
796 if (!NT_SUCCESS(status)) {
797 return(status);
798 }
799
800 //
801 // Create device object for this device.
802 //
803
804 sprintf(ntNameBuffer,
805 "\\Device\\CdRom%lu",
806 *DeviceCount);
807
808 status = ScsiClassCreateDeviceObject(DriverObject,
809 ntNameBuffer,
810 NULL,
811 &deviceObject,
812 InitializationData);
813
814 if (!NT_SUCCESS(status)) {
815 DebugPrint((1,"CreateCdRomDeviceObjects: Can not create device %s\n",
816 ntNameBuffer));
817
818 RtlFreeUnicodeString(&ntUnicodeString);
819 goto CreateCdRomDeviceObjectExit;
820 }
821
822 //
823 // Indicate that IRPs should include MDLs.
824 //
825
826 deviceObject->Flags |= DO_DIRECT_IO;
827
828 //
829 // Set up required stack size in device object.
830 //
831
832 deviceObject->StackSize = PortDeviceObject->StackSize + 2;
833
834 deviceExtension = deviceObject->DeviceExtension;
835
836 //
837 // Allocate spinlock for split request completion.
838 //
839
840 KeInitializeSpinLock(&deviceExtension->SplitRequestSpinLock);
841
842 //
843 // This is the physical device.
844 //
845
846 deviceExtension->PhysicalDevice = deviceObject;
847
848 //
849 // Initialize lock count to zero. The lock count is used to
850 // disable the ejection mechanism when media is mounted.
851 //
852
853 deviceExtension->LockCount = 0;
854
855 //
856 // Save system cdrom number
857 //
858
859 deviceExtension->DeviceNumber = *DeviceCount;
860
861 //
862 // Copy port device object to device extension.
863 //
864
865 deviceExtension->PortDeviceObject = PortDeviceObject;
866
867 //
868 // Set the alignment requirements for the device based on the
869 // host adapter requirements
870 //
871
872 if (PortDeviceObject->AlignmentRequirement > deviceObject->AlignmentRequirement) {
873 deviceObject->AlignmentRequirement = PortDeviceObject->AlignmentRequirement;
874 }
875
876 //
877 // Save address of port driver capabilities.
878 //
879
880 deviceExtension->PortCapabilities = PortCapabilities;
881
882 //
883 // Clear SRB flags.
884 //
885
886 deviceExtension->SrbFlags = 0;
887 deviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
888
889 //
890 // Allocate request sense buffer.
891 //
892
893 senseData = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE);
894
895 if (senseData == NULL) {
896
897 //
898 // The buffer cannot be allocated.
899 //
900
901 status = STATUS_INSUFFICIENT_RESOURCES;
902 goto CreateCdRomDeviceObjectExit;
903 }
904
905 //
906 // Set the sense data pointer in the device extension.
907 //
908
909 deviceExtension->SenseData = senseData;
910
911 //
912 // CDROMs are not partitionable so starting offset is 0.
913 //
914
915 deviceExtension->StartingOffset.LowPart = 0;
916 deviceExtension->StartingOffset.HighPart = 0;
917
918 //
919 // Path/TargetId/LUN describes a device location on the SCSI bus.
920 // This information comes from the LunInfo buffer.
921 //
922
923 deviceExtension->PortNumber = (UCHAR)PortNumber;
924 deviceExtension->PathId = LunInfo->PathId;
925 deviceExtension->TargetId = LunInfo->TargetId;
926 deviceExtension->Lun = LunInfo->Lun;
927
928 //
929 // Set timeout value in seconds.
930 //
931
932 timeOut = ScsiClassQueryTimeOutRegistryValue(RegistryPath);
933 if (timeOut) {
934 deviceExtension->TimeOutValue = timeOut;
935 } else {
936 deviceExtension->TimeOutValue = SCSI_CDROM_TIMEOUT;
937 }
938
939 //
940 // Build the lookaside list for srb's for the physical disk. Should only
941 // need a couple.
942 //
943
944 ScsiClassInitializeSrbLookasideList(deviceExtension,
945 CDROM_SRB_LIST_SIZE);
946
947 srbListInitialized = TRUE;
948
949 //
950 // Back pointer to device object.
951 //
952
953 deviceExtension->DeviceObject = deviceObject;
954
955 //
956 // Allocate buffer for drive geometry.
957 //
958
959 deviceExtension->DiskGeometry =
960 ExAllocatePool(NonPagedPool, sizeof(DISK_GEOMETRY));
961
962 if (deviceExtension->DiskGeometry == NULL) {
963
964 status = STATUS_INSUFFICIENT_RESOURCES;
965 goto CreateCdRomDeviceObjectExit;
966 }
967
968 //
969 // Set up media change support defaults.
970 //
971
972 cddata = (PCDROM_DATA)(deviceExtension + 1);
973
974 KeInitializeSpinLock(&cddata->FormSpinLock);
975 KeInitializeSpinLock(&cddata->TimerIrpSpinLock);
976 InitializeListHead(&cddata->TimerIrpList);
977
978 cddata->MediaChangeCountDown = MEDIA_CHANGE_DEFAULT_TIME;
979 cddata->MediaChangeSupported = FALSE;
980 cddata->MediaChange = FALSE;
981
982 //
983 // Assume that there is initially no media in the device
984 // only notify upper layers if there is something there
985 //
986
987 deviceExtension->MediaChangeNoMedia = TRUE;
988 cddata->MediaChangeIrp = NULL;
989 #ifdef DBG
990 cddata->MediaChangeIrpTimeInUse = 0;
991 cddata->MediaChangeIrpLost = FALSE;
992 #endif
993
994 //
995 // Scan for Scsi controllers that require special processing.
996 //
997
998 ScanForSpecial(deviceObject,
999 (PINQUIRYDATA) LunInfo->InquiryData,
1000 PortCapabilities);
1001
1002 //
1003 // Do READ CAPACITY. This SCSI command
1004 // returns the last sector address on the device
1005 // and the bytes per sector.
1006 // These are used to calculate the drive capacity
1007 // in bytes.
1008 //
1009
1010 status = ScsiClassReadDriveCapacity(deviceObject);
1011 bps = deviceExtension->DiskGeometry->BytesPerSector;
1012
1013 if (!NT_SUCCESS(status) || !bps) {
1014
1015 DebugPrint((1,
1016 "CreateCdRomDeviceObjects: Can't read capacity for device %s\n",
1017 ntNameBuffer));
1018
1019 //
1020 // Set disk geometry to default values (per ISO 9660).
1021 //
1022
1023 bps = 2048;
1024 deviceExtension->SectorShift = 11;
1025 deviceExtension->PartitionLength.QuadPart = (LONGLONG)(0x7fffffff);
1026 } else {
1027
1028 //
1029 // Insure that bytes per sector is a power of 2
1030 // This corrects a problem with the HP 4020i CDR where it
1031 // returns an incorrect number for bytes per sector.
1032 //
1033
1034 lastBit = (ULONG) -1;
1035 while (bps) {
1036 lastBit++;
1037 bps = bps >> 1;
1038 }
1039
1040 bps = 1 << lastBit;
1041 }
1042 deviceExtension->DiskGeometry->BytesPerSector = bps;
1043 DebugPrint((2, "CreateCdRomDeviceObject: Calc'd bps = %x\n", bps));
1044
1045 //
1046 // Check to see if this is some sort of changer device
1047 //
1048
1049 changerDevice = FALSE;
1050
1051 //
1052 // Search for devices that have special requirements for media
1053 // change support.
1054 //
1055
1056 if (deviceExtension->Lun > 0) {
1057 changerDevice = TRUE;
1058 }
1059
1060 if (!changerDevice) {
1061 changerDevice = IsThisASanyo(deviceObject, deviceExtension->PathId,
1062 deviceExtension->TargetId);
1063 }
1064
1065 if (!changerDevice) {
1066 ULONG tmp;
1067 changerDevice = IsThisAnAtapiChanger(deviceObject, &tmp);
1068 }
1069
1070 if (!changerDevice) {
1071 changerDevice = IsThisAMultiLunDevice(deviceObject, PortDeviceObject);
1072 }
1073
1074 //
1075 // If it is a changer device, increment the timeout to take platter-swapping
1076 // time into account
1077 //
1078
1079 if(changerDevice) {
1080 deviceExtension->TimeOutValue += SCSI_CHANGER_BONUS_TIMEOUT;
1081 }
1082
1083 //
1084 // Create the media change named event. If this succeeds then continue
1085 // initializing the media change support data items.
1086 //
1087
1088 CdRomCreateNamedEvent(deviceExtension,*DeviceCount);
1089 if (deviceExtension->MediaChangeEvent) {
1090
1091 //
1092 // If this is not a changer, get an IRP for the timer request
1093 // and initialize the timer.
1094 //
1095
1096 if (!changerDevice) {
1097
1098 //
1099 // Not a changer device - continue with media change initialization.
1100 // Determine if the user actually wants media change events.
1101 //
1102
1103 if (CdRomCheckRegistryForMediaChangeValue(RegistryPath, *DeviceCount)) {
1104 PIO_STACK_LOCATION irpStack;
1105 PSCSI_REQUEST_BLOCK srb;
1106 PIRP irp;
1107
1108 //
1109 // User wants it - preallocate IRP and SRB.
1110 //
1111
1112 irp = IoAllocateIrp((CCHAR)(deviceObject->StackSize+1),
1113 FALSE);
1114 if (irp) {
1115 PVOID buffer;
1116
1117 srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK));
1118 buffer = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE);
1119
1120 if (srb && buffer) {
1121 PCDB cdb;
1122
1123 //
1124 // All resources have been allocated set up the IRP.
1125 //
1126
1127 IoSetNextIrpStackLocation(irp);
1128 irpStack = IoGetCurrentIrpStackLocation(irp);
1129 irpStack->DeviceObject = deviceObject;
1130 irpStack = IoGetNextIrpStackLocation(irp);
1131 cddata->MediaChangeIrp = irp;
1132 irpStack->Parameters.Scsi.Srb = srb;
1133
1134 //
1135 // Initialize the SRB
1136 //
1137
1138 RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
1139
1140 srb->CdbLength = 6;
1141 srb->TimeOutValue = deviceExtension->TimeOutValue * 2;
1142 srb->QueueTag = SP_UNTAGGED;
1143 srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
1144 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
1145 srb->PathId = deviceExtension->PathId;
1146 srb->TargetId = deviceExtension->TargetId;
1147 srb->Lun = deviceExtension->Lun;
1148 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1149
1150 //
1151 // Initialize and set up the sense information buffer
1152 //
1153
1154 RtlZeroMemory(buffer, SENSE_BUFFER_SIZE);
1155 srb->SenseInfoBuffer = buffer;
1156 srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
1157
1158 //
1159 // Initialize the CDB
1160 //
1161
1162 cdb = (PCDB)&srb->Cdb[0];
1163 cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
1164 cdb->CDB6GENERIC.LogicalUnitNumber = deviceExtension->Lun;
1165
1166 //
1167 // It is ok to support media change events on this device.
1168 //
1169
1170 cddata->MediaChangeSupported = TRUE;
1171 cddata->MediaChange = TRUE;
1172
1173 } else {
1174
1175 if (srb) {
1176 ExFreePool(srb);
1177 }
1178 if (buffer) {
1179 ExFreePool(buffer);
1180 }
1181 IoFreeIrp(irp);
1182 }
1183 }
1184 } else {
1185 deviceExtension->MediaChangeEvent = NULL;
1186 }
1187 } else {
1188 deviceExtension->MediaChangeEvent = NULL;
1189 }
1190 }
1191
1192 //
1193 // Assume use of 6-byte mode sense/select for now.
1194 //
1195
1196 cddata->XAFlags |= XA_USE_6_BYTE;
1197
1198 //
1199 // Build and issue mode sense with Read error recovery page. This will be used to change
1200 // block size in case of any raw reads (Mode 2, Form 2).
1201 //
1202
1203 length = (sizeof(MODE_READ_RECOVERY_PAGE) + MODE_BLOCK_DESC_LENGTH + MODE_HEADER_LENGTH);
1204
1205 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
1206
1207 srb.CdbLength = 6;
1208 cdb = (PCDB)srb.Cdb;
1209
1210 //
1211 // Set timeout value from device extension.
1212 //
1213
1214 srb.TimeOutValue = deviceExtension->TimeOutValue;
1215
1216 //
1217 // Build the MODE SENSE CDB. The data returned will be kept in the device extension
1218 // and used to set block size.
1219 //
1220
1221 cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
1222 cdb->MODE_SENSE.PageCode = 0x1;
1223 cdb->MODE_SENSE.AllocationLength = (UCHAR)length;
1224
1225 buffer = ExAllocatePool(NonPagedPoolCacheAligned, (sizeof(MODE_READ_RECOVERY_PAGE) + MODE_BLOCK_DESC_LENGTH + MODE_HEADER_LENGTH10));
1226 if (!buffer) {
1227 status = STATUS_INSUFFICIENT_RESOURCES;
1228 goto CreateCdRomDeviceObjectExit;
1229 }
1230
1231 status = ScsiClassSendSrbSynchronous(deviceObject,
1232 &srb,
1233 buffer,
1234 length,
1235 FALSE);
1236 if (!NT_SUCCESS(status)) {
1237
1238 //
1239 // May be Atapi, try 10-byte.
1240 //
1241
1242 length = (sizeof(MODE_READ_RECOVERY_PAGE) + MODE_BLOCK_DESC_LENGTH + MODE_HEADER_LENGTH10);
1243
1244 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
1245
1246 //
1247 // Build the MODE SENSE CDB.
1248 //
1249
1250 srb.CdbLength = 10;
1251 cdb = (PCDB)srb.Cdb;
1252
1253 //
1254 // Set timeout value from device extension.
1255 //
1256
1257 srb.TimeOutValue = deviceExtension->TimeOutValue;
1258
1259 cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
1260 cdb->MODE_SENSE10.PageCode = 0x1;
1261
1262 cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(length >> 8);
1263 cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(length & 0xFF);
1264
1265 status = ScsiClassSendSrbSynchronous(deviceObject,
1266 &srb,
1267 buffer,
1268 length,
1269 FALSE);
1270 if (status == STATUS_DATA_OVERRUN) {
1271
1272 //
1273 // Build and issue the ReadCd command to ensure that this device supports it.
1274 //
1275
1276 RtlZeroMemory(cdb, 12);
1277
1278 cdb->READ_CD.OperationCode = SCSIOP_READ_CD;
1279
1280 status = ScsiClassSendSrbSynchronous(deviceObject,
1281 &srb,
1282 NULL,
1283 0,
1284 FALSE);
1285
1286 //
1287 // If the command wasn't rejected then support the READ_CD.
1288 //
1289
1290 if (NT_SUCCESS(status) || (status == STATUS_NO_MEDIA_IN_DEVICE)) {
1291
1292 //
1293 // Using Read CD precludes issueing a mode select to
1294 // set the user data size. So, no buffer copy is
1295 // necessary.
1296 //
1297
1298 cddata->XAFlags &= ~XA_USE_6_BYTE;
1299 cddata->XAFlags = XA_USE_READ_CD | XA_USE_10_BYTE;
1300 } else {
1301
1302 RtlCopyMemory(&cddata->u1.Header, buffer, sizeof(ERROR_RECOVERY_DATA10));
1303 cddata->u1.Header.ModeDataLength = 0;
1304
1305 cddata->XAFlags &= ~XA_USE_6_BYTE;
1306 cddata->XAFlags |= XA_USE_10_BYTE;
1307 }
1308
1309 } else if (NT_SUCCESS(status)) {
1310
1311 RtlCopyMemory(&cddata->u1.Header, buffer, sizeof(ERROR_RECOVERY_DATA10));
1312 cddata->u1.Header.ModeDataLength = 0;
1313
1314 cddata->XAFlags &= ~XA_USE_6_BYTE;
1315 cddata->XAFlags |= XA_USE_10_BYTE;
1316
1317 } else {
1318 cddata->XAFlags |= XA_NOT_SUPPORTED;
1319 }
1320 } else {
1321 RtlCopyMemory(&cddata->u1.Header, buffer, sizeof(ERROR_RECOVERY_DATA));
1322 cddata->u1.Header.ModeDataLength = 0;
1323 }
1324
1325 ExFreePool(buffer);
1326
1327 //
1328 // Start the timer now regardless of if Autorun is enabled.
1329 // The timer must run forever since IoStopTimer faults.
1330 //
1331
1332 IoInitializeTimer(deviceObject, CdRomTickHandler, NULL);
1333 IoStartTimer(deviceObject);
1334
1335 return(STATUS_SUCCESS);
1336
1337 CreateCdRomDeviceObjectExit:
1338
1339 //
1340 // Release the device since an error occured.
1341 //
1342
1343 ScsiClassClaimDevice(PortDeviceObject,
1344 LunInfo,
1345 TRUE,
1346 NULL);
1347
1348 if (senseData != NULL) {
1349 ExFreePool(senseData);
1350 }
1351
1352 if (deviceExtension->DiskGeometry != NULL) {
1353 ExFreePool(deviceExtension->DiskGeometry);
1354 }
1355
1356 if (deviceObject != NULL) {
1357 if (srbListInitialized) {
1358 ExDeleteNPagedLookasideList(&deviceExtension->SrbLookasideListHead);
1359 }
1360 IoDeleteDevice(deviceObject);
1361 }
1362
1363
1364 return status;
1365
1366 } // end CreateCdRomDeviceObject()
1367
1368 VOID
1369 STDCALL
1370 ScsiCdRomStartIo(
1371 IN PDEVICE_OBJECT DeviceObject,
1372 IN PIRP Irp
1373 )
1374 {
1375
1376 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
1377 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
1378 PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
1379 PIO_STACK_LOCATION irpStack;
1380 PIRP irp2 = NULL;
1381 ULONG transferPages;
1382 ULONG transferByteCount = currentIrpStack->Parameters.Read.Length;
1383 ULONG maximumTransferLength = deviceExtension->PortCapabilities->MaximumTransferLength;
1384 PCDROM_DATA cdData;
1385 PSCSI_REQUEST_BLOCK srb = NULL;
1386 PCDB cdb;
1387 PUCHAR senseBuffer = NULL;
1388 PVOID dataBuffer;
1389 NTSTATUS status;
1390 BOOLEAN use6Byte;
1391
1392 //
1393 // Mark IRP with status pending.
1394 //
1395
1396 IoMarkIrpPending(Irp);
1397
1398 //
1399 // If the flag is set in the device object, force a verify.
1400 //
1401
1402 if (DeviceObject->Flags & DO_VERIFY_VOLUME) {
1403 DebugPrint((2, "ScsiCdRomStartIo: [%lx] Volume needs verified\n", Irp));
1404 if (!(currentIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME)) {
1405
1406 if (Irp->Tail.Overlay.Thread) {
1407 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
1408 }
1409
1410 Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
1411
1412 DebugPrint((2, "ScsiCdRomStartIo: [%lx] Calling UpdateCapcity - "
1413 "ioctl event = %lx\n",
1414 Irp,
1415 nextIrpStack->Parameters.Others.Argument1
1416 ));
1417
1418 //
1419 // our device control dispatch routine stores an event in the next
1420 // stack location to signal when startio has completed. We need to
1421 // pass this in so that the update capacity completion routine can
1422 // set it rather than completing the Irp.
1423 //
1424
1425 status = CdRomUpdateCapacity(deviceExtension,
1426 Irp,
1427 nextIrpStack->Parameters.Others.Argument1
1428 );
1429
1430 DebugPrint((2, "ScsiCdRomStartIo: [%lx] UpdateCapacity returned %lx\n", Irp, status));
1431 ASSERT(status == STATUS_PENDING);
1432 return;
1433 }
1434 }
1435
1436 cdData = (PCDROM_DATA)(deviceExtension + 1);
1437 use6Byte = cdData->XAFlags & XA_USE_6_BYTE;
1438
1439 if (currentIrpStack->MajorFunction == IRP_MJ_READ) {
1440
1441 //
1442 // Add partition byte offset to make starting byte relative to
1443 // beginning of disk. In addition, add in skew for DM Driver, if any.
1444 //
1445
1446 currentIrpStack->Parameters.Read.ByteOffset.QuadPart += (deviceExtension->StartingOffset.QuadPart);
1447
1448 //
1449 // Calculate number of pages in this transfer.
1450 //
1451
1452 transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp->MdlAddress),
1453 currentIrpStack->Parameters.Read.Length);
1454
1455 //
1456 // Check if request length is greater than the maximum number of
1457 // bytes that the hardware can transfer.
1458 //
1459
1460 if (cdData->RawAccess) {
1461
1462 ASSERT(!(cdData->XAFlags & XA_USE_READ_CD));
1463
1464 //
1465 // Fire off a mode select to switch back to cooked sectors.
1466 //
1467
1468 irp2 = IoAllocateIrp((CCHAR)(deviceExtension->DeviceObject->StackSize+1),
1469 FALSE);
1470
1471 if (!irp2) {
1472 Irp->IoStatus.Information = 0;
1473 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1474 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1475 IoStartNextPacket(DeviceObject, FALSE);
1476 return;
1477 }
1478
1479 srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK));
1480 if (!srb) {
1481 Irp->IoStatus.Information = 0;
1482 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1483 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1484 IoFreeIrp(irp2);
1485 IoStartNextPacket(DeviceObject, FALSE);
1486 return;
1487 }
1488
1489 RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
1490
1491 cdb = (PCDB)srb->Cdb;
1492
1493 //
1494 // Allocate sense buffer.
1495 //
1496
1497 senseBuffer = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE);
1498
1499 if (!senseBuffer) {
1500 Irp->IoStatus.Information = 0;
1501 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1502 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1503 ExFreePool(srb);
1504 IoFreeIrp(irp2);
1505 IoStartNextPacket(DeviceObject, FALSE);
1506 return;
1507 }
1508
1509 //
1510 // Set up the irp.
1511 //
1512
1513 IoSetNextIrpStackLocation(irp2);
1514 irp2->IoStatus.Status = STATUS_SUCCESS;
1515 irp2->IoStatus.Information = 0;
1516 irp2->Flags = 0;
1517 irp2->UserBuffer = NULL;
1518
1519 //
1520 // Save the device object and irp in a private stack location.
1521 //
1522
1523 irpStack = IoGetCurrentIrpStackLocation(irp2);
1524 irpStack->DeviceObject = deviceExtension->DeviceObject;
1525 irpStack->Parameters.Others.Argument2 = (PVOID) Irp;
1526
1527 //
1528 // The retry count will be in the real Irp, as the retry logic will
1529 // recreate our private irp.
1530 //
1531
1532 if (!(nextIrpStack->Parameters.Others.Argument1)) {
1533
1534 //
1535 // Only jam this in if it doesn't exist. The completion routines can
1536 // call StartIo directly in the case of retries and resetting it will
1537 // cause infinite loops.
1538 //
1539
1540 nextIrpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES;
1541 }
1542
1543 //
1544 // Construct the IRP stack for the lower level driver.
1545 //
1546
1547 irpStack = IoGetNextIrpStackLocation(irp2);
1548 irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
1549 irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
1550 irpStack->Parameters.Scsi.Srb = srb;
1551
1552 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
1553 srb->PathId = deviceExtension->PathId;
1554 srb->TargetId = deviceExtension->TargetId;
1555 srb->Lun = deviceExtension->Lun;
1556 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1557 srb->Cdb[1] |= deviceExtension->Lun << 5;
1558 srb->SrbStatus = srb->ScsiStatus = 0;
1559 srb->NextSrb = 0;
1560 srb->OriginalRequest = irp2;
1561 srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
1562 srb->SenseInfoBuffer = senseBuffer;
1563
1564 transferByteCount = (use6Byte) ? sizeof(ERROR_RECOVERY_DATA) : sizeof(ERROR_RECOVERY_DATA10);
1565 dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned, transferByteCount );
1566 if (!dataBuffer) {
1567 Irp->IoStatus.Information = 0;
1568 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1569 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1570 ExFreePool(senseBuffer);
1571 ExFreePool(srb);
1572 IoFreeIrp(irp2);
1573 IoStartNextPacket(DeviceObject, FALSE);
1574 return;
1575
1576 }
1577
1578 irp2->MdlAddress = IoAllocateMdl(dataBuffer,
1579 transferByteCount,
1580 FALSE,
1581 FALSE,
1582 (PIRP) NULL);
1583
1584 if (!irp2->MdlAddress) {
1585 Irp->IoStatus.Information = 0;
1586 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1587 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1588 ExFreePool(senseBuffer);
1589 ExFreePool(srb);
1590 ExFreePool(dataBuffer);
1591 IoFreeIrp(irp2);
1592 IoStartNextPacket(DeviceObject, FALSE);
1593 return;
1594 }
1595
1596 //
1597 // Prepare the MDL
1598 //
1599
1600 MmBuildMdlForNonPagedPool(irp2->MdlAddress);
1601
1602 srb->DataBuffer = dataBuffer;
1603
1604 //
1605 // Set the new block size in the descriptor.
1606 //
1607
1608 cdData->u1.BlockDescriptor.BlockLength[0] = (UCHAR)(COOKED_SECTOR_SIZE >> 16) & 0xFF;
1609 cdData->u1.BlockDescriptor.BlockLength[1] = (UCHAR)(COOKED_SECTOR_SIZE >> 8) & 0xFF;
1610 cdData->u1.BlockDescriptor.BlockLength[2] = (UCHAR)(COOKED_SECTOR_SIZE & 0xFF);
1611
1612 //
1613 // Move error page into dataBuffer.
1614 //
1615
1616 RtlCopyMemory(srb->DataBuffer, &cdData->u1.Header, transferByteCount);
1617
1618 //
1619 // Build and send a mode select to switch into raw mode.
1620 //
1621
1622 srb->SrbFlags = deviceExtension->SrbFlags;
1623 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_OUT);
1624 srb->DataTransferLength = transferByteCount;
1625 srb->TimeOutValue = deviceExtension->TimeOutValue * 2;
1626
1627 if (use6Byte) {
1628 srb->CdbLength = 6;
1629 cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
1630 cdb->MODE_SELECT.PFBit = 1;
1631 cdb->MODE_SELECT.ParameterListLength = (UCHAR)transferByteCount;
1632 } else {
1633
1634 srb->CdbLength = 10;
1635 cdb->MODE_SELECT10.OperationCode = SCSIOP_MODE_SELECT10;
1636 cdb->MODE_SELECT10.PFBit = 1;
1637 cdb->MODE_SELECT10.ParameterListLength[0] = (UCHAR)(transferByteCount >> 8);
1638 cdb->MODE_SELECT10.ParameterListLength[1] = (UCHAR)(transferByteCount & 0xFF);
1639 }
1640
1641 //
1642 // Update completion routine.
1643 //
1644
1645 IoSetCompletionRoutine(irp2,
1646 CdRomSwitchModeCompletion,
1647 srb,
1648 TRUE,
1649 TRUE,
1650 TRUE);
1651
1652 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
1653 return;
1654 }
1655
1656 if ((currentIrpStack->Parameters.Read.Length > maximumTransferLength) ||
1657 (transferPages >
1658 deviceExtension->PortCapabilities->MaximumPhysicalPages)) {
1659
1660 //
1661 // Request needs to be split. Completion of each portion of the
1662 // request will fire off the next portion. The final request will
1663 // signal Io to send a new request.
1664 //
1665
1666 transferPages =
1667 deviceExtension->PortCapabilities->MaximumPhysicalPages - 1;
1668
1669 if(maximumTransferLength > transferPages << PAGE_SHIFT) {
1670 maximumTransferLength = transferPages << PAGE_SHIFT;
1671 }
1672
1673 //
1674 // Check that the maximum transfer size is not zero
1675 //
1676
1677 if(maximumTransferLength == 0) {
1678 maximumTransferLength = PAGE_SIZE;
1679 }
1680
1681 ScsiClassSplitRequest(DeviceObject, Irp, maximumTransferLength);
1682 return;
1683
1684 } else {
1685
1686 //
1687 // Build SRB and CDB for this IRP.
1688 //
1689
1690 ScsiClassBuildRequest(DeviceObject, Irp);
1691
1692 }
1693
1694
1695 } else if (currentIrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) {
1696
1697 //
1698 // Allocate an irp, srb and associated structures.
1699 //
1700
1701 irp2 = IoAllocateIrp((CCHAR)(deviceExtension->DeviceObject->StackSize+1),
1702 FALSE);
1703
1704 if (!irp2) {
1705 Irp->IoStatus.Information = 0;
1706 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1707 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1708 IoStartNextPacket(DeviceObject, FALSE);
1709 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp, Irp->IoStatus.Status, __LINE__));
1710 return;
1711 }
1712
1713 srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK));
1714 if (!srb) {
1715 Irp->IoStatus.Information = 0;
1716 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1717 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1718 IoFreeIrp(irp2);
1719 IoStartNextPacket(DeviceObject, FALSE);
1720 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp, Irp->IoStatus.Status, __LINE__));
1721 return;
1722 }
1723
1724 RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
1725
1726 cdb = (PCDB)srb->Cdb;
1727
1728 //
1729 // Allocate sense buffer.
1730 //
1731
1732 senseBuffer = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE);
1733
1734 if (!senseBuffer) {
1735 Irp->IoStatus.Information = 0;
1736 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1737 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1738 ExFreePool(srb);
1739 IoFreeIrp(irp2);
1740 IoStartNextPacket(DeviceObject, FALSE);
1741 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp, Irp->IoStatus.Status, __LINE__));
1742 return;
1743 }
1744
1745 //
1746 // Set up the irp.
1747 //
1748
1749 IoSetNextIrpStackLocation(irp2);
1750 irp2->IoStatus.Status = STATUS_SUCCESS;
1751 irp2->IoStatus.Information = 0;
1752 irp2->Flags = 0;
1753 irp2->UserBuffer = NULL;
1754
1755 //
1756 // Save the device object and irp in a private stack location.
1757 //
1758
1759 irpStack = IoGetCurrentIrpStackLocation(irp2);
1760 irpStack->DeviceObject = deviceExtension->DeviceObject;
1761 irpStack->Parameters.Others.Argument2 = (PVOID) Irp;
1762
1763 //
1764 // The retry count will be in the real Irp, as the retry logic will
1765 // recreate our private irp.
1766 //
1767
1768 if (!(nextIrpStack->Parameters.Others.Argument1)) {
1769
1770 //
1771 // Only jam this in if it doesn't exist. The completion routines can
1772 // call StartIo directly in the case of retries and resetting it will
1773 // cause infinite loops.
1774 //
1775
1776 nextIrpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES;
1777 }
1778
1779 //
1780 // Construct the IRP stack for the lower level driver.
1781 //
1782
1783 irpStack = IoGetNextIrpStackLocation(irp2);
1784 irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
1785 irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
1786 irpStack->Parameters.Scsi.Srb = srb;
1787
1788 IoSetCompletionRoutine(irp2,
1789 CdRomDeviceControlCompletion,
1790 srb,
1791 TRUE,
1792 TRUE,
1793 TRUE);
1794 //
1795 // Setup those fields that are generic to all requests.
1796 //
1797
1798 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
1799 srb->PathId = deviceExtension->PathId;
1800 srb->TargetId = deviceExtension->TargetId;
1801 srb->Lun = deviceExtension->Lun;
1802 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1803 srb->Cdb[1] |= deviceExtension->Lun << 5;
1804 srb->SrbStatus = srb->ScsiStatus = 0;
1805 srb->NextSrb = 0;
1806 srb->OriginalRequest = irp2;
1807 srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
1808 srb->SenseInfoBuffer = senseBuffer;
1809
1810 switch (currentIrpStack->Parameters.DeviceIoControl.IoControlCode) {
1811
1812 case IOCTL_CDROM_RAW_READ: {
1813
1814 //
1815 // Determine whether the drive is currently in raw or cooked mode,
1816 // and which command to use to read the data.
1817 //
1818
1819 if (!(cdData->XAFlags & XA_USE_READ_CD)) {
1820
1821 PRAW_READ_INFO rawReadInfo =
1822 (PRAW_READ_INFO)currentIrpStack->Parameters.DeviceIoControl.Type3InputBuffer;
1823 ULONG maximumTransferLength;
1824 ULONG transferPages;
1825
1826 if (cdData->RawAccess) {
1827
1828 ULONG startingSector;
1829
1830 //
1831 // Free the recently allocated irp, as we don't need it.
1832 //
1833
1834 IoFreeIrp(irp2);
1835
1836 cdb = (PCDB)srb->Cdb;
1837 RtlZeroMemory(cdb, 12);
1838
1839 //
1840 // Calculate starting offset.
1841 //
1842
1843 startingSector = (ULONG)(rawReadInfo->DiskOffset.QuadPart >> deviceExtension->SectorShift);
1844 transferByteCount = rawReadInfo->SectorCount * RAW_SECTOR_SIZE;
1845 maximumTransferLength = deviceExtension->PortCapabilities->MaximumTransferLength;
1846 transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp->MdlAddress),
1847 transferByteCount);
1848
1849 //
1850 // Determine if request is within limits imposed by miniport.
1851 //
1852
1853 if (transferByteCount > maximumTransferLength ||
1854 transferPages > deviceExtension->PortCapabilities->MaximumPhysicalPages) {
1855
1856 //
1857 // The claim is that this won't happen, and is backed up by
1858 // ActiveMovie usage, which does unbuffered XA reads of 0x18000, yet
1859 // we get only 4 sector requests.
1860 //
1861
1862
1863 Irp->IoStatus.Information = 0;
1864 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
1865 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1866 ExFreePool(senseBuffer);
1867 ExFreePool(srb);
1868 IoStartNextPacket(DeviceObject, FALSE);
1869 return;
1870
1871 }
1872
1873 srb->OriginalRequest = Irp;
1874 srb->SrbFlags = deviceExtension->SrbFlags;
1875 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN);
1876 srb->DataTransferLength = transferByteCount;
1877 srb->TimeOutValue = deviceExtension->TimeOutValue;
1878 srb->CdbLength = 10;
1879 srb->DataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
1880
1881 if (rawReadInfo->TrackMode == CDDA) {
1882 if (cdData->XAFlags & PLEXTOR_CDDA) {
1883
1884 srb->CdbLength = 12;
1885
1886 cdb->PLXTR_READ_CDDA.LogicalUnitNumber = deviceExtension->Lun;
1887 cdb->PLXTR_READ_CDDA.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF);
1888 cdb->PLXTR_READ_CDDA.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF);
1889 cdb->PLXTR_READ_CDDA.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF);
1890 cdb->PLXTR_READ_CDDA.LogicalBlockByte0 = (UCHAR) ((startingSector >> 24) & 0xFF);
1891
1892 cdb->PLXTR_READ_CDDA.TransferBlockByte3 = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
1893 cdb->PLXTR_READ_CDDA.TransferBlockByte2 = (UCHAR) (rawReadInfo->SectorCount >> 8);
1894 cdb->PLXTR_READ_CDDA.TransferBlockByte1 = 0;
1895 cdb->PLXTR_READ_CDDA.TransferBlockByte0 = 0;
1896
1897 cdb->PLXTR_READ_CDDA.SubCode = 0;
1898 cdb->PLXTR_READ_CDDA.OperationCode = 0xD8;
1899
1900 } else if (cdData->XAFlags & NEC_CDDA) {
1901
1902 cdb->NEC_READ_CDDA.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF);
1903 cdb->NEC_READ_CDDA.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF);
1904 cdb->NEC_READ_CDDA.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF);
1905 cdb->NEC_READ_CDDA.LogicalBlockByte0 = (UCHAR) ((startingSector >> 24) & 0xFF);
1906
1907 cdb->NEC_READ_CDDA.TransferBlockByte1 = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
1908 cdb->NEC_READ_CDDA.TransferBlockByte0 = (UCHAR) (rawReadInfo->SectorCount >> 8);
1909
1910 cdb->NEC_READ_CDDA.OperationCode = 0xD4;
1911 }
1912 } else {
1913
1914 cdb->CDB10.LogicalUnitNumber = deviceExtension->Lun;
1915
1916 cdb->CDB10.TransferBlocksMsb = (UCHAR) (rawReadInfo->SectorCount >> 8);
1917 cdb->CDB10.TransferBlocksLsb = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
1918
1919 cdb->CDB10.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF);
1920 cdb->CDB10.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF);
1921 cdb->CDB10.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF);
1922 cdb->CDB10.LogicalBlockByte0 = (UCHAR) ((startingSector >> 24) & 0xFF);
1923
1924 cdb->CDB10.OperationCode = SCSIOP_READ;
1925 }
1926
1927 srb->SrbStatus = srb->ScsiStatus = 0;
1928
1929 nextIrpStack->MajorFunction = IRP_MJ_SCSI;
1930 nextIrpStack->Parameters.Scsi.Srb = srb;
1931
1932 if (!(nextIrpStack->Parameters.Others.Argument1)) {
1933
1934 //
1935 // Only jam this in if it doesn't exist. The completion routines can
1936 // call StartIo directly in the case of retries and resetting it will
1937 // cause infinite loops.
1938 //
1939
1940 nextIrpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES;
1941 }
1942
1943 //
1944 // Set up IoCompletion routine address.
1945 //
1946
1947 IoSetCompletionRoutine(Irp,
1948 CdRomXACompletion,
1949 srb,
1950 TRUE,
1951 TRUE,
1952 TRUE);
1953
1954 IoCallDriver(deviceExtension->PortDeviceObject, Irp);
1955 return;
1956
1957 } else {
1958
1959 transferByteCount = (use6Byte) ? sizeof(ERROR_RECOVERY_DATA) : sizeof(ERROR_RECOVERY_DATA10);
1960 dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned, transferByteCount );
1961 if (!dataBuffer) {
1962 Irp->IoStatus.Information = 0;
1963 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1964 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1965 ExFreePool(senseBuffer);
1966 ExFreePool(srb);
1967 IoFreeIrp(irp2);
1968 IoStartNextPacket(DeviceObject, FALSE);
1969 return;
1970
1971 }
1972
1973 irp2->MdlAddress = IoAllocateMdl(dataBuffer,
1974 transferByteCount,
1975 FALSE,
1976 FALSE,
1977 (PIRP) NULL);
1978
1979 if (!irp2->MdlAddress) {
1980 Irp->IoStatus.Information = 0;
1981 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1982 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1983 ExFreePool(senseBuffer);
1984 ExFreePool(srb);
1985 ExFreePool(dataBuffer);
1986 IoFreeIrp(irp2);
1987 IoStartNextPacket(DeviceObject, FALSE);
1988 return;
1989 }
1990
1991 //
1992 // Prepare the MDL
1993 //
1994
1995 MmBuildMdlForNonPagedPool(irp2->MdlAddress);
1996
1997 srb->DataBuffer = dataBuffer;
1998
1999 //
2000 // Set the new block size in the descriptor.
2001 //
2002
2003 cdData->u1.BlockDescriptor.BlockLength[0] = (UCHAR)(RAW_SECTOR_SIZE >> 16) & 0xFF;
2004 cdData->u1.BlockDescriptor.BlockLength[1] = (UCHAR)(RAW_SECTOR_SIZE >> 8) & 0xFF;
2005 cdData->u1.BlockDescriptor.BlockLength[2] = (UCHAR)(RAW_SECTOR_SIZE & 0xFF);
2006
2007
2008 //
2009 // TODO: Set density code, based on operation
2010 //
2011
2012 cdData->u1.BlockDescriptor.DensityCode = 0;
2013
2014
2015 //
2016 // Move error page into dataBuffer.
2017 //
2018
2019 RtlCopyMemory(srb->DataBuffer, &cdData->u1.Header, transferByteCount);
2020
2021
2022 //
2023 // Build and send a mode select to switch into raw mode.
2024 //
2025
2026 srb->SrbFlags = deviceExtension->SrbFlags;
2027 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_OUT);
2028 srb->DataTransferLength = transferByteCount;
2029 srb->TimeOutValue = deviceExtension->TimeOutValue * 2;
2030
2031 if (use6Byte) {
2032 srb->CdbLength = 6;
2033 cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
2034 cdb->MODE_SELECT.PFBit = 1;
2035 cdb->MODE_SELECT.ParameterListLength = (UCHAR)transferByteCount;
2036 } else {
2037
2038 srb->CdbLength = 10;
2039 cdb->MODE_SELECT10.OperationCode = SCSIOP_MODE_SELECT10;
2040 cdb->MODE_SELECT10.PFBit = 1;
2041 cdb->MODE_SELECT10.ParameterListLength[0] = (UCHAR)(transferByteCount >> 8);
2042 cdb->MODE_SELECT10.ParameterListLength[1] = (UCHAR)(transferByteCount & 0xFF);
2043 }
2044
2045 //
2046 // Update completion routine.
2047 //
2048
2049 IoSetCompletionRoutine(irp2,
2050 CdRomSwitchModeCompletion,
2051 srb,
2052 TRUE,
2053 TRUE,
2054 TRUE);
2055
2056 }
2057
2058 } else {
2059
2060 PRAW_READ_INFO rawReadInfo =
2061 (PRAW_READ_INFO)currentIrpStack->Parameters.DeviceIoControl.Type3InputBuffer;
2062 ULONG startingSector;
2063
2064 //
2065 // Free the recently allocated irp, as we don't need it.
2066 //
2067
2068 IoFreeIrp(irp2);
2069
2070 cdb = (PCDB)srb->Cdb;
2071 RtlZeroMemory(cdb, 12);
2072
2073
2074 //
2075 // Calculate starting offset.
2076 //
2077
2078 startingSector = (ULONG)(rawReadInfo->DiskOffset.QuadPart >> deviceExtension->SectorShift);
2079 transferByteCount = rawReadInfo->SectorCount * RAW_SECTOR_SIZE;
2080
2081
2082 srb->OriginalRequest = Irp;
2083 srb->SrbFlags = deviceExtension->SrbFlags;
2084 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN);
2085 srb->DataTransferLength = transferByteCount;
2086 srb->TimeOutValue = deviceExtension->TimeOutValue;
2087 srb->DataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
2088 srb->CdbLength = 12;
2089 srb->SrbStatus = srb->ScsiStatus = 0;
2090
2091 //
2092 // Fill in CDB fields.
2093 //
2094
2095 cdb = (PCDB)srb->Cdb;
2096
2097
2098 cdb->READ_CD.TransferBlocks[2] = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
2099 cdb->READ_CD.TransferBlocks[1] = (UCHAR) (rawReadInfo->SectorCount >> 8 );
2100 cdb->READ_CD.TransferBlocks[0] = (UCHAR) (rawReadInfo->SectorCount >> 16);
2101
2102
2103 cdb->READ_CD.StartingLBA[3] = (UCHAR) (startingSector & 0xFF);
2104 cdb->READ_CD.StartingLBA[2] = (UCHAR) ((startingSector >> 8));
2105 cdb->READ_CD.StartingLBA[1] = (UCHAR) ((startingSector >> 16));
2106 cdb->READ_CD.StartingLBA[0] = (UCHAR) ((startingSector >> 24));
2107
2108 //
2109 // Setup cdb depending upon the sector type we want.
2110 //
2111
2112 switch (rawReadInfo->TrackMode) {
2113 case CDDA:
2114
2115 cdb->READ_CD.ExpectedSectorType = CD_DA_SECTOR;
2116 cdb->READ_CD.IncludeUserData = 1;
2117 cdb->READ_CD.HeaderCode = 3;
2118 cdb->READ_CD.IncludeSyncData = 1;
2119 break;
2120
2121 case YellowMode2:
2122
2123 cdb->READ_CD.ExpectedSectorType = YELLOW_MODE2_SECTOR;
2124 cdb->READ_CD.IncludeUserData = 1;
2125 cdb->READ_CD.HeaderCode = 1;
2126 cdb->READ_CD.IncludeSyncData = 1;
2127 break;
2128
2129 case XAForm2:
2130
2131 cdb->READ_CD.ExpectedSectorType = FORM2_MODE2_SECTOR;
2132 cdb->READ_CD.IncludeUserData = 1;
2133 cdb->READ_CD.HeaderCode = 3;
2134 cdb->READ_CD.IncludeSyncData = 1;
2135 break;
2136
2137 default:
2138 Irp->IoStatus.Information = 0;
2139 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
2140 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2141 ExFreePool(senseBuffer);
2142 ExFreePool(srb);
2143 IoFreeIrp(irp2);
2144 IoStartNextPacket(DeviceObject, FALSE);
2145 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp, Irp->IoStatus.Status, __LINE__));
2146 return;
2147 }
2148
2149 cdb->READ_CD.OperationCode = SCSIOP_READ_CD;
2150
2151 nextIrpStack->MajorFunction = IRP_MJ_SCSI;
2152 nextIrpStack->Parameters.Scsi.Srb = srb;
2153
2154 if (!(nextIrpStack->Parameters.Others.Argument1)) {
2155
2156 //
2157 // Only jam this in if it doesn't exist. The completion routines can
2158 // call StartIo directly in the case of retries and resetting it will
2159 // cause infinite loops.
2160 //
2161
2162 nextIrpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES;
2163 }
2164
2165 //
2166 // Set up IoCompletion routine address.
2167 //
2168
2169 IoSetCompletionRoutine(Irp,
2170 CdRomXACompletion,
2171 srb,
2172 TRUE,
2173 TRUE,
2174 TRUE);
2175
2176 IoCallDriver(deviceExtension->PortDeviceObject, Irp);
2177 return;
2178
2179 }
2180
2181 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2182 return;
2183 }
2184
2185 case IOCTL_CDROM_GET_DRIVE_GEOMETRY: {
2186
2187 //
2188 // Issue ReadCapacity to update device extension
2189 // with information for current media.
2190 //
2191
2192 DebugPrint((3,
2193 "CdRomStartIo: Get drive capacity\n"));
2194
2195 //
2196 // setup remaining srb and cdb parameters.
2197 //
2198
2199 srb->SrbFlags = deviceExtension->SrbFlags;
2200 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN);
2201 srb->DataTransferLength = sizeof(READ_CAPACITY_DATA);
2202 srb->CdbLength = 10;
2203 srb->TimeOutValue = deviceExtension->TimeOutValue;
2204
2205 dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned, sizeof(READ_CAPACITY_DATA));
2206 if (!dataBuffer) {
2207 Irp->IoStatus.Information = 0;
2208 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2209 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2210 ExFreePool(senseBuffer);
2211 ExFreePool(srb);
2212 IoFreeIrp(irp2);
2213 IoStartNextPacket(DeviceObject, FALSE);
2214 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp, Irp->IoStatus.Status, __LINE__));
2215 return;
2216
2217 }
2218
2219 irp2->MdlAddress = IoAllocateMdl(dataBuffer,
2220 sizeof(READ_CAPACITY_DATA),
2221 FALSE,
2222 FALSE,
2223 (PIRP) NULL);
2224
2225 if (!irp2->MdlAddress) {
2226 Irp->IoStatus.Information = 0;
2227 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2228 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2229 ExFreePool(senseBuffer);
2230 ExFreePool(srb);
2231 ExFreePool(dataBuffer);
2232 IoFreeIrp(irp2);
2233 IoStartNextPacket(DeviceObject, FALSE);
2234 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp, Irp->IoStatus.Status, __LINE__));
2235 return;
2236 }
2237
2238 //
2239 // Prepare the MDL
2240 //
2241
2242 MmBuildMdlForNonPagedPool(irp2->MdlAddress);
2243
2244 srb->DataBuffer = dataBuffer;
2245 cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
2246
2247 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2248 return;
2249 }
2250
2251 case IOCTL_CDROM_CHECK_VERIFY: {
2252
2253 //
2254 // Since a test unit ready is about to be performed, reset the timer
2255 // value to decrease the opportunities for it to race with this code.
2256 //
2257
2258 cdData->MediaChangeCountDown = MEDIA_CHANGE_DEFAULT_TIME;
2259
2260 //
2261 // Set up the SRB/CDB
2262 //
2263
2264 srb->CdbLength = 6;
2265 cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
2266 srb->TimeOutValue = deviceExtension->TimeOutValue * 2;
2267 srb->SrbFlags = deviceExtension->SrbFlags;
2268 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_DATA_TRANSFER);
2269
2270 DebugPrint((2, "ScsiCdRomStartIo: [%lx] Sending CHECK_VERIFY irp %lx\n", Irp, irp2));
2271 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2272 return;
2273 }
2274
2275 case IOCTL_CDROM_GET_LAST_SESSION:
2276
2277 //
2278 // Set format to return first and last session numbers.
2279 //
2280
2281 cdb->READ_TOC.Format = GET_LAST_SESSION;
2282
2283 //
2284 // Fall through to READ TOC code.
2285 //
2286
2287 case IOCTL_CDROM_READ_TOC: {
2288
2289
2290 if (currentIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_READ_TOC) {
2291
2292 //
2293 // Use MSF addressing if not request for session information.
2294 //
2295
2296 cdb->READ_TOC.Msf = CDB_USE_MSF;
2297 }
2298
2299 //
2300 // Set size of TOC structure.
2301 //
2302
2303 transferByteCount =
2304 currentIrpStack->Parameters.Read.Length >
2305 sizeof(CDROM_TOC) ? sizeof(CDROM_TOC):
2306 currentIrpStack->Parameters.Read.Length;
2307
2308 cdb->READ_TOC.AllocationLength[0] = (UCHAR) (transferByteCount >> 8);
2309 cdb->READ_TOC.AllocationLength[1] = (UCHAR) (transferByteCount & 0xFF);
2310
2311 cdb->READ_TOC.Control = 0;
2312
2313 //
2314 // Start at beginning of disc.
2315 //
2316
2317 cdb->READ_TOC.StartingTrack = 0;
2318
2319 //
2320 // setup remaining srb and cdb parameters.
2321 //
2322
2323 srb->SrbFlags = deviceExtension->SrbFlags;
2324 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN);
2325 srb->DataTransferLength = transferByteCount;
2326 srb->CdbLength = 10;
2327 srb->TimeOutValue = deviceExtension->TimeOutValue;
2328
2329 dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned, transferByteCount);
2330 if (!dataBuffer) {
2331 Irp->IoStatus.Information = 0;
2332 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2333 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2334 ExFreePool(senseBuffer);
2335 ExFreePool(srb);
2336 IoFreeIrp(irp2);
2337 IoStartNextPacket(DeviceObject, FALSE);
2338 return;
2339
2340 }
2341
2342 irp2->MdlAddress = IoAllocateMdl(dataBuffer,
2343 transferByteCount,
2344 FALSE,
2345 FALSE,
2346 (PIRP) NULL);
2347
2348 if (!irp2->MdlAddress) {
2349 Irp->IoStatus.Information = 0;
2350 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2351 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2352 ExFreePool(senseBuffer);
2353 ExFreePool(srb);
2354 ExFreePool(dataBuffer);
2355 IoFreeIrp(irp2);
2356 IoStartNextPacket(DeviceObject, FALSE);
2357 return;
2358 }
2359
2360 //
2361 // Prepare the MDL
2362 //
2363
2364 MmBuildMdlForNonPagedPool(irp2->MdlAddress);
2365
2366 srb->DataBuffer = dataBuffer;
2367 cdb->READ_TOC.OperationCode = SCSIOP_READ_TOC;
2368
2369 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2370 return;
2371
2372 }
2373
2374 case IOCTL_CDROM_PLAY_AUDIO_MSF: {
2375
2376 PCDROM_PLAY_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
2377
2378 //
2379 // Set up the SRB/CDB
2380 //
2381
2382 srb->CdbLength = 10;
2383 cdb->PLAY_AUDIO_MSF.OperationCode = SCSIOP_PLAY_AUDIO_MSF;
2384
2385 cdb->PLAY_AUDIO_MSF.StartingM = inputBuffer->StartingM;
2386 cdb->PLAY_AUDIO_MSF.StartingS = inputBuffer->StartingS;
2387 cdb->PLAY_AUDIO_MSF.StartingF = inputBuffer->StartingF;
2388
2389 cdb->PLAY_AUDIO_MSF.EndingM = inputBuffer->EndingM;
2390 cdb->PLAY_AUDIO_MSF.EndingS = inputBuffer->EndingS;
2391 cdb->PLAY_AUDIO_MSF.EndingF = inputBuffer->EndingF;
2392
2393 srb->TimeOutValue = deviceExtension->TimeOutValue;
2394 srb->SrbFlags = deviceExtension->SrbFlags;
2395 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_DATA_TRANSFER);
2396
2397 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2398 return;
2399
2400 }
2401
2402 case IOCTL_CDROM_READ_Q_CHANNEL: {
2403
2404 PCDROM_SUB_Q_DATA_FORMAT inputBuffer =
2405 Irp->AssociatedIrp.SystemBuffer;
2406
2407 //
2408 // Allocate buffer for subq channel information.
2409 //
2410
2411 dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
2412 sizeof(SUB_Q_CHANNEL_DATA));
2413
2414 if (!dataBuffer) {
2415 Irp->IoStatus.Information = 0;
2416 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2417 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2418 ExFreePool(senseBuffer);
2419 ExFreePool(srb);
2420 IoFreeIrp(irp2);
2421 IoStartNextPacket(DeviceObject, FALSE);
2422 return;
2423
2424 }
2425
2426 irp2->MdlAddress = IoAllocateMdl(dataBuffer,
2427 transferByteCount,
2428 FALSE,
2429 FALSE,
2430 (PIRP) NULL);
2431
2432 if (!irp2->MdlAddress) {
2433 Irp->IoStatus.Information = 0;
2434 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2435 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2436 ExFreePool(senseBuffer);
2437 ExFreePool(srb);
2438 ExFreePool(dataBuffer);
2439 IoFreeIrp(irp2);
2440 IoStartNextPacket(DeviceObject, FALSE);
2441 return;
2442 }
2443
2444 //
2445 // Prepare the MDL
2446 //
2447
2448 MmBuildMdlForNonPagedPool(irp2->MdlAddress);
2449
2450 srb->DataBuffer = dataBuffer;
2451
2452 //
2453 // Always logical unit 0, but only use MSF addressing
2454 // for IOCTL_CDROM_CURRENT_POSITION
2455 //
2456
2457 if (inputBuffer->Format==IOCTL_CDROM_CURRENT_POSITION)
2458 cdb->SUBCHANNEL.Msf = CDB_USE_MSF;
2459
2460 //
2461 // Return subchannel data
2462 //
2463
2464 cdb->SUBCHANNEL.SubQ = CDB_SUBCHANNEL_BLOCK;
2465
2466 //
2467 // Specify format of informatin to return
2468 //
2469
2470 cdb->SUBCHANNEL.Format = inputBuffer->Format;
2471
2472 //
2473 // Specify which track to access (only used by Track ISRC reads)
2474 //
2475
2476 if (inputBuffer->Format==IOCTL_CDROM_TRACK_ISRC) {
2477 cdb->SUBCHANNEL.TrackNumber = inputBuffer->Track;
2478 }
2479
2480 //
2481 // Set size of channel data -- however, this is dependent on
2482 // what information we are requesting (which Format)
2483 //
2484
2485 switch( inputBuffer->Format ) {
2486
2487 case IOCTL_CDROM_CURRENT_POSITION:
2488 transferByteCount = sizeof(SUB_Q_CURRENT_POSITION);
2489 break;
2490
2491 case IOCTL_CDROM_MEDIA_CATALOG:
2492 transferByteCount = sizeof(SUB_Q_MEDIA_CATALOG_NUMBER);
2493 break;
2494
2495 case IOCTL_CDROM_TRACK_ISRC:
2496 transferByteCount = sizeof(SUB_Q_TRACK_ISRC);
2497 break;
2498 }
2499
2500 cdb->SUBCHANNEL.AllocationLength[0] = (UCHAR) (transferByteCount >> 8);
2501 cdb->SUBCHANNEL.AllocationLength[1] = (UCHAR) (transferByteCount & 0xFF);
2502 cdb->SUBCHANNEL.OperationCode = SCSIOP_READ_SUB_CHANNEL;
2503 srb->SrbFlags = deviceExtension->SrbFlags;
2504 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN);
2505 srb->DataTransferLength = transferByteCount;
2506 srb->CdbLength = 10;
2507 srb->TimeOutValue = deviceExtension->TimeOutValue;
2508
2509 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2510 return;
2511
2512 }
2513
2514 case IOCTL_CDROM_PAUSE_AUDIO: {
2515
2516 cdb->PAUSE_RESUME.OperationCode = SCSIOP_PAUSE_RESUME;
2517 cdb->PAUSE_RESUME.Action = CDB_AUDIO_PAUSE;
2518
2519 srb->CdbLength = 10;
2520 srb->TimeOutValue = deviceExtension->TimeOutValue;
2521 srb->SrbFlags = deviceExtension->SrbFlags;
2522 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_DATA_TRANSFER);
2523
2524 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2525 return;
2526 }
2527
2528 case IOCTL_CDROM_RESUME_AUDIO: {
2529
2530 cdb->PAUSE_RESUME.OperationCode = SCSIOP_PAUSE_RESUME;
2531 cdb->PAUSE_RESUME.Action = CDB_AUDIO_RESUME;
2532
2533 srb->CdbLength = 10;
2534 srb->TimeOutValue = deviceExtension->TimeOutValue;
2535 srb->SrbFlags = deviceExtension->SrbFlags;
2536 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_DATA_TRANSFER);
2537
2538 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2539 return;
2540 }
2541
2542 case IOCTL_CDROM_SEEK_AUDIO_MSF: {
2543
2544 PCDROM_SEEK_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
2545 ULONG logicalBlockAddress;
2546
2547 logicalBlockAddress = MSF_TO_LBA(inputBuffer->M, inputBuffer->S, inputBuffer->F);
2548
2549 cdb->SEEK.OperationCode = SCSIOP_SEEK;
2550 cdb->SEEK.LogicalBlockAddress[0] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte3;
2551 cdb->SEEK.LogicalBlockAddress[1] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte2;
2552 cdb->SEEK.LogicalBlockAddress[2] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte1;
2553 cdb->SEEK.LogicalBlockAddress[3] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte0;
2554
2555 srb->CdbLength = 10;
2556 srb->TimeOutValue = deviceExtension->TimeOutValue;
2557 srb->SrbFlags = deviceExtension->SrbFlags;
2558 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_DATA_TRANSFER);
2559
2560 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2561 return;
2562
2563 }
2564
2565 case IOCTL_CDROM_STOP_AUDIO: {
2566
2567 cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
2568 cdb->START_STOP.Immediate = 1;
2569 cdb->START_STOP.Start = 0;
2570 cdb->START_STOP.LoadEject = 0;
2571
2572 srb->CdbLength = 6;
2573 srb->TimeOutValue = deviceExtension->TimeOutValue;
2574
2575 srb->SrbFlags = deviceExtension->SrbFlags;
2576 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_DATA_TRANSFER);
2577
2578 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2579 return;
2580 }
2581
2582 case IOCTL_CDROM_GET_CONTROL: {
2583 //
2584 // Allocate buffer for volume control information.
2585 //
2586
2587 dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
2588 MODE_DATA_SIZE);
2589
2590 if (!dataBuffer) {
2591 Irp->IoStatus.Information = 0;
2592 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2593 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2594 ExFreePool(senseBuffer);
2595 ExFreePool(srb);
2596 IoFreeIrp(irp2);
2597 IoStartNextPacket(DeviceObject, FALSE);
2598 return;
2599
2600 }
2601
2602 irp2->MdlAddress = IoAllocateMdl(dataBuffer,
2603 MODE_DATA_SIZE,
2604 FALSE,
2605 FALSE,
2606 (PIRP) NULL);
2607
2608 if (!irp2->MdlAddress) {
2609 Irp->IoStatus.Information = 0;
2610 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2611 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2612 ExFreePool(senseBuffer);
2613 ExFreePool(srb);
2614 ExFreePool(dataBuffer);
2615 IoFreeIrp(irp2);
2616 IoStartNextPacket(DeviceObject, FALSE);
2617 return;
2618 }
2619
2620 //
2621 // Prepare the MDL
2622 //
2623
2624 MmBuildMdlForNonPagedPool(irp2->MdlAddress);
2625 srb->DataBuffer = dataBuffer;
2626
2627 RtlZeroMemory(dataBuffer, MODE_DATA_SIZE);
2628
2629 //
2630 // Setup for either 6 or 10 byte CDBs.
2631 //
2632
2633 if (use6Byte) {
2634
2635 cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
2636 cdb->MODE_SENSE.PageCode = CDROM_AUDIO_CONTROL_PAGE;
2637 cdb->MODE_SENSE.AllocationLength = MODE_DATA_SIZE;
2638
2639 //
2640 // Disable block descriptors.
2641 //
2642
2643 cdb->MODE_SENSE.Dbd = TRUE;
2644
2645 srb->CdbLength = 6;
2646 } else {
2647
2648 cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
2649 cdb->MODE_SENSE10.PageCode = CDROM_AUDIO_CONTROL_PAGE;
2650 cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(MODE_DATA_SIZE >> 8);
2651 cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(MODE_DATA_SIZE & 0xFF);
2652
2653 //
2654 // Disable block descriptors.
2655 //
2656
2657 cdb->MODE_SENSE10.Dbd = TRUE;
2658
2659 srb->CdbLength = 10;
2660 }
2661
2662 srb->TimeOutValue = deviceExtension->TimeOutValue;
2663 srb->DataTransferLength = MODE_DATA_SIZE;
2664 srb->SrbFlags = deviceExtension->SrbFlags;
2665 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN);
2666
2667 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2668 return;
2669
2670 }
2671
2672 case IOCTL_CDROM_GET_VOLUME:
2673 case IOCTL_CDROM_SET_VOLUME: {
2674
2675 dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
2676 MODE_DATA_SIZE);
2677
2678 if (!dataBuffer) {
2679 Irp->IoStatus.Information = 0;
2680 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2681 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2682 ExFreePool(senseBuffer);
2683 ExFreePool(srb);
2684 IoFreeIrp(irp2);
2685 IoStartNextPacket(DeviceObject, FALSE);
2686 return;
2687 }
2688
2689 irp2->MdlAddress = IoAllocateMdl(dataBuffer,
2690 MODE_DATA_SIZE,
2691 FALSE,
2692 FALSE,
2693 (PIRP) NULL);
2694
2695 if (!irp2->MdlAddress) {
2696 Irp->IoStatus.Information = 0;
2697 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2698 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2699 ExFreePool(senseBuffer);
2700 ExFreePool(srb);
2701 ExFreePool(dataBuffer);
2702 IoFreeIrp(irp2);
2703 IoStartNextPacket(DeviceObject, FALSE);
2704 return;
2705 }
2706
2707 //
2708 // Prepare the MDL
2709 //
2710
2711 MmBuildMdlForNonPagedPool(irp2->MdlAddress);
2712 srb->DataBuffer = dataBuffer;
2713
2714 RtlZeroMemory(dataBuffer, MODE_DATA_SIZE);
2715
2716
2717 if (use6Byte) {
2718 cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
2719 cdb->MODE_SENSE.PageCode = CDROM_AUDIO_CONTROL_PAGE;
2720 cdb->MODE_SENSE.AllocationLength = MODE_DATA_SIZE;
2721
2722 srb->CdbLength = 6;
2723
2724 } else {
2725
2726 cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
2727 cdb->MODE_SENSE10.PageCode = CDROM_AUDIO_CONTROL_PAGE;
2728 cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(MODE_DATA_SIZE >> 8);
2729 cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(MODE_DATA_SIZE & 0xFF);
2730
2731 srb->CdbLength = 10;
2732 }
2733
2734 srb->TimeOutValue = deviceExtension->TimeOutValue;
2735 srb->DataTransferLength = MODE_DATA_SIZE;
2736 srb->SrbFlags = deviceExtension->SrbFlags;
2737 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN);
2738
2739 if (currentIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_SET_VOLUME) {
2740
2741 //
2742 // Setup a different completion routine as the mode sense data is needed in order
2743 // to send the mode select.
2744 //
2745
2746 IoSetCompletionRoutine(irp2,
2747 CdRomSetVolumeIntermediateCompletion,
2748 srb,
2749 TRUE,
2750 TRUE,
2751 TRUE);
2752
2753 }
2754
2755 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2756 return;
2757
2758 }
2759
2760 default:
2761
2762 //
2763 // Just complete the request - CdRomClassIoctlCompletion will take
2764 // care of it for us
2765 //
2766
2767 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2768 return;
2769
2770 } // end switch()
2771 }
2772
2773 //
2774 // If a read or an unhandled IRP_MJ_XX, end up here. The unhandled IRP_MJ's
2775 // are expected and composed of AutoRun Irps, at present.
2776 //
2777
2778 IoCallDriver(deviceExtension->PortDeviceObject, Irp);
2779 return;
2780 }
2781
2782
2783 NTSTATUS
2784 STDCALL
2785 ScsiCdRomReadVerification(
2786 IN PDEVICE_OBJECT DeviceObject,
2787 IN PIRP Irp
2788 )
2789
2790 /*++
2791
2792 Routine Description:
2793
2794 This is the entry called by the I/O system for read requests.
2795 It builds the SRB and sends it to the port driver.
2796
2797 Arguments:
2798
2799 DeviceObject - the system object for the device.
2800 Irp - IRP involved.
2801
2802 Return Value:
2803
2804 NT Status
2805
2806 --*/
2807
2808 {
2809 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
2810 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
2811 ULONG transferByteCount = currentIrpStack->Parameters.Read.Length;
2812 LARGE_INTEGER startingOffset = currentIrpStack->Parameters.Read.ByteOffset;
2813
2814 //
2815 // If the cd is playing music then reject this request.
2816 //
2817
2818 if (PLAY_ACTIVE(deviceExtension)) {
2819 Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
2820 return STATUS_DEVICE_BUSY;
2821 }
2822
2823 //
2824 // Verify parameters of this request.
2825 // Check that ending sector is on disc and
2826 // that number of bytes to transfer is a multiple of
2827 // the sector size.
2828 //
2829
2830 startingOffset.QuadPart = currentIrpStack->Parameters.Read.ByteOffset.QuadPart +
2831 transferByteCount;
2832
2833 if (!deviceExtension->DiskGeometry->BytesPerSector) {
2834 deviceExtension->DiskGeometry->BytesPerSector = 2048;
2835 }
2836
2837 if ((startingOffset.QuadPart > deviceExtension->PartitionLength.QuadPart) ||
2838 (transferByteCount & deviceExtension->DiskGeometry->BytesPerSector - 1)) {
2839
2840 DebugPrint((1,"ScsiCdRomRead: Invalid I/O parameters\n"));
2841 DebugPrint((1, "\toffset %x:%x, Length %x:%x\n",
2842 startingOffset.u.HighPart,
2843 startingOffset.u.LowPart,
2844 deviceExtension->PartitionLength.u.HighPart,
2845 deviceExtension->PartitionLength.u.LowPart));
2846 DebugPrint((1, "\tbps %x\n", deviceExtension->DiskGeometry->BytesPerSector));
2847
2848 //
2849 // Fail request with status of invalid parameters.
2850 //
2851
2852 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
2853
2854 return STATUS_INVALID_PARAMETER;
2855 }
2856
2857
2858 return STATUS_SUCCESS;
2859
2860 } // end ScsiCdRomReadVerification()
2861
2862
2863 NTSTATUS
2864 STDCALL
2865 CdRomDeviceControlCompletion(
2866 IN PDEVICE_OBJECT DeviceObject,
2867 IN PIRP Irp,
2868 IN PVOID Context
2869 )
2870 {
2871 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
2872 PDEVICE_EXTENSION physicalExtension = deviceExtension->PhysicalDevice->DeviceExtension;
2873 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
2874 PCDROM_DATA cdData = (PCDROM_DATA)(deviceExtension + 1);
2875 BOOLEAN use6Byte = cdData->XAFlags & XA_USE_6_BYTE;
2876 PIO_STACK_LOCATION realIrpStack;
2877 PIO_STACK_LOCATION realIrpNextStack;
2878 PSCSI_REQUEST_BLOCK srb = Context;
2879 PIRP realIrp = NULL;
2880 NTSTATUS status;
2881 BOOLEAN retry;
2882
2883 //
2884 // Extract the 'real' irp from the irpstack.
2885 //
2886
2887 realIrp = (PIRP) irpStack->Parameters.Others.Argument2;
2888 realIrpStack = IoGetCurrentIrpStackLocation(realIrp);
2889 realIrpNextStack = IoGetNextIrpStackLocation(realIrp);
2890
2891 //
2892 // Check SRB status for success of completing request.
2893 //
2894
2895 if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
2896
2897 DebugPrint((2,
2898 "CdRomDeviceControlCompletion: Irp %lx, Srb %lx Real Irp %lx Status %lx\n",
2899 Irp,
2900 srb,
2901 realIrp,
2902 srb->SrbStatus));
2903
2904 //
2905 // Release the queue if it is frozen.
2906 //
2907
2908 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
2909 DebugPrint((2, "CdRomDeviceControlCompletion: Releasing Queue\n"));
2910 ScsiClassReleaseQueue(DeviceObject);
2911 }
2912
2913
2914 retry = ScsiClassInterpretSenseInfo(DeviceObject,
2915 srb,
2916 irpStack->MajorFunction,
2917 irpStack->Parameters.DeviceIoControl.IoControlCode,
2918 MAXIMUM_RETRIES - ((ULONG)realIrpNextStack->Parameters.Others.Argument1),
2919 &status);
2920
2921 DebugPrint((2, "CdRomDeviceControlCompletion: IRP will %sbe retried\n",
2922 (retry ? "" : "not ")));
2923
2924 //
2925 // Some of the Device Controls need special cases on non-Success status's.
2926 //
2927
2928 if (realIrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) {
2929 if ((realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_GET_LAST_SESSION) ||
2930 (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_READ_TOC) ||
2931 (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_GET_CONTROL) ||
2932 (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_GET_VOLUME)) {
2933
2934 if (status == STATUS_DATA_OVERRUN) {
2935 status = STATUS_SUCCESS;
2936 retry = FALSE;
2937 }
2938 }
2939
2940 if (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_READ_Q_CHANNEL) {
2941 PLAY_ACTIVE(deviceExtension) = FALSE;
2942 }
2943 }
2944
2945 //
2946 // If the status is verified required and the this request
2947 // should bypass verify required then retry the request.
2948 //
2949
2950 if (realIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME &&
2951 status == STATUS_VERIFY_REQUIRED) {
2952
2953 if (((realIrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) ||
2954 (realIrpStack->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL)) &&
2955 (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_CHECK_VERIFY)) {
2956
2957 //
2958 // Update the geometry information, as the media could have changed.
2959 // The completion routine for this will complete the real irp and start
2960 // the next packet.
2961 //
2962
2963 status = CdRomUpdateCapacity(deviceExtension,realIrp, NULL);
2964 DebugPrint((2, "CdRomDeviceControlCompletion: [%lx] CdRomUpdateCapacity completed with status %lx\n", realIrp, status));
2965 ASSERT(status == STATUS_PENDING);
2966
2967 return STATUS_MORE_PROCESSING_REQUIRED;
2968
2969 } else {
2970
2971 status = STATUS_IO_DEVICE_ERROR;
2972 retry = TRUE;
2973 }
2974
2975 }
2976
2977 if (retry && (realIrpNextStack->Parameters.Others.Argument1 = (ULONG)realIrpNextStack->Parameters.Others.Argument1-1)) {
2978
2979
2980 if (((ULONG)realIrpNextStack->Parameters.Others.Argument1)) {
2981
2982 //
2983 // Retry request.
2984 //
2985
2986 DebugPrint((1, "Retry request %lx - Calling StartIo\n", Irp));
2987
2988
2989 ExFreePool(srb->SenseInfoBuffer);
2990 if (srb->DataBuffer) {
2991 ExFreePool(srb->DataBuffer);
2992 }
2993 ExFreePool(srb);
2994 if (Irp->MdlAddress) {
2995 IoFreeMdl(Irp->MdlAddress);
2996 }
2997
2998 IoFreeIrp(Irp);
2999
3000 //
3001 // Call StartIo directly since IoStartNextPacket hasn't been called,
3002 // the serialisation is still intact.
3003 //
3004
3005 ScsiCdRomStartIo(DeviceObject, realIrp);
3006 return STATUS_MORE_PROCESSING_REQUIRED;
3007
3008 }
3009
3010 //
3011 // Exhausted retries. Fall through and complete the request with the appropriate status.
3012 //
3013
3014 }
3015 } else {
3016
3017 //
3018 // Set status for successful request.
3019 //
3020
3021 status = STATUS_SUCCESS;
3022 }
3023
3024 if (NT_SUCCESS(status)) {
3025
3026 switch (realIrpStack->Parameters.DeviceIoControl.IoControlCode) {
3027
3028 case IOCTL_CDROM_GET_DRIVE_GEOMETRY: {
3029
3030 PREAD_CAPACITY_DATA readCapacityBuffer = srb->DataBuffer;
3031 ULONG lastSector;
3032 ULONG bps;
3033 ULONG lastBit;
3034 ULONG tmp;
3035
3036 //
3037 // Swizzle bytes from Read Capacity and translate into
3038 // the necessary geometry information in the device extension.
3039 //
3040
3041 tmp = readCapacityBuffer->BytesPerBlock;
3042 ((PFOUR_BYTE)&bps)->Byte0 = ((PFOUR_BYTE)&tmp)->Byte3;
3043 ((PFOUR_BYTE)&bps)->Byte1 = ((PFOUR_BYTE)&tmp)->Byte2;
3044 ((PFOUR_BYTE)&bps)->Byte2 = ((PFOUR_BYTE)&tmp)->Byte1;
3045 ((PFOUR_BYTE)&bps)->Byte3 = ((PFOUR_BYTE)&tmp)->Byte0;
3046
3047 //
3048 // Insure that bps is a power of 2.
3049 // This corrects a problem with the HP 4020i CDR where it
3050 // returns an incorrect number for bytes per sector.
3051 //
3052
3053 if (!bps) {
3054 bps = 2048;
3055 } else {
3056 lastBit = (ULONG) -1;
3057 while (bps) {
3058 lastBit++;
3059 bps = bps >> 1;
3060 }
3061
3062 bps = 1 << lastBit;
3063 }
3064 deviceExtension->DiskGeometry->BytesPerSector = bps;
3065
3066 DebugPrint((2,
3067 "CdRomDeviceControlCompletion: Calculated bps %#x\n",
3068 deviceExtension->DiskGeometry->BytesPerSector));
3069
3070 //
3071 // Copy last sector in reverse byte order.
3072 //
3073
3074 tmp = readCapacityBuffer->LogicalBlockAddress;
3075 ((PFOUR_BYTE)&lastSector)->Byte0 = ((PFOUR_BYTE)&tmp)->Byte3;
3076 ((PFOUR_BYTE)&lastSector)->Byte1 = ((PFOUR_BYTE)&tmp)->Byte2;
3077 ((PFOUR_BYTE)&lastSector)->Byte2 = ((PFOUR_BYTE)&tmp)->Byte1;
3078 ((PFOUR_BYTE)&lastSector)->Byte3 = ((PFOUR_BYTE)&tmp)->Byte0;
3079
3080 //
3081 // Calculate sector to byte shift.
3082 //
3083
3084 WHICH_BIT(bps, deviceExtension->SectorShift);
3085
3086 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Sector size is %d\n",
3087 deviceExtension->DiskGeometry->BytesPerSector));
3088
3089 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Number of Sectors is %d\n",
3090 lastSector + 1));
3091
3092 //
3093 // Calculate media capacity in bytes.
3094 //
3095
3096 deviceExtension->PartitionLength.QuadPart = (LONGLONG)(lastSector + 1);
3097
3098 //
3099 // Calculate number of cylinders.
3100 //
3101
3102 deviceExtension->DiskGeometry->Cylinders.QuadPart = (LONGLONG)((lastSector + 1)/(32 * 64));
3103
3104 deviceExtension->PartitionLength.QuadPart =
3105 (deviceExtension->PartitionLength.QuadPart << deviceExtension->SectorShift);
3106
3107 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
3108
3109 //
3110 // This device supports removable media.
3111 //
3112
3113 deviceExtension->DiskGeometry->MediaType = RemovableMedia;
3114
3115 } else {
3116
3117 //
3118 // Assume media type is fixed disk.
3119 //
3120
3121 deviceExtension->DiskGeometry->MediaType = FixedMedia;
3122 }
3123
3124 //
3125 // Assume sectors per track are 32;
3126 //
3127
3128 deviceExtension->DiskGeometry->SectorsPerTrack = 32;
3129
3130 //
3131 // Assume tracks per cylinder (number of heads) is 64.
3132 //
3133
3134 deviceExtension->DiskGeometry->TracksPerCylinder = 64;
3135
3136 //
3137 // Copy the device extension's geometry info into the user buffer.
3138 //
3139
3140 RtlMoveMemory(realIrp->AssociatedIrp.SystemBuffer,
3141 deviceExtension->DiskGeometry,
3142 sizeof(DISK_GEOMETRY));
3143
3144 //
3145 // update information field.
3146 //
3147
3148 realIrp->IoStatus.Information = sizeof(DISK_GEOMETRY);
3149 break;
3150 }
3151
3152 case IOCTL_CDROM_CHECK_VERIFY:
3153
3154 if((realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_CHECK_VERIFY) &&
3155 (realIrpStack->Parameters.DeviceIoControl.OutputBufferLength)) {
3156
3157 *((PULONG)realIrp->AssociatedIrp.SystemBuffer) =
3158 physicalExtension->MediaChangeCount;
3159 realIrp->IoStatus.Information = sizeof(ULONG);
3160 } else {
3161 realIrp->IoStatus.Information = 0;
3162 }
3163
3164 DebugPrint((2, "CdRomDeviceControlCompletion: [%lx] completing CHECK_VERIFY buddy irp %lx\n", realIrp, Irp));
3165 break;
3166
3167 case IOCTL_CDROM_GET_LAST_SESSION:
3168 case IOCTL_CDROM_READ_TOC: {
3169
3170 PCDROM_TOC toc = srb->DataBuffer;
3171
3172 //
3173 // Copy the device extension's geometry info into the user buffer.
3174 //
3175
3176 RtlMoveMemory(realIrp->AssociatedIrp.SystemBuffer,
3177 toc,
3178 srb->DataTransferLength);
3179
3180 //
3181 // update information field.
3182 //
3183
3184 realIrp->IoStatus.Information = srb->DataTransferLength;
3185 break;
3186 }
3187
3188 case IOCTL_CDROM_PLAY_AUDIO_MSF:
3189
3190 PLAY_ACTIVE(deviceExtension) = TRUE;
3191
3192 break;
3193
3194 case IOCTL_CDROM_READ_Q_CHANNEL: {
3195
3196 PSUB_Q_CHANNEL_DATA userChannelData = realIrp->AssociatedIrp.SystemBuffer;
3197 PCDROM_SUB_Q_DATA_FORMAT inputBuffer = realIrp->AssociatedIrp.SystemBuffer;
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 STDCALL
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)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 = (ULONG)realIrpNextStack->Parameters.Others.Argument1-1)) {
3503
3504 if (((ULONG)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 STDCALL
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)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 = (ULONG)realIrpNextStack->Parameters.Others.Argument1-1)) {
3829
3830 if (((ULONG)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 STDCALL
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)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 = (ULONG)irpNextStack->Parameters.Others.Argument1-1)) {
4205
4206 if (((ULONG)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 STDCALL
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 STDCALL
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(InquiryData->VendorId, "HITACHI CDR-1750S", strlen("HITACHI CDR-1750S")) == 0 ||
4875 strncmp(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 STDCALL
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) (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 STDCALL
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 STDCALL
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 STDCALL
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 STDCALL
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 STDCALL
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 count;
5881
5882 //
5883 // Decrement the countdown timer and put the IRP back in the list.
5884 //
5885
5886 count = (ULONG) 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 STDCALL
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 UCHAR 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 STDCALL
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 STDCALL
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 STDCALL
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 STDCALL
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 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) 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 STDCALL
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 STDCALL
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 }