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