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