[CDROM]
[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;