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