merge trunk head (37902)
[reactos.git] / reactos / drivers / storage / class / cdrom / cdrom.c
1 /*
2 * PROJECT: ReactOS Storage Stack
3 * LICENSE: DDK - see license.txt in the root dir
4 * FILE: drivers/storage/cdrom/cdrom.c
5 * PURPOSE: CDROM driver
6 * PROGRAMMERS: Based on a source code sample from Microsoft NT4 DDK
7 */
8
9 #include <ntddk.h>
10 #include <scsi.h>
11 #include <ntddscsi.h>
12 #include <ntdddisk.h>
13 #include <ntddcdrm.h>
14 #include <include/class2.h>
15 #include <stdio.h>
16
17 //#define NDEBUG
18 #include <debug.h>
19
20 #define CDB12GENERIC_LENGTH 12
21
22 typedef struct _XA_CONTEXT {
23
24 //
25 // Pointer to the device object.
26 //
27
28 PDEVICE_OBJECT DeviceObject;
29
30 //
31 // Pointer to the original request when
32 // a mode select must be sent.
33 //
34
35 PIRP OriginalRequest;
36
37 //
38 // Pointer to the mode select srb.
39 //
40
41 PSCSI_REQUEST_BLOCK Srb;
42 } XA_CONTEXT, *PXA_CONTEXT;
43
44 typedef struct _ERROR_RECOVERY_DATA {
45 MODE_PARAMETER_HEADER Header;
46 MODE_PARAMETER_BLOCK BlockDescriptor;
47 MODE_READ_RECOVERY_PAGE ReadRecoveryPage;
48 } ERROR_RECOVERY_DATA, *PERROR_RECOVERY_DATA;
49
50 typedef struct _ERROR_RECOVERY_DATA10 {
51 MODE_PARAMETER_HEADER10 Header10;
52 MODE_PARAMETER_BLOCK BlockDescriptor10;
53 MODE_READ_RECOVERY_PAGE ReadRecoveryPage10;
54 } ERROR_RECOVERY_DATA10, *PERROR_RECOVERY_DATA10;
55
56 //
57 // CdRom specific addition to device extension.
58 //
59
60 typedef struct _CDROM_DATA {
61
62 //
63 // Indicates whether an audio play operation
64 // is currently being performed.
65 //
66
67 BOOLEAN PlayActive;
68
69 //
70 // Indicates whether the blocksize used for user data
71 // is 2048 or 2352.
72 //
73
74 BOOLEAN RawAccess;
75
76 //
77 // Indicates whether 6 or 10 byte mode sense/select
78 // should be used.
79 //
80
81 USHORT XAFlags;
82
83 //
84 // Storage for the error recovery page. This is used
85 // as an easy method to switch block sizes.
86 //
87
88 union {
89 ERROR_RECOVERY_DATA u1;
90 ERROR_RECOVERY_DATA10 u2;
91 };
92
93
94 //
95 // Pointer to the original irp for the raw read.
96 //
97
98 PIRP SavedReadIrp;
99
100 //
101 // Used to protect accesses to the RawAccess flag.
102 //
103
104 KSPIN_LOCK FormSpinLock;
105
106 //
107 // Even if media change support is requested, there are some devices
108 // that are not supported. This flag will indicate that such a device
109 // is present when it is FALSE.
110 //
111
112 BOOLEAN MediaChangeSupported;
113
114 //
115 // The media change event is being supported. The media change timer
116 // should be running whenever this is true.
117 //
118
119 BOOLEAN MediaChange;
120
121 //
122 // The timer value to support media change events. This is a countdown
123 // value used to determine when to poll the device for a media change.
124 // The max value for the timer is 255 seconds.
125 //
126
127 UCHAR MediaChangeCountDown;
128
129 #ifdef DBG
130 //
131 // Second timer to keep track of how long the media change IRP has been
132 // in use. If this value exceeds the timeout (#defined) then we should
133 // print out a message to the user and set the MediaChangeIrpLost flag
134 //
135
136 SHORT MediaChangeIrpTimeInUse;
137
138 //
139 // Set by CdRomTickHandler when we determine that the media change irp has
140 // been lost
141 //
142
143 BOOLEAN MediaChangeIrpLost;
144 #endif
145
146 UCHAR PadReserve; // use this for new flags.
147
148 //
149 // An IRP is allocated and kept for the duration that media change
150 // detection is in effect. If this is NULL and MediaChange is TRUE,
151 // the detection is in progress. This should always be NULL when
152 // MediaChange is FALSE.
153 //
154
155 PIRP MediaChangeIrp;
156
157 //
158 // The timer work list is a collection of IRPS that are prepared for
159 // submission, but need to allow some time to pass before they are
160 // run.
161 //
162
163 LIST_ENTRY TimerIrpList;
164 KSPIN_LOCK TimerIrpSpinLock;
165
166 } CDROM_DATA, *PCDROM_DATA;
167
168 #define DEVICE_EXTENSION_SIZE sizeof(DEVICE_EXTENSION) + sizeof(CDROM_DATA)
169 #define SCSI_CDROM_TIMEOUT 10
170 #define SCSI_CHANGER_BONUS_TIMEOUT 10
171 #define HITACHI_MODE_DATA_SIZE 12
172 #define MODE_DATA_SIZE 64
173 #define RAW_SECTOR_SIZE 2352
174 #define COOKED_SECTOR_SIZE 2048
175 #define MEDIA_CHANGE_DEFAULT_TIME 4
176 #define CDROM_SRB_LIST_SIZE 4
177
178
179 #ifdef DBG
180
181 //
182 // Used to detect the loss of the autorun irp. The driver prints out a message
183 // (debug level 0) if this timeout ever occurs
184 //
185 #define MEDIA_CHANGE_TIMEOUT_TIME 300
186
187 #endif
188
189 #define PLAY_ACTIVE(DeviceExtension) (((PCDROM_DATA)(DeviceExtension + 1))->PlayActive)
190
191 #define MSF_TO_LBA(Minutes,Seconds,Frames) \
192 (ULONG)((60 * 75 * (Minutes)) + (75 * (Seconds)) + ((Frames) - 150))
193
194 #define LBA_TO_MSF(Lba,Minutes,Seconds,Frames) \
195 { \
196 (Minutes) = (UCHAR)(Lba / (60 * 75)); \
197 (Seconds) = (UCHAR)((Lba % (60 * 75)) / 75); \
198 (Frames) = (UCHAR)((Lba % (60 * 75)) % 75); \
199 }
200
201 #define DEC_TO_BCD(x) (((x / 10) << 4) + (x % 10))
202
203 //
204 // Define flags for XA, CDDA, and Mode Select/Sense
205 //
206
207 #define XA_USE_6_BYTE 0x01
208 #define XA_USE_10_BYTE 0x02
209 #define XA_USE_READ_CD 0x04
210 #define XA_NOT_SUPPORTED 0x08
211
212 #define PLEXTOR_CDDA 0x10
213 #define NEC_CDDA 0x20
214
215 //
216 // Sector types for READ_CD
217 //
218
219 #define ANY_SECTOR 0
220 #define CD_DA_SECTOR 1
221 #define YELLOW_MODE1_SECTOR 2
222 #define YELLOW_MODE2_SECTOR 3
223 #define FORM2_MODE1_SECTOR 4
224 #define FORM2_MODE2_SECTOR 5
225
226
227 #ifdef POOL_TAGGING
228 #ifdef ExAllocatePool
229 #undef ExAllocatePool
230 #endif
231 #define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'CscS')
232 #endif
233
234 NTSTATUS
235 NTAPI
236 DriverEntry(
237 IN PDRIVER_OBJECT DriverObject,
238 IN PUNICODE_STRING RegistryPath
239 );
240
241 BOOLEAN
242 NTAPI
243 ScsiCdRomFindDevices(
244 IN PDRIVER_OBJECT DriverObject,
245 IN PUNICODE_STRING RegistryPath,
246 IN PCLASS_INIT_DATA InitializationData,
247 IN PDEVICE_OBJECT PortDeviceObject,
248 IN ULONG PortNumber
249 );
250
251 NTSTATUS
252 NTAPI
253 ScsiCdRomOpenClose(
254 IN PDEVICE_OBJECT DeviceObject,
255 IN PIRP Irp
256 );
257
258 NTSTATUS
259 NTAPI
260 ScsiCdRomReadVerification(
261 IN PDEVICE_OBJECT DeviceObject,
262 IN PIRP Irp
263 );
264
265 NTSTATUS
266 NTAPI
267 ScsiCdRomSwitchMode(
268 IN PDEVICE_OBJECT DeviceObject,
269 IN ULONG SectorSize,
270 IN PIRP OriginalRequest
271 );
272
273 NTSTATUS
274 NTAPI
275 CdRomDeviceControl(
276 IN PDEVICE_OBJECT DeviceObject,
277 IN PIRP Irp
278 );
279
280 IO_COMPLETION_ROUTINE CdRomDeviceControlCompletion;
281 NTSTATUS
282 NTAPI
283 CdRomDeviceControlCompletion(
284 IN PDEVICE_OBJECT DeviceObject,
285 IN PIRP Irp,
286 IN PVOID Context
287 );
288
289 IO_COMPLETION_ROUTINE CdRomSetVolumeIntermediateCompletion;
290 NTSTATUS
291 NTAPI
292 CdRomSetVolumeIntermediateCompletion(
293 IN PDEVICE_OBJECT DeviceObject,
294 IN PIRP Irp,
295 IN PVOID Context
296 );
297
298 IO_COMPLETION_ROUTINE CdRomSwitchModeCompletion;
299 NTSTATUS
300 NTAPI
301 CdRomSwitchModeCompletion(
302 IN PDEVICE_OBJECT DeviceObject,
303 IN PIRP Irp,
304 IN PVOID Context
305 );
306
307 IO_COMPLETION_ROUTINE CdRomXACompletion;
308 NTSTATUS
309 NTAPI
310 CdRomXACompletion(
311 IN PDEVICE_OBJECT DeviceObject,
312 IN PIRP Irp,
313 IN PVOID Context
314 );
315
316 IO_COMPLETION_ROUTINE CdRomClassIoctlCompletion;
317 NTSTATUS
318 NTAPI
319 CdRomClassIoctlCompletion(
320 IN PDEVICE_OBJECT DeviceObject,
321 IN PIRP Irp,
322 IN PVOID Context
323 );
324
325 VOID
326 NTAPI
327 ScsiCdRomStartIo(
328 IN PDEVICE_OBJECT DeviceObject,
329 IN PIRP Irp
330 );
331
332 VOID
333 NTAPI
334 CdRomTickHandler(
335 IN PDEVICE_OBJECT DeviceObject,
336 IN PVOID Context
337 );
338
339 BOOLEAN
340 NTAPI
341 CdRomCheckRegistryForMediaChangeValue(
342 IN PUNICODE_STRING RegistryPath,
343 IN ULONG DeviceNumber
344 );
345
346 NTSTATUS
347 NTAPI
348 CdRomUpdateCapacity(
349 IN PDEVICE_EXTENSION DeviceExtension,
350 IN PIRP IrpToComplete,
351 IN OPTIONAL PKEVENT IoctlEvent
352 );
353
354 NTSTATUS
355 NTAPI
356 CreateCdRomDeviceObject(
357 IN PDRIVER_OBJECT DriverObject,
358 IN PDEVICE_OBJECT PortDeviceObject,
359 IN ULONG PortNumber,
360 IN PULONG DeviceCount,
361 PIO_SCSI_CAPABILITIES PortCapabilities,
362 IN PSCSI_INQUIRY_DATA LunInfo,
363 IN PCLASS_INIT_DATA InitializationData,
364 IN PUNICODE_STRING RegistryPath
365 );
366
367 VOID
368 NTAPI
369 ScanForSpecial(
370 PDEVICE_OBJECT DeviceObject,
371 PINQUIRYDATA InquiryData,
372 PIO_SCSI_CAPABILITIES PortCapabilities
373 );
374
375 BOOLEAN
376 NTAPI
377 CdRomIsPlayActive(
378 IN PDEVICE_OBJECT DeviceObject
379 );
380
381 VOID
382 NTAPI
383 HitachProcessError(
384 PDEVICE_OBJECT DeviceObject,
385 PSCSI_REQUEST_BLOCK Srb,
386 NTSTATUS *Status,
387 BOOLEAN *Retry
388 );
389
390 IO_COMPLETION_ROUTINE ToshibaProcessErrorCompletion;
391 VOID
392 NTAPI
393 ToshibaProcessError(
394 PDEVICE_OBJECT DeviceObject,
395 PSCSI_REQUEST_BLOCK Srb,
396 NTSTATUS *Status,
397 BOOLEAN *Retry
398 );
399
400 BOOLEAN
401 NTAPI
402 IsThisAnAtapiChanger(
403 IN PDEVICE_OBJECT DeviceObject,
404 OUT PULONG DiscsPresent
405 );
406
407 BOOLEAN
408 NTAPI
409 IsThisASanyo(
410 IN PDEVICE_OBJECT DeviceObject,
411 IN UCHAR PathId,
412 IN UCHAR TargetId
413 );
414
415 BOOLEAN
416 NTAPI
417 IsThisAMultiLunDevice(
418 IN PDEVICE_OBJECT DeviceObject,
419 IN PDEVICE_OBJECT PortDeviceObject
420 );
421
422 VOID
423 NTAPI
424 CdRomCreateNamedEvent(
425 IN PDEVICE_EXTENSION DeviceExtension,
426 IN ULONG DeviceNumber
427 );
428
429 #ifdef _PPC_
430 NTSTATUS
431 FindScsiAdapter (
432 IN HANDLE KeyHandle,
433 IN UNICODE_STRING ScsiUnicodeString[],
434 OUT PUCHAR IntermediateController
435 );
436 #endif
437
438 #ifdef ALLOC_PRAGMA
439 #pragma alloc_text(PAGE, DriverEntry)
440 #pragma alloc_text(PAGE, ScsiCdRomFindDevices)
441 #pragma alloc_text(PAGE, CreateCdRomDeviceObject)
442 #pragma alloc_text(PAGE, ScanForSpecial)
443 //#pragma alloc_text(PAGE, CdRomDeviceControl)
444 #pragma alloc_text(PAGE, HitachProcessError)
445 #pragma alloc_text(PAGE, CdRomIsPlayActive)
446 #pragma alloc_text(PAGE, ScsiCdRomReadVerification)
447 #pragma alloc_text(INIT, CdRomCheckRegistryForMediaChangeValue)
448 #pragma alloc_text(INIT, IsThisAnAtapiChanger)
449 #pragma alloc_text(INIT, IsThisASanyo)
450 #pragma alloc_text(INIT, IsThisAMultiLunDevice)
451 #pragma alloc_text(INIT, CdRomCreateNamedEvent)
452 #ifdef _PPC_
453 #pragma alloc_text(PAGE, FindScsiAdapter)
454 #endif
455 #endif
456
457 ULONG NoLoad = 0;
458
459 NTSTATUS
460 NTAPI
461 DriverEntry(
462 IN PDRIVER_OBJECT DriverObject,
463 IN PUNICODE_STRING RegistryPath
464 )
465
466 /*++
467
468 Routine Description:
469
470 This routine initializes the cdrom class driver.
471
472 Arguments:
473
474 DriverObject - Pointer to driver object created by system.
475
476 RegistryPath - Pointer to the name of the services node for this driver.
477
478 Return Value:
479
480 The function value is the final status from the initialization operation.
481
482 --*/
483
484 {
485 CLASS_INIT_DATA InitializationData;
486
487 if(NoLoad) {
488 return STATUS_NO_SUCH_DEVICE;
489 }
490
491 //
492 // Zero InitData
493 //
494
495 RtlZeroMemory (&InitializationData, sizeof(CLASS_INIT_DATA));
496
497 //
498 // Set sizes
499 //
500
501 InitializationData.InitializationDataSize = sizeof(CLASS_INIT_DATA);
502 InitializationData.DeviceExtensionSize = DEVICE_EXTENSION_SIZE;
503
504 InitializationData.DeviceType = FILE_DEVICE_CD_ROM;
505 InitializationData.DeviceCharacteristics = FILE_REMOVABLE_MEDIA | FILE_READ_ONLY_DEVICE;
506
507 //
508 // Set entry points
509 //
510
511 InitializationData.ClassReadWriteVerification = ScsiCdRomReadVerification;
512 InitializationData.ClassDeviceControl = CdRomDeviceControl;
513 InitializationData.ClassFindDevices = ScsiCdRomFindDevices;
514 InitializationData.ClassShutdownFlush = NULL;
515 InitializationData.ClassCreateClose = NULL;
516 InitializationData.ClassStartIo = ScsiCdRomStartIo;
517
518 //
519 // Call the class init routine
520 //
521
522 return ScsiClassInitialize( DriverObject, RegistryPath, &InitializationData);
523
524 } // end DriverEntry()
525
526 BOOLEAN
527 NTAPI
528 ScsiCdRomFindDevices(
529 IN PDRIVER_OBJECT DriverObject,
530 IN PUNICODE_STRING RegistryPath,
531 IN PCLASS_INIT_DATA InitializationData,
532 IN PDEVICE_OBJECT PortDeviceObject,
533 IN ULONG PortNumber
534 )
535
536 /*++
537
538 Routine Description:
539
540 Connect to SCSI port driver. Get adapter capabilities and
541 SCSI bus configuration information. Search inquiry data
542 for CDROM devices to process.
543
544 Arguments:
545
546 DriverObject - CDROM class driver object.
547 PortDeviceObject - SCSI port driver device object.
548 PortNumber - The system ordinal for this scsi adapter.
549
550 Return Value:
551
552 TRUE if CDROM device present on this SCSI adapter.
553
554 --*/
555
556 {
557 PIO_SCSI_CAPABILITIES portCapabilities;
558 PULONG cdRomCount;
559 PCHAR buffer;
560 PSCSI_INQUIRY_DATA lunInfo;
561 PSCSI_ADAPTER_BUS_INFO adapterInfo;
562 PINQUIRYDATA inquiryData;
563 ULONG scsiBus;
564 NTSTATUS status;
565 BOOLEAN foundDevice = FALSE;
566
567 //
568 // Call port driver to get adapter capabilities.
569 //
570
571 status = ScsiClassGetCapabilities(PortDeviceObject, &portCapabilities);
572
573 if (!NT_SUCCESS(status)) {
574 DebugPrint((1,"FindScsiDevices: ScsiClassGetCapabilities failed\n"));
575 return foundDevice;
576 }
577
578 //
579 // Call port driver to get inquiry information to find cdroms.
580 //
581
582 status = ScsiClassGetInquiryData(PortDeviceObject, (PSCSI_ADAPTER_BUS_INFO *) &buffer);
583
584 if (!NT_SUCCESS(status)) {
585 DebugPrint((1,"FindScsiDevices: ScsiClassGetInquiryData failed\n"));
586 return foundDevice;
587 }
588
589 //
590 // Get the address of the count of the number of cdroms already initialized.
591 //
592
593 cdRomCount = &IoGetConfigurationInformation()->CdRomCount;
594 adapterInfo = (PVOID) buffer;
595
596 //
597 // For each SCSI bus this adapter supports ...
598 //
599
600 for (scsiBus=0; scsiBus < adapterInfo->NumberOfBuses; scsiBus++) {
601
602 //
603 // Get the SCSI bus scan data for this bus.
604 //
605
606 lunInfo = (PVOID) (buffer + adapterInfo->BusData[scsiBus].InquiryDataOffset);
607
608 //
609 // Search list for unclaimed disk devices.
610 //
611
612 while (adapterInfo->BusData[scsiBus].InquiryDataOffset) {
613
614 inquiryData = (PVOID)lunInfo->InquiryData;
615
616 if ((inquiryData->DeviceType == READ_ONLY_DIRECT_ACCESS_DEVICE) &&
617 (inquiryData->DeviceTypeQualifier == 0) &&
618 (!lunInfo->DeviceClaimed)) {
619
620 DebugPrint((1,"FindScsiDevices: Vendor string is %.24s\n",
621 inquiryData->VendorId));
622
623 //
624 // Create device objects for cdrom
625 //
626
627 status = CreateCdRomDeviceObject(DriverObject,
628 PortDeviceObject,
629 PortNumber,
630 cdRomCount,
631 portCapabilities,
632 lunInfo,
633 InitializationData,
634 RegistryPath);
635
636 if (NT_SUCCESS(status)) {
637
638 //
639 // Increment system cdrom device count.
640 //
641
642 (*cdRomCount)++;
643
644 //
645 // Indicate that a cdrom device was found.
646 //
647
648 foundDevice = TRUE;
649 }
650 }
651
652 //
653 // Get next LunInfo.
654 //
655
656 if (lunInfo->NextInquiryDataOffset == 0) {
657 break;
658 }
659
660 lunInfo = (PVOID) (buffer + lunInfo->NextInquiryDataOffset);
661 }
662 }
663
664 ExFreePool(buffer);
665
666
667 return foundDevice;
668
669 } // end FindScsiCdRoms()
670
671 VOID
672 NTAPI
673 CdRomCreateNamedEvent(
674 IN PDEVICE_EXTENSION DeviceExtension,
675 IN ULONG DeviceNumber
676 )
677
678 /*++
679
680 Routine Description:
681
682 Create the named synchronization event for notification of media change
683 events to the system. The event is reset before this function returns.
684
685 Arguments:
686
687 DeviceExtension - the device extension pointer for storage of the event pointer.
688
689 Return Value:
690
691 None.
692
693 --*/
694
695 {
696 UNICODE_STRING unicodeString;
697 OBJECT_ATTRIBUTES objectAttributes;
698 CCHAR eventNameBuffer[MAXIMUM_FILENAME_LENGTH];
699 STRING eventNameString;
700 HANDLE handle;
701 NTSTATUS status;
702
703
704 sprintf(eventNameBuffer,"\\Device\\MediaChangeEvent%ld",
705 DeviceNumber);
706
707 RtlInitString(&eventNameString,
708 eventNameBuffer);
709
710 status = RtlAnsiStringToUnicodeString(&unicodeString,
711 &eventNameString,
712 TRUE);
713
714 if (!NT_SUCCESS(status)) {
715 return;
716 }
717
718 InitializeObjectAttributes(&objectAttributes,
719 &unicodeString,
720 OBJ_PERMANENT | OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
721 NULL,
722 NULL);
723
724 DeviceExtension->MediaChangeEvent = IoCreateSynchronizationEvent(&unicodeString,
725 &handle);
726 DeviceExtension->MediaChangeEventHandle = handle;
727
728 KeClearEvent(DeviceExtension->MediaChangeEvent);
729
730 RtlFreeUnicodeString(&unicodeString);
731 }
732
733 NTSTATUS
734 NTAPI
735 CreateCdRomDeviceObject(
736 IN PDRIVER_OBJECT DriverObject,
737 IN PDEVICE_OBJECT PortDeviceObject,
738 IN ULONG PortNumber,
739 IN PULONG DeviceCount,
740 IN PIO_SCSI_CAPABILITIES PortCapabilities,
741 IN PSCSI_INQUIRY_DATA LunInfo,
742 IN PCLASS_INIT_DATA InitializationData,
743 IN PUNICODE_STRING RegistryPath
744 )
745
746 /*++
747
748 Routine Description:
749
750 This routine creates an object for the device and then calls the
751 SCSI port driver for media capacity and sector size.
752
753 Arguments:
754
755 DriverObject - Pointer to driver object created by system.
756 PortDeviceObject - to connect to SCSI port driver.
757 DeviceCount - Number of previously installed CDROMs.
758 PortCapabilities - Pointer to structure returned by SCSI port
759 driver describing adapter capabilites (and limitations).
760 LunInfo - Pointer to configuration information for this device.
761
762 Return Value:
763
764 NTSTATUS
765
766 --*/
767 {
768 CHAR ntNameBuffer[64];
769 NTSTATUS status;
770 BOOLEAN changerDevice;
771 SCSI_REQUEST_BLOCK srb;
772 ULONG length;
773 PCDROM_DATA cddata;
774 PCDB cdb;
775 PVOID senseData = NULL;
776 PDEVICE_OBJECT deviceObject = NULL;
777 PDEVICE_EXTENSION deviceExtension = NULL;
778 PUCHAR buffer;
779 ULONG bps;
780 ULONG lastBit;
781 ULONG timeOut;
782 BOOLEAN srbListInitialized = FALSE;
783
784 //
785 // Claim the device. Note that any errors after this
786 // will goto the generic handler, where the device will
787 // be released.
788 //
789
790 status = ScsiClassClaimDevice(PortDeviceObject,
791 LunInfo,
792 FALSE,
793 &PortDeviceObject);
794
795 if (!NT_SUCCESS(status)) {
796 return(status);
797 }
798
799 //
800 // Create device object for this device.
801 //
802
803 sprintf(ntNameBuffer,
804 "\\Device\\CdRom%lu",
805 *DeviceCount);
806
807 status = ScsiClassCreateDeviceObject(DriverObject,
808 ntNameBuffer,
809 NULL,
810 &deviceObject,
811 InitializationData);
812
813 if (!NT_SUCCESS(status)) {
814 DebugPrint((1,"CreateCdRomDeviceObjects: Can not create device %s\n",
815 ntNameBuffer));
816
817 goto CreateCdRomDeviceObjectExit;
818 }
819
820 //
821 // Indicate that IRPs should include MDLs.
822 //
823
824 deviceObject->Flags |= DO_DIRECT_IO;
825
826 //
827 // Set up required stack size in device object.
828 //
829
830 deviceObject->StackSize = PortDeviceObject->StackSize + 2;
831
832 deviceExtension = deviceObject->DeviceExtension;
833
834 //
835 // Allocate spinlock for split request completion.
836 //
837
838 KeInitializeSpinLock(&deviceExtension->SplitRequestSpinLock);
839
840 //
841 // This is the physical device.
842 //
843
844 deviceExtension->PhysicalDevice = deviceObject;
845
846 //
847 // Initialize lock count to zero. The lock count is used to
848 // disable the ejection mechanism when media is mounted.
849 //
850
851 deviceExtension->LockCount = 0;
852
853 //
854 // Save system cdrom number
855 //
856
857 deviceExtension->DeviceNumber = *DeviceCount;
858
859 //
860 // Copy port device object to device extension.
861 //
862
863 deviceExtension->PortDeviceObject = PortDeviceObject;
864
865 //
866 // Set the alignment requirements for the device based on the
867 // host adapter requirements
868 //
869
870 if (PortDeviceObject->AlignmentRequirement > deviceObject->AlignmentRequirement) {
871 deviceObject->AlignmentRequirement = PortDeviceObject->AlignmentRequirement;
872 }
873
874 //
875 // Save address of port driver capabilities.
876 //
877
878 deviceExtension->PortCapabilities = PortCapabilities;
879
880 //
881 // Clear SRB flags.
882 //
883
884 deviceExtension->SrbFlags = 0;
885 deviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
886
887 //
888 // Allocate request sense buffer.
889 //
890
891 senseData = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE);
892
893 if (senseData == NULL) {
894
895 //
896 // The buffer cannot be allocated.
897 //
898
899 status = STATUS_INSUFFICIENT_RESOURCES;
900 goto CreateCdRomDeviceObjectExit;
901 }
902
903 //
904 // Set the sense data pointer in the device extension.
905 //
906
907 deviceExtension->SenseData = senseData;
908
909 //
910 // CDROMs are not partitionable so starting offset is 0.
911 //
912
913 deviceExtension->StartingOffset.LowPart = 0;
914 deviceExtension->StartingOffset.HighPart = 0;
915
916 //
917 // Path/TargetId/LUN describes a device location on the SCSI bus.
918 // This information comes from the LunInfo buffer.
919 //
920
921 deviceExtension->PortNumber = (UCHAR)PortNumber;
922 deviceExtension->PathId = LunInfo->PathId;
923 deviceExtension->TargetId = LunInfo->TargetId;
924 deviceExtension->Lun = LunInfo->Lun;
925
926 //
927 // Set timeout value in seconds.
928 //
929
930 timeOut = ScsiClassQueryTimeOutRegistryValue(RegistryPath);
931 if (timeOut) {
932 deviceExtension->TimeOutValue = timeOut;
933 } else {
934 deviceExtension->TimeOutValue = SCSI_CDROM_TIMEOUT;
935 }
936
937 //
938 // Build the lookaside list for srb's for the physical disk. Should only
939 // need a couple.
940 //
941
942 ScsiClassInitializeSrbLookasideList(deviceExtension,
943 CDROM_SRB_LIST_SIZE);
944
945 srbListInitialized = TRUE;
946
947 //
948 // Back pointer to device object.
949 //
950
951 deviceExtension->DeviceObject = deviceObject;
952
953 //
954 // Allocate buffer for drive geometry.
955 //
956
957 deviceExtension->DiskGeometry =
958 ExAllocatePool(NonPagedPool, sizeof(DISK_GEOMETRY));
959
960 if (deviceExtension->DiskGeometry == NULL) {
961
962 status = STATUS_INSUFFICIENT_RESOURCES;
963 goto CreateCdRomDeviceObjectExit;
964 }
965
966 //
967 // Set up media change support defaults.
968 //
969
970 cddata = (PCDROM_DATA)(deviceExtension + 1);
971
972 KeInitializeSpinLock(&cddata->FormSpinLock);
973 KeInitializeSpinLock(&cddata->TimerIrpSpinLock);
974 InitializeListHead(&cddata->TimerIrpList);
975
976 cddata->MediaChangeCountDown = MEDIA_CHANGE_DEFAULT_TIME;
977 cddata->MediaChangeSupported = FALSE;
978 cddata->MediaChange = FALSE;
979
980 //
981 // Assume that there is initially no media in the device
982 // only notify upper layers if there is something there
983 //
984
985 deviceExtension->MediaChangeNoMedia = TRUE;
986 cddata->MediaChangeIrp = NULL;
987 #ifdef DBG
988 cddata->MediaChangeIrpTimeInUse = 0;
989 cddata->MediaChangeIrpLost = FALSE;
990 #endif
991
992 //
993 // Scan for Scsi controllers that require special processing.
994 //
995
996 ScanForSpecial(deviceObject,
997 (PINQUIRYDATA) LunInfo->InquiryData,
998 PortCapabilities);
999
1000 //
1001 // Do READ CAPACITY. This SCSI command
1002 // returns the last sector address on the device
1003 // and the bytes per sector.
1004 // These are used to calculate the drive capacity
1005 // in bytes.
1006 //
1007
1008 status = ScsiClassReadDriveCapacity(deviceObject);
1009 bps = deviceExtension->DiskGeometry->BytesPerSector;
1010
1011 if (!NT_SUCCESS(status) || !bps) {
1012
1013 DebugPrint((1,
1014 "CreateCdRomDeviceObjects: Can't read capacity for device %s\n",
1015 ntNameBuffer));
1016
1017 //
1018 // Set disk geometry to default values (per ISO 9660).
1019 //
1020
1021 bps = 2048;
1022 deviceExtension->SectorShift = 11;
1023 deviceExtension->PartitionLength.QuadPart = (LONGLONG)(0x7fffffff);
1024 } else {
1025
1026 //
1027 // Insure that bytes per sector is a power of 2
1028 // This corrects a problem with the HP 4020i CDR where it
1029 // returns an incorrect number for bytes per sector.
1030 //
1031
1032 lastBit = (ULONG) -1;
1033 while (bps) {
1034 lastBit++;
1035 bps = bps >> 1;
1036 }
1037
1038 bps = 1 << lastBit;
1039 }
1040 deviceExtension->DiskGeometry->BytesPerSector = bps;
1041 DebugPrint((2, "CreateCdRomDeviceObject: Calc'd bps = %x\n", bps));
1042
1043 //
1044 // Check to see if this is some sort of changer device
1045 //
1046
1047 changerDevice = FALSE;
1048
1049 //
1050 // Search for devices that have special requirements for media
1051 // change support.
1052 //
1053
1054 if (deviceExtension->Lun > 0) {
1055 changerDevice = TRUE;
1056 }
1057
1058 if (!changerDevice) {
1059 changerDevice = IsThisASanyo(deviceObject, deviceExtension->PathId,
1060 deviceExtension->TargetId);
1061 }
1062
1063 if (!changerDevice) {
1064 ULONG tmp;
1065 changerDevice = IsThisAnAtapiChanger(deviceObject, &tmp);
1066 }
1067
1068 if (!changerDevice) {
1069 changerDevice = IsThisAMultiLunDevice(deviceObject, PortDeviceObject);
1070 }
1071
1072 //
1073 // If it is a changer device, increment the timeout to take platter-swapping
1074 // time into account
1075 //
1076
1077 if(changerDevice) {
1078 deviceExtension->TimeOutValue += SCSI_CHANGER_BONUS_TIMEOUT;
1079 }
1080
1081 //
1082 // Create the media change named event. If this succeeds then continue
1083 // initializing the media change support data items.
1084 //
1085
1086 CdRomCreateNamedEvent(deviceExtension,*DeviceCount);
1087 if (deviceExtension->MediaChangeEvent) {
1088
1089 //
1090 // If this is not a changer, get an IRP for the timer request
1091 // and initialize the timer.
1092 //
1093
1094 if (!changerDevice) {
1095
1096 //
1097 // Not a changer device - continue with media change initialization.
1098 // Determine if the user actually wants media change events.
1099 //
1100
1101 if (CdRomCheckRegistryForMediaChangeValue(RegistryPath, *DeviceCount)) {
1102 PIO_STACK_LOCATION irpStack;
1103 PSCSI_REQUEST_BLOCK srb;
1104 PIRP irp;
1105
1106 //
1107 // User wants it - preallocate IRP and SRB.
1108 //
1109
1110 irp = IoAllocateIrp((CCHAR)(deviceObject->StackSize+1),
1111 FALSE);
1112 if (irp) {
1113 PVOID buffer;
1114
1115 srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK));
1116 buffer = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE);
1117
1118 if (srb && buffer) {
1119 PCDB cdb;
1120
1121 //
1122 // All resources have been allocated set up the IRP.
1123 //
1124
1125 IoSetNextIrpStackLocation(irp);
1126 irpStack = IoGetCurrentIrpStackLocation(irp);
1127 irpStack->DeviceObject = deviceObject;
1128 irpStack = IoGetNextIrpStackLocation(irp);
1129 cddata->MediaChangeIrp = irp;
1130 irpStack->Parameters.Scsi.Srb = srb;
1131
1132 //
1133 // Initialize the SRB
1134 //
1135
1136 RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
1137
1138 srb->CdbLength = 6;
1139 srb->TimeOutValue = deviceExtension->TimeOutValue * 2;
1140 srb->QueueTag = SP_UNTAGGED;
1141 srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
1142 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
1143 srb->PathId = deviceExtension->PathId;
1144 srb->TargetId = deviceExtension->TargetId;
1145 srb->Lun = deviceExtension->Lun;
1146 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1147
1148 //
1149 // Initialize and set up the sense information buffer
1150 //
1151
1152 RtlZeroMemory(buffer, SENSE_BUFFER_SIZE);
1153 srb->SenseInfoBuffer = buffer;
1154 srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
1155
1156 //
1157 // Initialize the CDB
1158 //
1159
1160 cdb = (PCDB)&srb->Cdb[0];
1161 cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
1162 cdb->CDB6GENERIC.LogicalUnitNumber = deviceExtension->Lun;
1163
1164 //
1165 // It is ok to support media change events on this device.
1166 //
1167
1168 cddata->MediaChangeSupported = TRUE;
1169 cddata->MediaChange = TRUE;
1170
1171 } else {
1172
1173 if (srb) {
1174 ExFreePool(srb);
1175 }
1176 if (buffer) {
1177 ExFreePool(buffer);
1178 }
1179 IoFreeIrp(irp);
1180 }
1181 }
1182 } else {
1183 deviceExtension->MediaChangeEvent = NULL;
1184 }
1185 } else {
1186 deviceExtension->MediaChangeEvent = NULL;
1187 }
1188 }
1189
1190 //
1191 // Assume use of 6-byte mode sense/select for now.
1192 //
1193
1194 cddata->XAFlags |= XA_USE_6_BYTE;
1195
1196 //
1197 // Build and issue mode sense with Read error recovery page. This will be used to change
1198 // block size in case of any raw reads (Mode 2, Form 2).
1199 //
1200
1201 length = (sizeof(MODE_READ_RECOVERY_PAGE) + MODE_BLOCK_DESC_LENGTH + MODE_HEADER_LENGTH);
1202
1203 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
1204
1205 srb.CdbLength = 6;
1206 cdb = (PCDB)srb.Cdb;
1207
1208 //
1209 // Set timeout value from device extension.
1210 //
1211
1212 srb.TimeOutValue = deviceExtension->TimeOutValue;
1213
1214 //
1215 // Build the MODE SENSE CDB. The data returned will be kept in the device extension
1216 // and used to set block size.
1217 //
1218
1219 cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
1220 cdb->MODE_SENSE.PageCode = 0x1;
1221 cdb->MODE_SENSE.AllocationLength = (UCHAR)length;
1222
1223 buffer = ExAllocatePool(NonPagedPoolCacheAligned, (sizeof(MODE_READ_RECOVERY_PAGE) + MODE_BLOCK_DESC_LENGTH + MODE_HEADER_LENGTH10));
1224 if (!buffer) {
1225 status = STATUS_INSUFFICIENT_RESOURCES;
1226 goto CreateCdRomDeviceObjectExit;
1227 }
1228
1229 status = ScsiClassSendSrbSynchronous(deviceObject,
1230 &srb,
1231 buffer,
1232 length,
1233 FALSE);
1234 if (!NT_SUCCESS(status)) {
1235
1236 //
1237 // May be Atapi, try 10-byte.
1238 //
1239
1240 length = (sizeof(MODE_READ_RECOVERY_PAGE) + MODE_BLOCK_DESC_LENGTH + MODE_HEADER_LENGTH10);
1241
1242 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
1243
1244 //
1245 // Build the MODE SENSE CDB.
1246 //
1247
1248 srb.CdbLength = 10;
1249 cdb = (PCDB)srb.Cdb;
1250
1251 //
1252 // Set timeout value from device extension.
1253 //
1254
1255 srb.TimeOutValue = deviceExtension->TimeOutValue;
1256
1257 cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
1258 cdb->MODE_SENSE10.PageCode = 0x1;
1259
1260 cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(length >> 8);
1261 cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(length & 0xFF);
1262
1263 status = ScsiClassSendSrbSynchronous(deviceObject,
1264 &srb,
1265 buffer,
1266 length,
1267 FALSE);
1268 if (status == STATUS_DATA_OVERRUN) {
1269
1270 //
1271 // Build and issue the ReadCd command to ensure that this device supports it.
1272 //
1273
1274 RtlZeroMemory(cdb, 12);
1275
1276 cdb->READ_CD.OperationCode = SCSIOP_READ_CD;
1277
1278 status = ScsiClassSendSrbSynchronous(deviceObject,
1279 &srb,
1280 NULL,
1281 0,
1282 FALSE);
1283
1284 //
1285 // If the command wasn't rejected then support the READ_CD.
1286 //
1287
1288 if (NT_SUCCESS(status) || (status == STATUS_NO_MEDIA_IN_DEVICE)) {
1289
1290 //
1291 // Using Read CD precludes issueing a mode select to
1292 // set the user data size. So, no buffer copy is
1293 // necessary.
1294 //
1295
1296 cddata->XAFlags &= ~XA_USE_6_BYTE;
1297 cddata->XAFlags = XA_USE_READ_CD | XA_USE_10_BYTE;
1298 } else {
1299
1300 RtlCopyMemory(&cddata->u1.Header, buffer, sizeof(ERROR_RECOVERY_DATA10));
1301 cddata->u1.Header.ModeDataLength = 0;
1302
1303 cddata->XAFlags &= ~XA_USE_6_BYTE;
1304 cddata->XAFlags |= XA_USE_10_BYTE;
1305 }
1306
1307 } else if (NT_SUCCESS(status)) {
1308
1309 RtlCopyMemory(&cddata->u1.Header, buffer, sizeof(ERROR_RECOVERY_DATA10));
1310 cddata->u1.Header.ModeDataLength = 0;
1311
1312 cddata->XAFlags &= ~XA_USE_6_BYTE;
1313 cddata->XAFlags |= XA_USE_10_BYTE;
1314
1315 } else {
1316 cddata->XAFlags |= XA_NOT_SUPPORTED;
1317 }
1318 } else {
1319 RtlCopyMemory(&cddata->u1.Header, buffer, sizeof(ERROR_RECOVERY_DATA));
1320 cddata->u1.Header.ModeDataLength = 0;
1321 }
1322
1323 ExFreePool(buffer);
1324
1325 //
1326 // Start the timer now regardless of if Autorun is enabled.
1327 // The timer must run forever since IoStopTimer faults.
1328 //
1329
1330 IoInitializeTimer(deviceObject, CdRomTickHandler, NULL);
1331 IoStartTimer(deviceObject);
1332
1333 return(STATUS_SUCCESS);
1334
1335 CreateCdRomDeviceObjectExit:
1336
1337 //
1338 // Release the device since an error occured.
1339 //
1340
1341 ScsiClassClaimDevice(PortDeviceObject,
1342 LunInfo,
1343 TRUE,
1344 NULL);
1345
1346 if (senseData != NULL) {
1347 ExFreePool(senseData);
1348 }
1349
1350 if (deviceExtension->DiskGeometry != NULL) {
1351 ExFreePool(deviceExtension->DiskGeometry);
1352 }
1353
1354 if (deviceObject != NULL) {
1355 if (srbListInitialized) {
1356 ExDeleteNPagedLookasideList(&deviceExtension->SrbLookasideListHead);
1357 }
1358 IoDeleteDevice(deviceObject);
1359 }
1360
1361
1362 return status;
1363
1364 } // end CreateCdRomDeviceObject()
1365
1366 VOID
1367 NTAPI
1368 ScsiCdRomStartIo(
1369 IN PDEVICE_OBJECT DeviceObject,
1370 IN PIRP Irp
1371 )
1372 {
1373
1374 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
1375 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
1376 PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
1377 PIO_STACK_LOCATION irpStack;
1378 PIRP irp2 = NULL;
1379 ULONG transferPages;
1380 ULONG transferByteCount = currentIrpStack->Parameters.Read.Length;
1381 ULONG maximumTransferLength = deviceExtension->PortCapabilities->MaximumTransferLength;
1382 PCDROM_DATA cdData;
1383 PSCSI_REQUEST_BLOCK srb = NULL;
1384 PCDB cdb;
1385 PUCHAR senseBuffer = NULL;
1386 PVOID dataBuffer;
1387 NTSTATUS status;
1388 BOOLEAN use6Byte;
1389
1390 //
1391 // Mark IRP with status pending.
1392 //
1393
1394 IoMarkIrpPending(Irp);
1395
1396 //
1397 // If the flag is set in the device object, force a verify.
1398 //
1399
1400 if (DeviceObject->Flags & DO_VERIFY_VOLUME) {
1401 DebugPrint((2, "ScsiCdRomStartIo: [%lx] Volume needs verified\n", Irp));
1402 if (!(currentIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME)) {
1403
1404 if (Irp->Tail.Overlay.Thread) {
1405 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
1406 }
1407
1408 Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
1409
1410 DebugPrint((2, "ScsiCdRomStartIo: [%lx] Calling UpdateCapcity - "
1411 "ioctl event = %lx\n",
1412 Irp,
1413 nextIrpStack->Parameters.Others.Argument1
1414 ));
1415
1416 //
1417 // our device control dispatch routine stores an event in the next
1418 // stack location to signal when startio has completed. We need to
1419 // pass this in so that the update capacity completion routine can
1420 // set it rather than completing the Irp.
1421 //
1422
1423 status = CdRomUpdateCapacity(deviceExtension,
1424 Irp,
1425 nextIrpStack->Parameters.Others.Argument1
1426 );
1427
1428 DebugPrint((2, "ScsiCdRomStartIo: [%lx] UpdateCapacity returned %lx\n", Irp, status));
1429 ASSERT(status == STATUS_PENDING);
1430 return;
1431 }
1432 }
1433
1434 cdData = (PCDROM_DATA)(deviceExtension + 1);
1435 use6Byte = cdData->XAFlags & XA_USE_6_BYTE;
1436
1437 if (currentIrpStack->MajorFunction == IRP_MJ_READ) {
1438
1439 //
1440 // Add partition byte offset to make starting byte relative to
1441 // beginning of disk. In addition, add in skew for DM Driver, if any.
1442 //
1443
1444 currentIrpStack->Parameters.Read.ByteOffset.QuadPart += (deviceExtension->StartingOffset.QuadPart);
1445
1446 //
1447 // Calculate number of pages in this transfer.
1448 //
1449
1450 transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp->MdlAddress),
1451 currentIrpStack->Parameters.Read.Length);
1452
1453 //
1454 // Check if request length is greater than the maximum number of
1455 // bytes that the hardware can transfer.
1456 //
1457
1458 if (cdData->RawAccess) {
1459
1460 ASSERT(!(cdData->XAFlags & XA_USE_READ_CD));
1461
1462 //
1463 // Fire off a mode select to switch back to cooked sectors.
1464 //
1465
1466 irp2 = IoAllocateIrp((CCHAR)(deviceExtension->DeviceObject->StackSize+1),
1467 FALSE);
1468
1469 if (!irp2) {
1470 Irp->IoStatus.Information = 0;
1471 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1472 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1473 IoStartNextPacket(DeviceObject, FALSE);
1474 return;
1475 }
1476
1477 srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK));
1478 if (!srb) {
1479 Irp->IoStatus.Information = 0;
1480 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1481 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1482 IoFreeIrp(irp2);
1483 IoStartNextPacket(DeviceObject, FALSE);
1484 return;
1485 }
1486
1487 RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
1488
1489 cdb = (PCDB)srb->Cdb;
1490
1491 //
1492 // Allocate sense buffer.
1493 //
1494
1495 senseBuffer = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE);
1496
1497 if (!senseBuffer) {
1498 Irp->IoStatus.Information = 0;
1499 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1500 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1501 ExFreePool(srb);
1502 IoFreeIrp(irp2);
1503 IoStartNextPacket(DeviceObject, FALSE);
1504 return;
1505 }
1506
1507 //
1508 // Set up the irp.
1509 //
1510
1511 IoSetNextIrpStackLocation(irp2);
1512 irp2->IoStatus.Status = STATUS_SUCCESS;
1513 irp2->IoStatus.Information = 0;
1514 irp2->Flags = 0;
1515 irp2->UserBuffer = NULL;
1516
1517 //
1518 // Save the device object and irp in a private stack location.
1519 //
1520
1521 irpStack = IoGetCurrentIrpStackLocation(irp2);
1522 irpStack->DeviceObject = deviceExtension->DeviceObject;
1523 irpStack->Parameters.Others.Argument2 = (PVOID) Irp;
1524
1525 //
1526 // The retry count will be in the real Irp, as the retry logic will
1527 // recreate our private irp.
1528 //
1529
1530 if (!(nextIrpStack->Parameters.Others.Argument1)) {
1531
1532 //
1533 // Only jam this in if it doesn't exist. The completion routines can
1534 // call StartIo directly in the case of retries and resetting it will
1535 // cause infinite loops.
1536 //
1537
1538 nextIrpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES;
1539 }
1540
1541 //
1542 // Construct the IRP stack for the lower level driver.
1543 //
1544
1545 irpStack = IoGetNextIrpStackLocation(irp2);
1546 irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
1547 irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
1548 irpStack->Parameters.Scsi.Srb = srb;
1549
1550 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
1551 srb->PathId = deviceExtension->PathId;
1552 srb->TargetId = deviceExtension->TargetId;
1553 srb->Lun = deviceExtension->Lun;
1554 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1555 srb->Cdb[1] |= deviceExtension->Lun << 5;
1556 srb->SrbStatus = srb->ScsiStatus = 0;
1557 srb->NextSrb = 0;
1558 srb->OriginalRequest = irp2;
1559 srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
1560 srb->SenseInfoBuffer = senseBuffer;
1561
1562 transferByteCount = (use6Byte) ? sizeof(ERROR_RECOVERY_DATA) : sizeof(ERROR_RECOVERY_DATA10);
1563 dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned, transferByteCount );
1564 if (!dataBuffer) {
1565 Irp->IoStatus.Information = 0;
1566 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1567 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1568 ExFreePool(senseBuffer);
1569 ExFreePool(srb);
1570 IoFreeIrp(irp2);
1571 IoStartNextPacket(DeviceObject, FALSE);
1572 return;
1573
1574 }
1575
1576 irp2->MdlAddress = IoAllocateMdl(dataBuffer,
1577 transferByteCount,
1578 FALSE,
1579 FALSE,
1580 (PIRP) NULL);
1581
1582 if (!irp2->MdlAddress) {
1583 Irp->IoStatus.Information = 0;
1584 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1585 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1586 ExFreePool(senseBuffer);
1587 ExFreePool(srb);
1588 ExFreePool(dataBuffer);
1589 IoFreeIrp(irp2);
1590 IoStartNextPacket(DeviceObject, FALSE);
1591 return;
1592 }
1593
1594 //
1595 // Prepare the MDL
1596 //
1597
1598 MmBuildMdlForNonPagedPool(irp2->MdlAddress);
1599
1600 srb->DataBuffer = dataBuffer;
1601
1602 //
1603 // Set the new block size in the descriptor.
1604 //
1605
1606 cdData->u1.BlockDescriptor.BlockLength[0] = (UCHAR)(COOKED_SECTOR_SIZE >> 16) & 0xFF;
1607 cdData->u1.BlockDescriptor.BlockLength[1] = (UCHAR)(COOKED_SECTOR_SIZE >> 8) & 0xFF;
1608 cdData->u1.BlockDescriptor.BlockLength[2] = (UCHAR)(COOKED_SECTOR_SIZE & 0xFF);
1609
1610 //
1611 // Move error page into dataBuffer.
1612 //
1613
1614 RtlCopyMemory(srb->DataBuffer, &cdData->u1.Header, transferByteCount);
1615
1616 //
1617 // Build and send a mode select to switch into raw mode.
1618 //
1619
1620 srb->SrbFlags = deviceExtension->SrbFlags;
1621 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_OUT);
1622 srb->DataTransferLength = transferByteCount;
1623 srb->TimeOutValue = deviceExtension->TimeOutValue * 2;
1624
1625 if (use6Byte) {
1626 srb->CdbLength = 6;
1627 cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
1628 cdb->MODE_SELECT.PFBit = 1;
1629 cdb->MODE_SELECT.ParameterListLength = (UCHAR)transferByteCount;
1630 } else {
1631
1632 srb->CdbLength = 10;
1633 cdb->MODE_SELECT10.OperationCode = SCSIOP_MODE_SELECT10;
1634 cdb->MODE_SELECT10.PFBit = 1;
1635 cdb->MODE_SELECT10.ParameterListLength[0] = (UCHAR)(transferByteCount >> 8);
1636 cdb->MODE_SELECT10.ParameterListLength[1] = (UCHAR)(transferByteCount & 0xFF);
1637 }
1638
1639 //
1640 // Update completion routine.
1641 //
1642
1643 IoSetCompletionRoutine(irp2,
1644 CdRomSwitchModeCompletion,
1645 srb,
1646 TRUE,
1647 TRUE,
1648 TRUE);
1649
1650 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
1651 return;
1652 }
1653
1654 if ((currentIrpStack->Parameters.Read.Length > maximumTransferLength) ||
1655 (transferPages >
1656 deviceExtension->PortCapabilities->MaximumPhysicalPages)) {
1657
1658 //
1659 // Request needs to be split. Completion of each portion of the
1660 // request will fire off the next portion. The final request will
1661 // signal Io to send a new request.
1662 //
1663
1664 transferPages =
1665 deviceExtension->PortCapabilities->MaximumPhysicalPages - 1;
1666
1667 if(maximumTransferLength > transferPages << PAGE_SHIFT) {
1668 maximumTransferLength = transferPages << PAGE_SHIFT;
1669 }
1670
1671 //
1672 // Check that the maximum transfer size is not zero
1673 //
1674
1675 if(maximumTransferLength == 0) {
1676 maximumTransferLength = PAGE_SIZE;
1677 }
1678
1679 ScsiClassSplitRequest(DeviceObject, Irp, maximumTransferLength);
1680 return;
1681
1682 } else {
1683
1684 //
1685 // Build SRB and CDB for this IRP.
1686 //
1687
1688 ScsiClassBuildRequest(DeviceObject, Irp);
1689
1690 }
1691
1692
1693 } else if (currentIrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) {
1694
1695 //
1696 // Allocate an irp, srb and associated structures.
1697 //
1698
1699 irp2 = IoAllocateIrp((CCHAR)(deviceExtension->DeviceObject->StackSize+1),
1700 FALSE);
1701
1702 if (!irp2) {
1703 Irp->IoStatus.Information = 0;
1704 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1705 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1706 IoStartNextPacket(DeviceObject, FALSE);
1707 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp, Irp->IoStatus.Status, __LINE__));
1708 return;
1709 }
1710
1711 srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK));
1712 if (!srb) {
1713 Irp->IoStatus.Information = 0;
1714 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1715 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1716 IoFreeIrp(irp2);
1717 IoStartNextPacket(DeviceObject, FALSE);
1718 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp, Irp->IoStatus.Status, __LINE__));
1719 return;
1720 }
1721
1722 RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
1723
1724 cdb = (PCDB)srb->Cdb;
1725
1726 //
1727 // Allocate sense buffer.
1728 //
1729
1730 senseBuffer = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE);
1731
1732 if (!senseBuffer) {
1733 Irp->IoStatus.Information = 0;
1734 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1735 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1736 ExFreePool(srb);
1737 IoFreeIrp(irp2);
1738 IoStartNextPacket(DeviceObject, FALSE);
1739 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp, Irp->IoStatus.Status, __LINE__));
1740 return;
1741 }
1742
1743 //
1744 // Set up the irp.
1745 //
1746
1747 IoSetNextIrpStackLocation(irp2);
1748 irp2->IoStatus.Status = STATUS_SUCCESS;
1749 irp2->IoStatus.Information = 0;
1750 irp2->Flags = 0;
1751 irp2->UserBuffer = NULL;
1752
1753 //
1754 // Save the device object and irp in a private stack location.
1755 //
1756
1757 irpStack = IoGetCurrentIrpStackLocation(irp2);
1758 irpStack->DeviceObject = deviceExtension->DeviceObject;
1759 irpStack->Parameters.Others.Argument2 = (PVOID) Irp;
1760
1761 //
1762 // The retry count will be in the real Irp, as the retry logic will
1763 // recreate our private irp.
1764 //
1765
1766 if (!(nextIrpStack->Parameters.Others.Argument1)) {
1767
1768 //
1769 // Only jam this in if it doesn't exist. The completion routines can
1770 // call StartIo directly in the case of retries and resetting it will
1771 // cause infinite loops.
1772 //
1773
1774 nextIrpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES;
1775 }
1776
1777 //
1778 // Construct the IRP stack for the lower level driver.
1779 //
1780
1781 irpStack = IoGetNextIrpStackLocation(irp2);
1782 irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
1783 irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
1784 irpStack->Parameters.Scsi.Srb = srb;
1785
1786 IoSetCompletionRoutine(irp2,
1787 CdRomDeviceControlCompletion,
1788 srb,
1789 TRUE,
1790 TRUE,
1791 TRUE);
1792 //
1793 // Setup those fields that are generic to all requests.
1794 //
1795
1796 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
1797 srb->PathId = deviceExtension->PathId;
1798 srb->TargetId = deviceExtension->TargetId;
1799 srb->Lun = deviceExtension->Lun;
1800 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1801 srb->Cdb[1] |= deviceExtension->Lun << 5;
1802 srb->SrbStatus = srb->ScsiStatus = 0;
1803 srb->NextSrb = 0;
1804 srb->OriginalRequest = irp2;
1805 srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
1806 srb->SenseInfoBuffer = senseBuffer;
1807
1808 switch (currentIrpStack->Parameters.DeviceIoControl.IoControlCode) {
1809
1810 case IOCTL_CDROM_RAW_READ: {
1811
1812 //
1813 // Determine whether the drive is currently in raw or cooked mode,
1814 // and which command to use to read the data.
1815 //
1816
1817 if (!(cdData->XAFlags & XA_USE_READ_CD)) {
1818
1819 PRAW_READ_INFO rawReadInfo =
1820 (PRAW_READ_INFO)currentIrpStack->Parameters.DeviceIoControl.Type3InputBuffer;
1821 ULONG maximumTransferLength;
1822 ULONG transferPages;
1823
1824 if (cdData->RawAccess) {
1825
1826 ULONG startingSector;
1827
1828 //
1829 // Free the recently allocated irp, as we don't need it.
1830 //
1831
1832 IoFreeIrp(irp2);
1833
1834 cdb = (PCDB)srb->Cdb;
1835 RtlZeroMemory(cdb, 12);
1836
1837 //
1838 // Calculate starting offset.
1839 //
1840
1841 startingSector = (ULONG)(rawReadInfo->DiskOffset.QuadPart >> deviceExtension->SectorShift);
1842 transferByteCount = rawReadInfo->SectorCount * RAW_SECTOR_SIZE;
1843 maximumTransferLength = deviceExtension->PortCapabilities->MaximumTransferLength;
1844 transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp->MdlAddress),
1845 transferByteCount);
1846
1847 //
1848 // Determine if request is within limits imposed by miniport.
1849 //
1850
1851 if (transferByteCount > maximumTransferLength ||
1852 transferPages > deviceExtension->PortCapabilities->MaximumPhysicalPages) {
1853
1854 //
1855 // The claim is that this won't happen, and is backed up by
1856 // ActiveMovie usage, which does unbuffered XA reads of 0x18000, yet
1857 // we get only 4 sector requests.
1858 //
1859
1860
1861 Irp->IoStatus.Information = 0;
1862 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
1863 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1864 ExFreePool(senseBuffer);
1865 ExFreePool(srb);
1866 IoStartNextPacket(DeviceObject, FALSE);
1867 return;
1868
1869 }
1870
1871 srb->OriginalRequest = Irp;
1872 srb->SrbFlags = deviceExtension->SrbFlags;
1873 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN);
1874 srb->DataTransferLength = transferByteCount;
1875 srb->TimeOutValue = deviceExtension->TimeOutValue;
1876 srb->CdbLength = 10;
1877 srb->DataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
1878
1879 if (rawReadInfo->TrackMode == CDDA) {
1880 if (cdData->XAFlags & PLEXTOR_CDDA) {
1881
1882 srb->CdbLength = 12;
1883
1884 cdb->PLXTR_READ_CDDA.LogicalUnitNumber = deviceExtension->Lun;
1885 cdb->PLXTR_READ_CDDA.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF);
1886 cdb->PLXTR_READ_CDDA.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF);
1887 cdb->PLXTR_READ_CDDA.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF);
1888 cdb->PLXTR_READ_CDDA.LogicalBlockByte0 = (UCHAR) ((startingSector >> 24) & 0xFF);
1889
1890 cdb->PLXTR_READ_CDDA.TransferBlockByte3 = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
1891 cdb->PLXTR_READ_CDDA.TransferBlockByte2 = (UCHAR) (rawReadInfo->SectorCount >> 8);
1892 cdb->PLXTR_READ_CDDA.TransferBlockByte1 = 0;
1893 cdb->PLXTR_READ_CDDA.TransferBlockByte0 = 0;
1894
1895 cdb->PLXTR_READ_CDDA.SubCode = 0;
1896 cdb->PLXTR_READ_CDDA.OperationCode = 0xD8;
1897
1898 } else if (cdData->XAFlags & NEC_CDDA) {
1899
1900 cdb->NEC_READ_CDDA.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF);
1901 cdb->NEC_READ_CDDA.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF);
1902 cdb->NEC_READ_CDDA.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF);
1903 cdb->NEC_READ_CDDA.LogicalBlockByte0 = (UCHAR) ((startingSector >> 24) & 0xFF);
1904
1905 cdb->NEC_READ_CDDA.TransferBlockByte1 = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
1906 cdb->NEC_READ_CDDA.TransferBlockByte0 = (UCHAR) (rawReadInfo->SectorCount >> 8);
1907
1908 cdb->NEC_READ_CDDA.OperationCode = 0xD4;
1909 }
1910 } else {
1911
1912 cdb->CDB10.LogicalUnitNumber = deviceExtension->Lun;
1913
1914 cdb->CDB10.TransferBlocksMsb = (UCHAR) (rawReadInfo->SectorCount >> 8);
1915 cdb->CDB10.TransferBlocksLsb = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
1916
1917 cdb->CDB10.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF);
1918 cdb->CDB10.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF);
1919 cdb->CDB10.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF);
1920 cdb->CDB10.LogicalBlockByte0 = (UCHAR) ((startingSector >> 24) & 0xFF);
1921
1922 cdb->CDB10.OperationCode = SCSIOP_READ;
1923 }
1924
1925 srb->SrbStatus = srb->ScsiStatus = 0;
1926
1927 nextIrpStack->MajorFunction = IRP_MJ_SCSI;
1928 nextIrpStack->Parameters.Scsi.Srb = srb;
1929
1930 if (!(nextIrpStack->Parameters.Others.Argument1)) {
1931
1932 //
1933 // Only jam this in if it doesn't exist. The completion routines can
1934 // call StartIo directly in the case of retries and resetting it will
1935 // cause infinite loops.
1936 //
1937
1938 nextIrpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES;
1939 }
1940
1941 //
1942 // Set up IoCompletion routine address.
1943 //
1944
1945 IoSetCompletionRoutine(Irp,
1946 CdRomXACompletion,
1947 srb,
1948 TRUE,
1949 TRUE,
1950 TRUE);
1951
1952 IoCallDriver(deviceExtension->PortDeviceObject, Irp);
1953 return;
1954
1955 } else {
1956
1957 transferByteCount = (use6Byte) ? sizeof(ERROR_RECOVERY_DATA) : sizeof(ERROR_RECOVERY_DATA10);
1958 dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned, transferByteCount );
1959 if (!dataBuffer) {
1960 Irp->IoStatus.Information = 0;
1961 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1962 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1963 ExFreePool(senseBuffer);
1964 ExFreePool(srb);
1965 IoFreeIrp(irp2);
1966 IoStartNextPacket(DeviceObject, FALSE);
1967 return;
1968
1969 }
1970
1971 irp2->MdlAddress = IoAllocateMdl(dataBuffer,
1972 transferByteCount,
1973 FALSE,
1974 FALSE,
1975 (PIRP) NULL);
1976
1977 if (!irp2->MdlAddress) {
1978 Irp->IoStatus.Information = 0;
1979 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1980 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1981 ExFreePool(senseBuffer);
1982 ExFreePool(srb);
1983 ExFreePool(dataBuffer);
1984 IoFreeIrp(irp2);
1985 IoStartNextPacket(DeviceObject, FALSE);
1986 return;
1987 }
1988
1989 //
1990 // Prepare the MDL
1991 //
1992
1993 MmBuildMdlForNonPagedPool(irp2->MdlAddress);
1994
1995 srb->DataBuffer = dataBuffer;
1996
1997 //
1998 // Set the new block size in the descriptor.
1999 //
2000
2001 cdData->u1.BlockDescriptor.BlockLength[0] = (UCHAR)(RAW_SECTOR_SIZE >> 16) & 0xFF;
2002 cdData->u1.BlockDescriptor.BlockLength[1] = (UCHAR)(RAW_SECTOR_SIZE >> 8) & 0xFF;
2003 cdData->u1.BlockDescriptor.BlockLength[2] = (UCHAR)(RAW_SECTOR_SIZE & 0xFF);
2004
2005
2006 //
2007 // TODO: Set density code, based on operation
2008 //
2009
2010 cdData->u1.BlockDescriptor.DensityCode = 0;
2011
2012
2013 //
2014 // Move error page into dataBuffer.
2015 //
2016
2017 RtlCopyMemory(srb->DataBuffer, &cdData->u1.Header, transferByteCount);
2018
2019
2020 //
2021 // Build and send a mode select to switch into raw mode.
2022 //
2023
2024 srb->SrbFlags = deviceExtension->SrbFlags;
2025 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_OUT);
2026 srb->DataTransferLength = transferByteCount;
2027 srb->TimeOutValue = deviceExtension->TimeOutValue * 2;
2028
2029 if (use6Byte) {
2030 srb->CdbLength = 6;
2031 cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
2032 cdb->MODE_SELECT.PFBit = 1;
2033 cdb->MODE_SELECT.ParameterListLength = (UCHAR)transferByteCount;
2034 } else {
2035
2036 srb->CdbLength = 10;
2037 cdb->MODE_SELECT10.OperationCode = SCSIOP_MODE_SELECT10;
2038 cdb->MODE_SELECT10.PFBit = 1;
2039 cdb->MODE_SELECT10.ParameterListLength[0] = (UCHAR)(transferByteCount >> 8);
2040 cdb->MODE_SELECT10.ParameterListLength[1] = (UCHAR)(transferByteCount & 0xFF);
2041 }
2042
2043 //
2044 // Update completion routine.
2045 //
2046
2047 IoSetCompletionRoutine(irp2,
2048 CdRomSwitchModeCompletion,
2049 srb,
2050 TRUE,
2051 TRUE,
2052 TRUE);
2053
2054 }
2055
2056 } else {
2057
2058 PRAW_READ_INFO rawReadInfo =
2059 (PRAW_READ_INFO)currentIrpStack->Parameters.DeviceIoControl.Type3InputBuffer;
2060 ULONG startingSector;
2061
2062 //
2063 // Free the recently allocated irp, as we don't need it.
2064 //
2065
2066 IoFreeIrp(irp2);
2067
2068 cdb = (PCDB)srb->Cdb;
2069 RtlZeroMemory(cdb, 12);
2070
2071
2072 //
2073 // Calculate starting offset.
2074 //
2075
2076 startingSector = (ULONG)(rawReadInfo->DiskOffset.QuadPart >> deviceExtension->SectorShift);
2077 transferByteCount = rawReadInfo->SectorCount * RAW_SECTOR_SIZE;
2078
2079
2080 srb->OriginalRequest = Irp;
2081 srb->SrbFlags = deviceExtension->SrbFlags;
2082 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN);
2083 srb->DataTransferLength = transferByteCount;
2084 srb->TimeOutValue = deviceExtension->TimeOutValue;
2085 srb->DataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
2086 srb->CdbLength = 12;
2087 srb->SrbStatus = srb->ScsiStatus = 0;
2088
2089 //
2090 // Fill in CDB fields.
2091 //
2092
2093 cdb = (PCDB)srb->Cdb;
2094
2095
2096 cdb->READ_CD.TransferBlocks[2] = (UCHAR) (rawReadInfo->SectorCount & 0xFF);
2097 cdb->READ_CD.TransferBlocks[1] = (UCHAR) (rawReadInfo->SectorCount >> 8 );
2098 cdb->READ_CD.TransferBlocks[0] = (UCHAR) (rawReadInfo->SectorCount >> 16);
2099
2100
2101 cdb->READ_CD.StartingLBA[3] = (UCHAR) (startingSector & 0xFF);
2102 cdb->READ_CD.StartingLBA[2] = (UCHAR) ((startingSector >> 8));
2103 cdb->READ_CD.StartingLBA[1] = (UCHAR) ((startingSector >> 16));
2104 cdb->READ_CD.StartingLBA[0] = (UCHAR) ((startingSector >> 24));
2105
2106 //
2107 // Setup cdb depending upon the sector type we want.
2108 //
2109
2110 switch (rawReadInfo->TrackMode) {
2111 case CDDA:
2112
2113 cdb->READ_CD.ExpectedSectorType = CD_DA_SECTOR;
2114 cdb->READ_CD.IncludeUserData = 1;
2115 cdb->READ_CD.HeaderCode = 3;
2116 cdb->READ_CD.IncludeSyncData = 1;
2117 break;
2118
2119 case YellowMode2:
2120
2121 cdb->READ_CD.ExpectedSectorType = YELLOW_MODE2_SECTOR;
2122 cdb->READ_CD.IncludeUserData = 1;
2123 cdb->READ_CD.HeaderCode = 1;
2124 cdb->READ_CD.IncludeSyncData = 1;
2125 break;
2126
2127 case XAForm2:
2128
2129 cdb->READ_CD.ExpectedSectorType = FORM2_MODE2_SECTOR;
2130 cdb->READ_CD.IncludeUserData = 1;
2131 cdb->READ_CD.HeaderCode = 3;
2132 cdb->READ_CD.IncludeSyncData = 1;
2133 break;
2134
2135 default:
2136 Irp->IoStatus.Information = 0;
2137 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
2138 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2139 ExFreePool(senseBuffer);
2140 ExFreePool(srb);
2141 IoFreeIrp(irp2);
2142 IoStartNextPacket(DeviceObject, FALSE);
2143 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp, Irp->IoStatus.Status, __LINE__));
2144 return;
2145 }
2146
2147 cdb->READ_CD.OperationCode = SCSIOP_READ_CD;
2148
2149 nextIrpStack->MajorFunction = IRP_MJ_SCSI;
2150 nextIrpStack->Parameters.Scsi.Srb = srb;
2151
2152 if (!(nextIrpStack->Parameters.Others.Argument1)) {
2153
2154 //
2155 // Only jam this in if it doesn't exist. The completion routines can
2156 // call StartIo directly in the case of retries and resetting it will
2157 // cause infinite loops.
2158 //
2159
2160 nextIrpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES;
2161 }
2162
2163 //
2164 // Set up IoCompletion routine address.
2165 //
2166
2167 IoSetCompletionRoutine(Irp,
2168 CdRomXACompletion,
2169 srb,
2170 TRUE,
2171 TRUE,
2172 TRUE);
2173
2174 IoCallDriver(deviceExtension->PortDeviceObject, Irp);
2175 return;
2176
2177 }
2178
2179 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2180 return;
2181 }
2182
2183 case IOCTL_CDROM_GET_DRIVE_GEOMETRY: {
2184
2185 //
2186 // Issue ReadCapacity to update device extension
2187 // with information for current media.
2188 //
2189
2190 DebugPrint((3,
2191 "CdRomStartIo: Get drive capacity\n"));
2192
2193 //
2194 // setup remaining srb and cdb parameters.
2195 //
2196
2197 srb->SrbFlags = deviceExtension->SrbFlags;
2198 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN);
2199 srb->DataTransferLength = sizeof(READ_CAPACITY_DATA);
2200 srb->CdbLength = 10;
2201 srb->TimeOutValue = deviceExtension->TimeOutValue;
2202
2203 dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned, sizeof(READ_CAPACITY_DATA));
2204 if (!dataBuffer) {
2205 Irp->IoStatus.Information = 0;
2206 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2207 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2208 ExFreePool(senseBuffer);
2209 ExFreePool(srb);
2210 IoFreeIrp(irp2);
2211 IoStartNextPacket(DeviceObject, FALSE);
2212 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp, Irp->IoStatus.Status, __LINE__));
2213 return;
2214
2215 }
2216
2217 irp2->MdlAddress = IoAllocateMdl(dataBuffer,
2218 sizeof(READ_CAPACITY_DATA),
2219 FALSE,
2220 FALSE,
2221 (PIRP) NULL);
2222
2223 if (!irp2->MdlAddress) {
2224 Irp->IoStatus.Information = 0;
2225 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2226 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2227 ExFreePool(senseBuffer);
2228 ExFreePool(srb);
2229 ExFreePool(dataBuffer);
2230 IoFreeIrp(irp2);
2231 IoStartNextPacket(DeviceObject, FALSE);
2232 DebugPrint((2, "ScsiCdRomStartIo: [%lx] bailing with status %lx at line %s\n", Irp, Irp->IoStatus.Status, __LINE__));
2233 return;
2234 }
2235
2236 //
2237 // Prepare the MDL
2238 //
2239
2240 MmBuildMdlForNonPagedPool(irp2->MdlAddress);
2241
2242 srb->DataBuffer = dataBuffer;
2243 cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
2244
2245 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2246 return;
2247 }
2248
2249 case IOCTL_CDROM_CHECK_VERIFY: {
2250
2251 //
2252 // Since a test unit ready is about to be performed, reset the timer
2253 // value to decrease the opportunities for it to race with this code.
2254 //
2255
2256 cdData->MediaChangeCountDown = MEDIA_CHANGE_DEFAULT_TIME;
2257
2258 //
2259 // Set up the SRB/CDB
2260 //
2261
2262 srb->CdbLength = 6;
2263 cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
2264 srb->TimeOutValue = deviceExtension->TimeOutValue * 2;
2265 srb->SrbFlags = deviceExtension->SrbFlags;
2266 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_DATA_TRANSFER);
2267
2268 DebugPrint((2, "ScsiCdRomStartIo: [%lx] Sending CHECK_VERIFY irp %lx\n", Irp, irp2));
2269 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2270 return;
2271 }
2272
2273 case IOCTL_CDROM_GET_LAST_SESSION:
2274
2275 //
2276 // Set format to return first and last session numbers.
2277 //
2278
2279 cdb->READ_TOC.Format = GET_LAST_SESSION;
2280
2281 //
2282 // Fall through to READ TOC code.
2283 //
2284
2285 case IOCTL_CDROM_READ_TOC: {
2286
2287
2288 if (currentIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_READ_TOC) {
2289
2290 //
2291 // Use MSF addressing if not request for session information.
2292 //
2293
2294 cdb->READ_TOC.Msf = CDB_USE_MSF;
2295 }
2296
2297 //
2298 // Set size of TOC structure.
2299 //
2300
2301 transferByteCount =
2302 currentIrpStack->Parameters.Read.Length >
2303 sizeof(CDROM_TOC) ? sizeof(CDROM_TOC):
2304 currentIrpStack->Parameters.Read.Length;
2305
2306 cdb->READ_TOC.AllocationLength[0] = (UCHAR) (transferByteCount >> 8);
2307 cdb->READ_TOC.AllocationLength[1] = (UCHAR) (transferByteCount & 0xFF);
2308
2309 cdb->READ_TOC.Control = 0;
2310
2311 //
2312 // Start at beginning of disc.
2313 //
2314
2315 cdb->READ_TOC.StartingTrack = 0;
2316
2317 //
2318 // setup remaining srb and cdb parameters.
2319 //
2320
2321 srb->SrbFlags = deviceExtension->SrbFlags;
2322 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN);
2323 srb->DataTransferLength = transferByteCount;
2324 srb->CdbLength = 10;
2325 srb->TimeOutValue = deviceExtension->TimeOutValue;
2326
2327 dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned, transferByteCount);
2328 if (!dataBuffer) {
2329 Irp->IoStatus.Information = 0;
2330 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2331 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2332 ExFreePool(senseBuffer);
2333 ExFreePool(srb);
2334 IoFreeIrp(irp2);
2335 IoStartNextPacket(DeviceObject, FALSE);
2336 return;
2337
2338 }
2339
2340 irp2->MdlAddress = IoAllocateMdl(dataBuffer,
2341 transferByteCount,
2342 FALSE,
2343 FALSE,
2344 (PIRP) NULL);
2345
2346 if (!irp2->MdlAddress) {
2347 Irp->IoStatus.Information = 0;
2348 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2349 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2350 ExFreePool(senseBuffer);
2351 ExFreePool(srb);
2352 ExFreePool(dataBuffer);
2353 IoFreeIrp(irp2);
2354 IoStartNextPacket(DeviceObject, FALSE);
2355 return;
2356 }
2357
2358 //
2359 // Prepare the MDL
2360 //
2361
2362 MmBuildMdlForNonPagedPool(irp2->MdlAddress);
2363
2364 srb->DataBuffer = dataBuffer;
2365 cdb->READ_TOC.OperationCode = SCSIOP_READ_TOC;
2366
2367 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2368 return;
2369
2370 }
2371
2372 case IOCTL_CDROM_PLAY_AUDIO_MSF: {
2373
2374 PCDROM_PLAY_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
2375
2376 //
2377 // Set up the SRB/CDB
2378 //
2379
2380 srb->CdbLength = 10;
2381 cdb->PLAY_AUDIO_MSF.OperationCode = SCSIOP_PLAY_AUDIO_MSF;
2382
2383 cdb->PLAY_AUDIO_MSF.StartingM = inputBuffer->StartingM;
2384 cdb->PLAY_AUDIO_MSF.StartingS = inputBuffer->StartingS;
2385 cdb->PLAY_AUDIO_MSF.StartingF = inputBuffer->StartingF;
2386
2387 cdb->PLAY_AUDIO_MSF.EndingM = inputBuffer->EndingM;
2388 cdb->PLAY_AUDIO_MSF.EndingS = inputBuffer->EndingS;
2389 cdb->PLAY_AUDIO_MSF.EndingF = inputBuffer->EndingF;
2390
2391 srb->TimeOutValue = deviceExtension->TimeOutValue;
2392 srb->SrbFlags = deviceExtension->SrbFlags;
2393 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_DATA_TRANSFER);
2394
2395 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2396 return;
2397
2398 }
2399
2400 case IOCTL_CDROM_READ_Q_CHANNEL: {
2401
2402 PCDROM_SUB_Q_DATA_FORMAT inputBuffer =
2403 Irp->AssociatedIrp.SystemBuffer;
2404
2405 //
2406 // Allocate buffer for subq channel information.
2407 //
2408
2409 dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
2410 sizeof(SUB_Q_CHANNEL_DATA));
2411
2412 if (!dataBuffer) {
2413 Irp->IoStatus.Information = 0;
2414 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2415 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2416 ExFreePool(senseBuffer);
2417 ExFreePool(srb);
2418 IoFreeIrp(irp2);
2419 IoStartNextPacket(DeviceObject, FALSE);
2420 return;
2421
2422 }
2423
2424 irp2->MdlAddress = IoAllocateMdl(dataBuffer,
2425 transferByteCount,
2426 FALSE,
2427 FALSE,
2428 (PIRP) NULL);
2429
2430 if (!irp2->MdlAddress) {
2431 Irp->IoStatus.Information = 0;
2432 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2433 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2434 ExFreePool(senseBuffer);
2435 ExFreePool(srb);
2436 ExFreePool(dataBuffer);
2437 IoFreeIrp(irp2);
2438 IoStartNextPacket(DeviceObject, FALSE);
2439 return;
2440 }
2441
2442 //
2443 // Prepare the MDL
2444 //
2445
2446 MmBuildMdlForNonPagedPool(irp2->MdlAddress);
2447
2448 srb->DataBuffer = dataBuffer;
2449
2450 //
2451 // Always logical unit 0, but only use MSF addressing
2452 // for IOCTL_CDROM_CURRENT_POSITION
2453 //
2454
2455 if (inputBuffer->Format==IOCTL_CDROM_CURRENT_POSITION)
2456 cdb->SUBCHANNEL.Msf = CDB_USE_MSF;
2457
2458 //
2459 // Return subchannel data
2460 //
2461
2462 cdb->SUBCHANNEL.SubQ = CDB_SUBCHANNEL_BLOCK;
2463
2464 //
2465 // Specify format of informatin to return
2466 //
2467
2468 cdb->SUBCHANNEL.Format = inputBuffer->Format;
2469
2470 //
2471 // Specify which track to access (only used by Track ISRC reads)
2472 //
2473
2474 if (inputBuffer->Format==IOCTL_CDROM_TRACK_ISRC) {
2475 cdb->SUBCHANNEL.TrackNumber = inputBuffer->Track;
2476 }
2477
2478 //
2479 // Set size of channel data -- however, this is dependent on
2480 // what information we are requesting (which Format)
2481 //
2482
2483 switch( inputBuffer->Format ) {
2484
2485 case IOCTL_CDROM_CURRENT_POSITION:
2486 transferByteCount = sizeof(SUB_Q_CURRENT_POSITION);
2487 break;
2488
2489 case IOCTL_CDROM_MEDIA_CATALOG:
2490 transferByteCount = sizeof(SUB_Q_MEDIA_CATALOG_NUMBER);
2491 break;
2492
2493 case IOCTL_CDROM_TRACK_ISRC:
2494 transferByteCount = sizeof(SUB_Q_TRACK_ISRC);
2495 break;
2496 }
2497
2498 cdb->SUBCHANNEL.AllocationLength[0] = (UCHAR) (transferByteCount >> 8);
2499 cdb->SUBCHANNEL.AllocationLength[1] = (UCHAR) (transferByteCount & 0xFF);
2500 cdb->SUBCHANNEL.OperationCode = SCSIOP_READ_SUB_CHANNEL;
2501 srb->SrbFlags = deviceExtension->SrbFlags;
2502 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN);
2503 srb->DataTransferLength = transferByteCount;
2504 srb->CdbLength = 10;
2505 srb->TimeOutValue = deviceExtension->TimeOutValue;
2506
2507 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2508 return;
2509
2510 }
2511
2512 case IOCTL_CDROM_PAUSE_AUDIO: {
2513
2514 cdb->PAUSE_RESUME.OperationCode = SCSIOP_PAUSE_RESUME;
2515 cdb->PAUSE_RESUME.Action = CDB_AUDIO_PAUSE;
2516
2517 srb->CdbLength = 10;
2518 srb->TimeOutValue = deviceExtension->TimeOutValue;
2519 srb->SrbFlags = deviceExtension->SrbFlags;
2520 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_DATA_TRANSFER);
2521
2522 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2523 return;
2524 }
2525
2526 case IOCTL_CDROM_RESUME_AUDIO: {
2527
2528 cdb->PAUSE_RESUME.OperationCode = SCSIOP_PAUSE_RESUME;
2529 cdb->PAUSE_RESUME.Action = CDB_AUDIO_RESUME;
2530
2531 srb->CdbLength = 10;
2532 srb->TimeOutValue = deviceExtension->TimeOutValue;
2533 srb->SrbFlags = deviceExtension->SrbFlags;
2534 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_DATA_TRANSFER);
2535
2536 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2537 return;
2538 }
2539
2540 case IOCTL_CDROM_SEEK_AUDIO_MSF: {
2541
2542 PCDROM_SEEK_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
2543 ULONG logicalBlockAddress;
2544
2545 logicalBlockAddress = MSF_TO_LBA(inputBuffer->M, inputBuffer->S, inputBuffer->F);
2546
2547 cdb->SEEK.OperationCode = SCSIOP_SEEK;
2548 cdb->SEEK.LogicalBlockAddress[0] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte3;
2549 cdb->SEEK.LogicalBlockAddress[1] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte2;
2550 cdb->SEEK.LogicalBlockAddress[2] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte1;
2551 cdb->SEEK.LogicalBlockAddress[3] = ((PFOUR_BYTE)&logicalBlockAddress)->Byte0;
2552
2553 srb->CdbLength = 10;
2554 srb->TimeOutValue = deviceExtension->TimeOutValue;
2555 srb->SrbFlags = deviceExtension->SrbFlags;
2556 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_DATA_TRANSFER);
2557
2558 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2559 return;
2560
2561 }
2562
2563 case IOCTL_CDROM_STOP_AUDIO: {
2564
2565 cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
2566 cdb->START_STOP.Immediate = 1;
2567 cdb->START_STOP.Start = 0;
2568 cdb->START_STOP.LoadEject = 0;
2569
2570 srb->CdbLength = 6;
2571 srb->TimeOutValue = deviceExtension->TimeOutValue;
2572
2573 srb->SrbFlags = deviceExtension->SrbFlags;
2574 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_DATA_TRANSFER);
2575
2576 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2577 return;
2578 }
2579
2580 case IOCTL_CDROM_GET_CONTROL: {
2581 //
2582 // Allocate buffer for volume control information.
2583 //
2584
2585 dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
2586 MODE_DATA_SIZE);
2587
2588 if (!dataBuffer) {
2589 Irp->IoStatus.Information = 0;
2590 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2591 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2592 ExFreePool(senseBuffer);
2593 ExFreePool(srb);
2594 IoFreeIrp(irp2);
2595 IoStartNextPacket(DeviceObject, FALSE);
2596 return;
2597
2598 }
2599
2600 irp2->MdlAddress = IoAllocateMdl(dataBuffer,
2601 MODE_DATA_SIZE,
2602 FALSE,
2603 FALSE,
2604 (PIRP) NULL);
2605
2606 if (!irp2->MdlAddress) {
2607 Irp->IoStatus.Information = 0;
2608 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2609 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2610 ExFreePool(senseBuffer);
2611 ExFreePool(srb);
2612 ExFreePool(dataBuffer);
2613 IoFreeIrp(irp2);
2614 IoStartNextPacket(DeviceObject, FALSE);
2615 return;
2616 }
2617
2618 //
2619 // Prepare the MDL
2620 //
2621
2622 MmBuildMdlForNonPagedPool(irp2->MdlAddress);
2623 srb->DataBuffer = dataBuffer;
2624
2625 RtlZeroMemory(dataBuffer, MODE_DATA_SIZE);
2626
2627 //
2628 // Setup for either 6 or 10 byte CDBs.
2629 //
2630
2631 if (use6Byte) {
2632
2633 cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
2634 cdb->MODE_SENSE.PageCode = CDROM_AUDIO_CONTROL_PAGE;
2635 cdb->MODE_SENSE.AllocationLength = MODE_DATA_SIZE;
2636
2637 //
2638 // Disable block descriptors.
2639 //
2640
2641 cdb->MODE_SENSE.Dbd = TRUE;
2642
2643 srb->CdbLength = 6;
2644 } else {
2645
2646 cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
2647 cdb->MODE_SENSE10.PageCode = CDROM_AUDIO_CONTROL_PAGE;
2648 cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(MODE_DATA_SIZE >> 8);
2649 cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(MODE_DATA_SIZE & 0xFF);
2650
2651 //
2652 // Disable block descriptors.
2653 //
2654
2655 cdb->MODE_SENSE10.Dbd = TRUE;
2656
2657 srb->CdbLength = 10;
2658 }
2659
2660 srb->TimeOutValue = deviceExtension->TimeOutValue;
2661 srb->DataTransferLength = MODE_DATA_SIZE;
2662 srb->SrbFlags = deviceExtension->SrbFlags;
2663 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN);
2664
2665 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2666 return;
2667
2668 }
2669
2670 case IOCTL_CDROM_GET_VOLUME:
2671 case IOCTL_CDROM_SET_VOLUME: {
2672
2673 dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
2674 MODE_DATA_SIZE);
2675
2676 if (!dataBuffer) {
2677 Irp->IoStatus.Information = 0;
2678 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2679 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2680 ExFreePool(senseBuffer);
2681 ExFreePool(srb);
2682 IoFreeIrp(irp2);
2683 IoStartNextPacket(DeviceObject, FALSE);
2684 return;
2685 }
2686
2687 irp2->MdlAddress = IoAllocateMdl(dataBuffer,
2688 MODE_DATA_SIZE,
2689 FALSE,
2690 FALSE,
2691 (PIRP) NULL);
2692
2693 if (!irp2->MdlAddress) {
2694 Irp->IoStatus.Information = 0;
2695 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2696 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2697 ExFreePool(senseBuffer);
2698 ExFreePool(srb);
2699 ExFreePool(dataBuffer);
2700 IoFreeIrp(irp2);
2701 IoStartNextPacket(DeviceObject, FALSE);
2702 return;
2703 }
2704
2705 //
2706 // Prepare the MDL
2707 //
2708
2709 MmBuildMdlForNonPagedPool(irp2->MdlAddress);
2710 srb->DataBuffer = dataBuffer;
2711
2712 RtlZeroMemory(dataBuffer, MODE_DATA_SIZE);
2713
2714
2715 if (use6Byte) {
2716 cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
2717 cdb->MODE_SENSE.PageCode = CDROM_AUDIO_CONTROL_PAGE;
2718 cdb->MODE_SENSE.AllocationLength = MODE_DATA_SIZE;
2719
2720 srb->CdbLength = 6;
2721
2722 } else {
2723
2724 cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
2725 cdb->MODE_SENSE10.PageCode = CDROM_AUDIO_CONTROL_PAGE;
2726 cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(MODE_DATA_SIZE >> 8);
2727 cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(MODE_DATA_SIZE & 0xFF);
2728
2729 srb->CdbLength = 10;
2730 }
2731
2732 srb->TimeOutValue = deviceExtension->TimeOutValue;
2733 srb->DataTransferLength = MODE_DATA_SIZE;
2734 srb->SrbFlags = deviceExtension->SrbFlags;
2735 srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN);
2736
2737 if (currentIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_SET_VOLUME) {
2738
2739 //
2740 // Setup a different completion routine as the mode sense data is needed in order
2741 // to send the mode select.
2742 //
2743
2744 IoSetCompletionRoutine(irp2,
2745 CdRomSetVolumeIntermediateCompletion,
2746 srb,
2747 TRUE,
2748 TRUE,
2749 TRUE);
2750
2751 }
2752
2753 IoCallDriver(deviceExtension->PortDeviceObject, irp2);
2754 return;
2755
2756 }
2757
2758 default:
2759
2760 //
2761 // Just complete the request - CdRomClassIoctlCompletion will take
2762 // care of it for us
2763 //
2764
2765 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2766 return;
2767
2768 } // end switch()
2769 }
2770
2771 //
2772 // If a read or an unhandled IRP_MJ_XX, end up here. The unhandled IRP_MJ's
2773 // are expected and composed of AutoRun Irps, at present.
2774 //
2775
2776 IoCallDriver(deviceExtension->PortDeviceObject, Irp);
2777 return;
2778 }
2779
2780
2781 NTSTATUS
2782 NTAPI
2783 ScsiCdRomReadVerification(
2784 IN PDEVICE_OBJECT DeviceObject,
2785 IN PIRP Irp
2786 )
2787
2788 /*++
2789
2790 Routine Description:
2791
2792 This is the entry called by the I/O system for read requests.
2793 It builds the SRB and sends it to the port driver.
2794
2795 Arguments:
2796
2797 DeviceObject - the system object for the device.
2798 Irp - IRP involved.
2799
2800 Return Value:
2801
2802 NT Status
2803
2804 --*/
2805
2806 {
2807 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
2808 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
2809 ULONG transferByteCount = currentIrpStack->Parameters.Read.Length;
2810 LARGE_INTEGER startingOffset = currentIrpStack->Parameters.Read.ByteOffset;
2811
2812 //
2813 // If the cd is playing music then reject this request.
2814 //
2815
2816 if (PLAY_ACTIVE(deviceExtension)) {
2817 Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
2818 return STATUS_DEVICE_BUSY;
2819 }
2820
2821 //
2822 // Verify parameters of this request.
2823 // Check that ending sector is on disc and
2824 // that number of bytes to transfer is a multiple of
2825 // the sector size.
2826 //
2827
2828 startingOffset.QuadPart = currentIrpStack->Parameters.Read.ByteOffset.QuadPart +
2829 transferByteCount;
2830
2831 if (!deviceExtension->DiskGeometry->BytesPerSector) {
2832 deviceExtension->DiskGeometry->BytesPerSector = 2048;
2833 }
2834
2835 if ((startingOffset.QuadPart > deviceExtension->PartitionLength.QuadPart) ||
2836 (transferByteCount & (deviceExtension->DiskGeometry->BytesPerSector - 1))) {
2837
2838 DebugPrint((1,"ScsiCdRomRead: Invalid I/O parameters\n"));
2839 DebugPrint((1, "\toffset %x:%x, Length %x:%x\n",
2840 startingOffset.u.HighPart,
2841 startingOffset.u.LowPart,
2842 deviceExtension->PartitionLength.u.HighPart,
2843 deviceExtension->PartitionLength.u.LowPart));
2844 DebugPrint((1, "\tbps %x\n", deviceExtension->DiskGeometry->BytesPerSector));
2845
2846 //
2847 // Fail request with status of invalid parameters.
2848 //
2849
2850 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
2851
2852 return STATUS_INVALID_PARAMETER;
2853 }
2854
2855
2856 return STATUS_SUCCESS;
2857
2858 } // end ScsiCdRomReadVerification()
2859
2860
2861 NTSTATUS
2862 NTAPI
2863 CdRomDeviceControlCompletion(
2864 IN PDEVICE_OBJECT DeviceObject,
2865 IN PIRP Irp,
2866 IN PVOID Context
2867 )
2868 {
2869 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
2870 PDEVICE_EXTENSION physicalExtension = deviceExtension->PhysicalDevice->DeviceExtension;
2871 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
2872 PCDROM_DATA cdData = (PCDROM_DATA)(deviceExtension + 1);
2873 BOOLEAN use6Byte = cdData->XAFlags & XA_USE_6_BYTE;
2874 PIO_STACK_LOCATION realIrpStack;
2875 PIO_STACK_LOCATION realIrpNextStack;
2876 PSCSI_REQUEST_BLOCK srb = Context;
2877 PIRP realIrp = NULL;
2878 NTSTATUS status;
2879 BOOLEAN retry;
2880
2881 //
2882 // Extract the 'real' irp from the irpstack.
2883 //
2884
2885 realIrp = (PIRP) irpStack->Parameters.Others.Argument2;
2886 realIrpStack = IoGetCurrentIrpStackLocation(realIrp);
2887 realIrpNextStack = IoGetNextIrpStackLocation(realIrp);
2888
2889 //
2890 // Check SRB status for success of completing request.
2891 //
2892
2893 if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
2894
2895 DebugPrint((2,
2896 "CdRomDeviceControlCompletion: Irp %lx, Srb %lx Real Irp %lx Status %lx\n",
2897 Irp,
2898 srb,
2899 realIrp,
2900 srb->SrbStatus));
2901
2902 //
2903 // Release the queue if it is frozen.
2904 //
2905
2906 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
2907 DebugPrint((2, "CdRomDeviceControlCompletion: Releasing Queue\n"));
2908 ScsiClassReleaseQueue(DeviceObject);
2909 }
2910
2911
2912 retry = ScsiClassInterpretSenseInfo(DeviceObject,
2913 srb,
2914 irpStack->MajorFunction,
2915 irpStack->Parameters.DeviceIoControl.IoControlCode,
2916 MAXIMUM_RETRIES - ((ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1),
2917 &status);
2918
2919 DebugPrint((2, "CdRomDeviceControlCompletion: IRP will %sbe retried\n",
2920 (retry ? "" : "not ")));
2921
2922 //
2923 // Some of the Device Controls need special cases on non-Success status's.
2924 //
2925
2926 if (realIrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) {
2927 if ((realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_GET_LAST_SESSION) ||
2928 (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_READ_TOC) ||
2929 (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_GET_CONTROL) ||
2930 (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_GET_VOLUME)) {
2931
2932 if (status == STATUS_DATA_OVERRUN) {
2933 status = STATUS_SUCCESS;
2934 retry = FALSE;
2935 }
2936 }
2937
2938 if (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_READ_Q_CHANNEL) {
2939 PLAY_ACTIVE(deviceExtension) = FALSE;
2940 }
2941 }
2942
2943 //
2944 // If the status is verified required and the this request
2945 // should bypass verify required then retry the request.
2946 //
2947
2948 if (realIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME &&
2949 status == STATUS_VERIFY_REQUIRED) {
2950
2951 if (((realIrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) ||
2952 (realIrpStack->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL)) &&
2953 (realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_CHECK_VERIFY)) {
2954
2955 //
2956 // Update the geometry information, as the media could have changed.
2957 // The completion routine for this will complete the real irp and start
2958 // the next packet.
2959 //
2960
2961 status = CdRomUpdateCapacity(deviceExtension,realIrp, NULL);
2962 DebugPrint((2, "CdRomDeviceControlCompletion: [%lx] CdRomUpdateCapacity completed with status %lx\n", realIrp, status));
2963 ASSERT(status == STATUS_PENDING);
2964
2965 return STATUS_MORE_PROCESSING_REQUIRED;
2966
2967 } else {
2968
2969 status = STATUS_IO_DEVICE_ERROR;
2970 retry = TRUE;
2971 }
2972
2973 }
2974
2975 if (retry && (realIrpNextStack->Parameters.Others.Argument1 = (PVOID)((ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1-1))) {
2976
2977
2978 if (((ULONG_PTR)realIrpNextStack->Parameters.Others.Argument1)) {
2979
2980 //
2981 // Retry request.
2982 //
2983
2984 DebugPrint((1, "Retry request %lx - Calling StartIo\n", Irp));
2985
2986
2987 ExFreePool(srb->SenseInfoBuffer);
2988 if (srb->DataBuffer) {
2989 ExFreePool(srb->DataBuffer);
2990 }
2991 ExFreePool(srb);
2992 if (Irp->MdlAddress) {
2993 IoFreeMdl(Irp->MdlAddress);
2994 }
2995
2996 IoFreeIrp(Irp);
2997
2998 //
2999 // Call StartIo directly since IoStartNextPacket hasn't been called,
3000 // the serialisation is still intact.
3001 //
3002
3003 ScsiCdRomStartIo(DeviceObject, realIrp);
3004 return STATUS_MORE_PROCESSING_REQUIRED;
3005
3006 }
3007
3008 //
3009 // Exhausted retries. Fall through and complete the request with the appropriate status.
3010 //
3011
3012 }
3013 } else {
3014
3015 //
3016 // Set status for successful request.
3017 //
3018
3019 status = STATUS_SUCCESS;
3020 }
3021
3022 if (NT_SUCCESS(status)) {
3023
3024 switch (realIrpStack->Parameters.DeviceIoControl.IoControlCode) {
3025
3026 case IOCTL_CDROM_GET_DRIVE_GEOMETRY: {
3027
3028 PREAD_CAPACITY_DATA readCapacityBuffer = srb->DataBuffer;
3029 ULONG lastSector;
3030 ULONG bps;
3031 ULONG lastBit;
3032 ULONG tmp;
3033
3034 //
3035 // Swizzle bytes from Read Capacity and translate into
3036 // the necessary geometry information in the device extension.
3037 //
3038
3039 tmp = readCapacityBuffer->BytesPerBlock;
3040 ((PFOUR_BYTE)&bps)->Byte0 = ((PFOUR_BYTE)&tmp)->Byte3;
3041 ((PFOUR_BYTE)&bps)->Byte1 = ((PFOUR_BYTE)&tmp)->Byte2;
3042 ((PFOUR_BYTE)&bps)->Byte2 = ((PFOUR_BYTE)&tmp)->Byte1;
3043 ((PFOUR_BYTE)&bps)->Byte3 = ((PFOUR_BYTE)&tmp)->Byte0;
3044
3045 //
3046 // Insure that bps is a power of 2.
3047 // This corrects a problem with the HP 4020i CDR where it
3048 // returns an incorrect number for bytes per sector.
3049 //
3050
3051 if (!bps) {
3052 bps = 2048;
3053 } else {
3054 lastBit = (ULONG) -1;
3055 while (bps) {
3056 lastBit++;
3057 bps = bps >> 1;
3058 }
3059
3060 bps = 1 << lastBit;
3061 }
3062 deviceExtension->DiskGeometry->BytesPerSector = bps;
3063
3064 DebugPrint((2,
3065 "CdRomDeviceControlCompletion: Calculated bps %#x\n",
3066 deviceExtension->DiskGeometry->BytesPerSector));
3067
3068 //
3069 // Copy last sector in reverse byte order.
3070 //
3071
3072 tmp = readCapacityBuffer->LogicalBlockAddress;
3073 ((PFOUR_BYTE)&lastSector)->Byte0 = ((PFOUR_BYTE)&tmp)->Byte3;
3074 ((PFOUR_BYTE)&lastSector)->Byte1 = ((PFOUR_BYTE)&tmp)->Byte2;
3075 ((PFOUR_BYTE)&lastSector)->Byte2 = ((PFOUR_BYTE)&tmp)->Byte1;
3076 ((PFOUR_BYTE)&lastSector)->Byte3 = ((PFOUR_BYTE)&tmp)->Byte0;
3077
3078 //
3079 // Calculate sector to byte shift.
3080 //
3081
3082 WHICH_BIT(bps, deviceExtension->SectorShift);
3083
3084 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Sector size is %d\n",
3085 deviceExtension->DiskGeometry->BytesPerSector));
3086
3087 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Number of Sectors is %d\n",
3088 lastSector + 1));
3089
3090 //
3091 // Calculate media capacity in bytes.
3092 //
3093
3094 deviceExtension->PartitionLength.QuadPart = (LONGLONG)(lastSector + 1);
3095
3096 //
3097 // Calculate number of cylinders.
3098 //
3099
3100 deviceExtension->DiskGeometry->Cylinders.QuadPart = (LONGLONG)((lastSector + 1)/(32 * 64));
3101
3102 deviceExtension->PartitionLength.QuadPart =
3103 (deviceExtension->PartitionLength.QuadPart << deviceExtension->SectorShift);
3104
3105 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
3106
3107 //
3108 // This device supports removable media.
3109 //
3110
3111 deviceExtension->DiskGeometry->MediaType = RemovableMedia;
3112
3113 } else {
3114
3115 //
3116 // Assume media type is fixed disk.
3117 //
3118
3119 deviceExtension->DiskGeometry->MediaType = FixedMedia;
3120 }
3121
3122 //
3123 // Assume sectors per track are 32;
3124 //
3125
3126 deviceExtension->DiskGeometry->SectorsPerTrack = 32;
3127
3128 //
3129 // Assume tracks per cylinder (number of heads) is 64.
3130 //
3131
3132 deviceExtension->DiskGeometry->TracksPerCylinder = 64;
3133
3134 //
3135 // Copy the device extension's geometry info into the user buffer.
3136 //
3137
3138 RtlMoveMemory(realIrp->AssociatedIrp.SystemBuffer,
3139 deviceExtension->DiskGeometry,
3140 sizeof(DISK_GEOMETRY));
3141
3142 //
3143 // update information field.
3144 //
3145
3146 realIrp->IoStatus.Information = sizeof(DISK_GEOMETRY);
3147 break;
3148 }
3149
3150 case IOCTL_CDROM_CHECK_VERIFY:
3151
3152 if((realIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_CHECK_VERIFY) &&
3153 (realIrpStack->Parameters.DeviceIoControl.OutputBufferLength)) {
3154
3155 *((PULONG)realIrp->AssociatedIrp.SystemBuffer) =
3156 physicalExtension->MediaChangeCount;
3157 realIrp->IoStatus.Information = sizeof(ULONG);
3158 } else {
3159 realIrp->IoStatus.Information = 0;
3160 }
3161
3162 DebugPrint((2, "CdRomDeviceControlCompletion: [%lx] completing CHECK_VERIFY buddy irp %lx\n", realIrp, Irp));
3163 break;
3164
3165 case IOCTL_CDROM_GET_LAST_SESSION:
3166 case IOCTL_CDROM_READ_TOC: {
3167
3168 PCDROM_TOC toc = srb->DataBuffer;
3169
3170 //
3171 // Copy the device extension's geometry info into the user buffer.
3172 //
3173
3174 RtlMoveMemory(realIrp->AssociatedIrp.SystemBuffer,
3175 toc,
3176 srb->DataTransferLength);
3177
3178 //
3179 // update information field.
3180 //
3181
3182 realIrp->IoStatus.Information = srb->DataTransferLength;
3183 break;
3184 }
3185
3186 case IOCTL_CDROM_PLAY_AUDIO_MSF:
3187
3188 PLAY_ACTIVE(deviceExtension) = TRUE;
3189
3190 break;
3191
3192 case IOCTL_CDROM_READ_Q_CHANNEL: {
3193
3194 PSUB_Q_CHANNEL_DATA userChannelData = realIrp->AssociatedIrp.SystemBuffer;
3195 #if DBG
3196 PCDROM_SUB_Q_DATA_FORMAT inputBuffer = realIrp->AssociatedIrp.SystemBuffer;
3197 #endif
3198 PSUB_Q_CHANNEL_DATA subQPtr = srb->DataBuffer;
3199
3200 #if DBG
3201 switch( inputBuffer->Format ) {
3202
3203 case IOCTL_CDROM_CURRENT_POSITION:
3204 DebugPrint((2,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr->CurrentPosition.Header.AudioStatus ));
3205 DebugPrint((2,"CdRomDeviceControlCompletion: ADR = 0x%x\n", subQPtr->CurrentPosition.ADR ));
3206 DebugPrint((2,"CdRomDeviceControlCompletion: Control = 0x%x\n", subQPtr->CurrentPosition.Control ));
3207 DebugPrint((2,"CdRomDeviceControlCompletion: Track = %u\n", subQPtr->CurrentPosition.TrackNumber ));
3208 DebugPrint((2,"CdRomDeviceControlCompletion: Index = %u\n", subQPtr->CurrentPosition.IndexNumber ));
3209 DebugPrint((2,"CdRomDeviceControlCompletion: Absolute Address = %x\n", *((PULONG)subQPtr->CurrentPosition.AbsoluteAddress) ));
3210 DebugPrint((2,"CdRomDeviceControlCompletion: Relative Address = %x\n", *((PULONG)subQPtr->CurrentPosition.TrackRelativeAddress) ));
3211 break;
3212
3213 case IOCTL_CDROM_MEDIA_CATALOG:
3214 DebugPrint((2,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr->MediaCatalog.Header.AudioStatus ));
3215 DebugPrint((2,"CdRomDeviceControlCompletion: Mcval is %u\n", subQPtr->MediaCatalog.Mcval ));
3216 break;
3217
3218 case IOCTL_CDROM_TRACK_ISRC:
3219 DebugPrint((2,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr->TrackIsrc.Header.AudioStatus ));
3220 DebugPrint((2,"CdRomDeviceControlCompletion: Tcval is %u\n", subQPtr->TrackIsrc.Tcval ));
3221 break;
3222
3223 }
3224 #endif
3225
3226 //
3227 // Update the play active status.
3228 //
3229
3230 if (subQPtr->CurrentPosition.Header.AudioStatus == AUDIO_STATUS_IN_PROGRESS) {
3231
3232 PLAY_ACTIVE(deviceExtension) = TRUE;
3233
3234 } else {
3235
3236 PLAY_ACTIVE(deviceExtension) = FALSE;
3237
3238 }
3239
3240 //
3241 // Check if output buffer is large enough to contain
3242 // the data.
3243 //
3244
3245 if (realIrpStack->Parameters.DeviceIoControl.OutputBufferLength <
3246 srb->DataTransferLength) {
3247
3248 srb->DataTransferLength =
3249 realIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
3250 }
3251
3252 //
3253 // Copy our buffer into users.
3254 //
3255
3256 RtlMoveMemory(userChannelData,
3257 subQPtr,
3258 srb->DataTransferLength);
3259
3260 realIrp->IoStatus.Information = srb->DataTransferLength;
3261 break;
3262 }
3263
3264 case IOCTL_CDROM_PAUSE_AUDIO:
3265
3266 PLAY_ACTIVE(deviceExtension) = FALSE;
3267 realIrp->IoStatus.Information = 0;
3268 break;
3269
3270 case IOCTL_CDROM_RESUME_AUDIO:
3271
3272 realIrp->IoStatus.Information = 0;
3273 break;
3274
3275 case IOCTL_CDROM_SEEK_AUDIO_MSF:
3276
3277 realIrp->IoStatus.Information = 0;
3278 break;
3279
3280 case IOCTL_CDROM_STOP_AUDIO:
3281
3282 PLAY_ACTIVE(deviceExtension) = FALSE;
3283
3284 realIrp->IoStatus.Information = 0;
3285 break;
3286
3287 case IOCTL_CDROM_GET_CONTROL: {
3288
3289 PCDROM_AUDIO_CONTROL audioControl = srb->DataBuffer;
3290 PAUDIO_OUTPUT audioOutput;
3291 ULONG bytesTransferred;
3292
3293 audioOutput = ScsiClassFindModePage((PCHAR)audioControl,
3294 srb->DataTransferLength,
3295 CDROM_AUDIO_CONTROL_PAGE,
3296 use6Byte);
3297 //
3298 // Verify the page is as big as expected.
3299 //
3300
3301 bytesTransferred = (PCHAR) audioOutput - (PCHAR) audioControl +
3302 sizeof(AUDIO_OUTPUT);
3303
3304 if (audioOutput != NULL &&
3305 srb->DataTransferLength >= bytesTransferred) {
3306
3307 audioControl->LbaFormat = audioOutput->LbaFormat;
3308
3309 audioControl->LogicalBlocksPerSecond =
3310 (audioOutput->LogicalBlocksPerSec