|
|
1.1 root 1: /*++
2:
3: Copyright (c) 1991 Microsoft Corporation
4:
5: Module Name:
6:
7: cdrom.c
8:
9: Abstract:
10:
11: The CDROM class driver tranlates IRPs to SRBs with embedded CDBs
12: and sends them to its devices through the port driver.
13:
14: Author:
15:
16: Mike Glass (mglass)
17:
18: Environment:
19:
20: kernel mode only
21:
22: Notes:
23:
24: SCSI Tape, CDRom and Disk class drivers share common routines
25: that can be found in the CLASS directory (..\ntos\dd\class).
26:
27: Revision History:
28:
29: --*/
30:
31: #include "ntddk.h"
32: #include "scsi.h"
33: #include "class.h"
34: #include "string.h"
35:
36: #define DEVICE_EXTENSION_SIZE sizeof(DEVICE_EXTENSION) + sizeof(BOOLEAN)
37: #define SCSI_CDROM_TIMEOUT 10
38: #define HITACHI_MODE_DATA_SIZE 12
39: #define MODE_DATA_SIZE 64
40:
41: #define PLAY_ACTIVE(DeviceExtension) *((PBOOLEAN) (DeviceExtension+1))
42:
43:
44: NTSTATUS
45: DriverEntry(
46: IN PDRIVER_OBJECT DriverObject,
47: IN PUNICODE_STRING RegistryPath
48: );
49:
50: BOOLEAN
51: FindScsiCdRoms(
52: IN PDRIVER_OBJECT DriveObject,
53: IN PDEVICE_OBJECT PortDeviceObject,
54: IN UCHAR PortNumber
55: );
56:
57: NTSTATUS
58: ScsiCdRomOpenClose(
59: IN PDEVICE_OBJECT DeviceObject,
60: IN PIRP Irp
61: );
62:
63: NTSTATUS
64: ScsiCdRomRead(
65: IN PDEVICE_OBJECT DeviceObject,
66: IN PIRP Irp
67: );
68:
69: NTSTATUS
70: ScsiCdRomDeviceControl(
71: IN PDEVICE_OBJECT DeviceObject,
72: IN PIRP Irp
73: );
74:
75: NTSTATUS
76: CreateCdRomDeviceObject(
77: IN PDRIVER_OBJECT DriverObject,
78: IN PDEVICE_OBJECT PortDeviceObject,
79: IN UCHAR PortNumber,
80: IN PULONG DeviceCount,
81: PIO_SCSI_CAPABILITIES PortCapabilities,
82: IN PSCSI_INQUIRY_DATA LunInfo
83: );
84:
85: NTSTATUS
86: GetTableOfContents(
87: IN PDEVICE_OBJECT DeviceObject
88: );
89:
90: VOID
91: ScanForSpecial(
92: PDEVICE_OBJECT DeviceObject,
93: PINQUIRYDATA InquiryData,
94: PIO_SCSI_CAPABILITIES PortCapabilities
95: );
96:
97: BOOLEAN
98: CdRomIsPlayActive(
99: IN PDEVICE_OBJECT DeviceObject
100: );
101:
102: VOID
103: HitachProcessError(
104: PDEVICE_OBJECT DeviceObject,
105: PSCSI_REQUEST_BLOCK Srb,
106: NTSTATUS *Status,
107: BOOLEAN *Retry
108: );
109:
110: #ifdef ALLOC_PRAGMA
111: #pragma alloc_text(init, DriverEntry)
112: #pragma alloc_text(init, FindScsiCdRoms)
113: #pragma alloc_text(init, CreateCdRomDeviceObject)
114: #pragma alloc_text(init, ScanForSpecial)
115: #endif
116:
117:
118: NTSTATUS
119: DriverEntry(
120: IN PDRIVER_OBJECT DriverObject,
121: IN PUNICODE_STRING RegistryPath
122: )
123:
124: /*++
125:
126: Routine Description:
127:
128: This routine initializes the CD-Rom class driver. The class
129: driver opens the port driver by name and then receives
130: configuration information used to attach to the CDROM devices.
131:
132: Arguments:
133:
134: DriverObject
135:
136: Return Value:
137:
138: NT Status
139:
140: --*/
141:
142: {
143: UCHAR portNumber = 0;
144: NTSTATUS status;
145: PFILE_OBJECT fileObject;
146: PDEVICE_OBJECT portDeviceObject;
147: STRING deviceNameString;
148: CCHAR deviceNameBuffer[256];
149: UNICODE_STRING unicodeDeviceName;
150: BOOLEAN foundOne = FALSE;
151:
152: DebugPrint((1,"\n\nSCSI CdRom Class Driver\n"));
153:
154: //
155: // Set up the device driver entry points.
156: //
157:
158: DriverObject->MajorFunction[IRP_MJ_CREATE] = ScsiCdRomOpenClose;
159: DriverObject->MajorFunction[IRP_MJ_CLOSE] = ScsiCdRomOpenClose;
160: DriverObject->MajorFunction[IRP_MJ_READ] = ScsiCdRomRead;
161: DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScsiCdRomDeviceControl;
162: DriverObject->MajorFunction[IRP_MJ_SCSI] = ScsiClassInternalIoControl;
163:
164:
165: //
166: // Open port driver device objects by name.
167: //
168:
169: do {
170:
171: //
172: // Create port driver name.
173: //
174:
175: sprintf(deviceNameBuffer,
176: "\\Device\\ScsiPort%d",
177: portNumber);
178:
179: DebugPrint((2,"ScsiCdRomInitialize: Open %s\n",
180: deviceNameBuffer));
181:
182: RtlInitString(&deviceNameString,
183: deviceNameBuffer);
184:
185: status = RtlAnsiStringToUnicodeString(&unicodeDeviceName,
186: &deviceNameString,
187: TRUE);
188:
189: if (!NT_SUCCESS(status)) {
190: break;
191: }
192:
193: status = IoGetDeviceObjectPointer(&unicodeDeviceName,
194: FILE_READ_ATTRIBUTES,
195: &fileObject,
196: &portDeviceObject);
197:
198: RtlFreeUnicodeString(&unicodeDeviceName);
199:
200: if (NT_SUCCESS(status)) {
201:
202: //
203: // SCSI port driver exists.
204: //
205:
206: if (FindScsiCdRoms(DriverObject,
207: portDeviceObject,
208: portNumber++)) {
209:
210: foundOne = TRUE;
211: }
212:
213: //
214: // Dereference the file object since the port device pointer is no
215: // longer needed. The claim device code references the port driver
216: // pointer that is actually being used.
217: //
218:
219: ObDereferenceObject(fileObject);
220: }
221:
222: } while (NT_SUCCESS(status));
223:
224: if (foundOne) {
225: return STATUS_SUCCESS;
226: } else {
227: return STATUS_NO_SUCH_DEVICE;
228: }
229:
230: } // end DriverEntry()
231:
232:
233: BOOLEAN
234: FindScsiCdRoms(
235: IN PDRIVER_OBJECT DriverObject,
236: IN PDEVICE_OBJECT PortDeviceObject,
237: IN UCHAR PortNumber
238: )
239:
240: /*++
241:
242: Routine Description:
243:
244: Connect to SCSI port driver. Get adapter capabilities and
245: SCSI bus configuration information. Search inquiry data
246: for CDROM devices to process.
247:
248: Arguments:
249:
250: DriverObject - CDROM class driver object.
251: PortDeviceObject - SCSI port driver device object.
252: PortNumber - The system ordinal for this scsi adapter.
253:
254: Return Value:
255:
256: TRUE if CDROM device present on this SCSI adapter.
257:
258: --*/
259:
260: {
261: PIO_SCSI_CAPABILITIES portCapabilities;
262: PULONG cdRomCount;
263: PCHAR buffer;
264: PSCSI_INQUIRY_DATA lunInfo;
265: PSCSI_ADAPTER_BUS_INFO adapterInfo;
266: PINQUIRYDATA inquiryData;
267: ULONG scsiBus;
268: NTSTATUS status;
269: BOOLEAN foundDevice = FALSE;
270:
271: //
272: // Call port driver to get adapter capabilities.
273: //
274:
275: status = ScsiClassGetCapabilities(PortDeviceObject, &portCapabilities);
276:
277: if (!NT_SUCCESS(status)) {
278: DebugPrint((1,"FindScsiDevices: ScsiClassGetCapabilities failed\n"));
279: return foundDevice;
280: }
281:
282: //
283: // Call port driver to get inquiry information to find cdroms.
284: //
285:
286: status = ScsiClassGetInquiryData(PortDeviceObject, (PSCSI_ADAPTER_BUS_INFO *) &buffer);
287:
288: if (!NT_SUCCESS(status)) {
289: DebugPrint((1,"FindScsiDevices: ScsiClassGetInquiryData failed\n"));
290: return foundDevice;
291: }
292:
293: //
294: // Get the address of the count of the number of cdroms already initialized.
295: //
296:
297: cdRomCount = &IoGetConfigurationInformation()->CdRomCount;
298: adapterInfo = (PVOID) buffer;
299:
300: //
301: // For each SCSI bus this adapter supports ...
302: //
303:
304: for (scsiBus=0; scsiBus < adapterInfo->NumberOfBuses; scsiBus++) {
305:
306: //
307: // Get the SCSI bus scan data for this bus.
308: //
309:
310: lunInfo = (PVOID) (buffer + adapterInfo->BusData[scsiBus].InquiryDataOffset);
311:
312: //
313: // Search list for unclaimed disk devices.
314: //
315:
316: while (adapterInfo->BusData[scsiBus].InquiryDataOffset) {
317:
318: inquiryData = (PVOID)lunInfo->InquiryData;
319:
320: if ((inquiryData->DeviceType == READ_ONLY_DIRECT_ACCESS_DEVICE) &&
321: (!lunInfo->DeviceClaimed)) {
322:
323: DebugPrint((1,"FindScsiDevices: Vendor string is %.24s\n",
324: inquiryData->VendorId));
325:
326: //
327: // Create device objects for cdrom
328: //
329:
330: status = CreateCdRomDeviceObject(DriverObject,
331: PortDeviceObject,
332: PortNumber,
333: cdRomCount,
334: portCapabilities,
335: lunInfo);
336:
337: if (NT_SUCCESS(status)) {
338:
339: //
340: // Increment system cdrom device count.
341: //
342:
343: (*cdRomCount)++;
344:
345: //
346: // Indicate that a cdrom device was found.
347: //
348:
349: foundDevice = TRUE;
350: }
351: }
352:
353: //
354: // Get next LunInfo.
355: //
356:
357: if (lunInfo->NextInquiryDataOffset == 0) {
358: break;
359: }
360:
361: lunInfo = (PVOID) (buffer + lunInfo->NextInquiryDataOffset);
362: }
363: }
364:
365: ExFreePool(buffer);
366:
367: return foundDevice;
368:
369: } // end FindScsiCdRoms()
370:
371:
372: NTSTATUS
373: CreateCdRomDeviceObject(
374: IN PDRIVER_OBJECT DriverObject,
375: IN PDEVICE_OBJECT PortDeviceObject,
376: IN UCHAR PortNumber,
377: IN PULONG DeviceCount,
378: IN PIO_SCSI_CAPABILITIES PortCapabilities,
379: IN PSCSI_INQUIRY_DATA LunInfo
380: )
381:
382: /*++
383:
384: Routine Description:
385:
386: This routine creates an object for the device and then calls the
387: SCSI port driver for media capacity and sector size.
388:
389: Arguments:
390:
391: DriverObject - Pointer to driver object created by system.
392: PortDeviceObject - to connect to SCSI port driver.
393: DeviceCount - Number of previously installed CDROMs.
394: PortCapabilities - Pointer to structure returned by SCSI port
395: driver describing adapter capabilites (and limitations).
396: LunInfo - Pointer to configuration information for this device.
397:
398: Return Value:
399:
400: NTSTATUS
401:
402: --*/
403: {
404: UCHAR ntNameBuffer[64];
405: UCHAR arcNameBuffer[64];
406: STRING ntNameString;
407: STRING arcNameString;
408: UNICODE_STRING ntUnicodeString;
409: UNICODE_STRING arcUnicodeString;
410: NTSTATUS status;
411: PDEVICE_OBJECT deviceObject = NULL;
412: PDEVICE_EXTENSION deviceExtension;
413: PVOID senseData = NULL;
414:
415: //
416: // Claim the device.
417: //
418:
419: status = ScsiClassClaimDevice(
420: PortDeviceObject,
421: LunInfo,
422: FALSE,
423: &PortDeviceObject
424: );
425:
426: if (!NT_SUCCESS(status)) {
427: return(status);
428: }
429:
430:
431: //
432: // Create device object for this device.
433: //
434:
435: sprintf(ntNameBuffer,
436: "\\Device\\CdRom%d",
437: *DeviceCount);
438:
439: RtlInitString(&ntNameString,
440: ntNameBuffer);
441:
442: DebugPrint((2,"CreateCdRomDeviceObjects: Create device object %s\n",
443: ntNameBuffer));
444:
445: //
446: // Convert ANSI string to Unicode.
447: //
448:
449: status = RtlAnsiStringToUnicodeString(&ntUnicodeString,
450: &ntNameString,
451: TRUE);
452:
453: if (!NT_SUCCESS(status)) {
454:
455: DebugPrint((1,
456: "CreateDiskDeviceObjects: Cannot convert string %s\n",
457: ntNameBuffer));
458:
459: //
460: // Release the device since an error occured.
461: //
462:
463: ScsiClassClaimDevice(
464: PortDeviceObject,
465: LunInfo,
466: TRUE,
467: NULL
468: );
469:
470: return(status);
471: }
472:
473: //
474: // Create device object for this CDROM.
475: //
476:
477: status = IoCreateDevice(DriverObject,
478: DEVICE_EXTENSION_SIZE,
479: &ntUnicodeString,
480: FILE_DEVICE_CD_ROM,
481: FILE_REMOVABLE_MEDIA | FILE_READ_ONLY_DEVICE,
482: FALSE,
483: &deviceObject);
484:
485:
486: if (!NT_SUCCESS(status)) {
487: DebugPrint((1,"CreateCdRomDeviceObjects: Can not create device %s\n",
488: ntNameBuffer));
489:
490: RtlFreeUnicodeString(&ntUnicodeString);
491: deviceObject = NULL;
492: goto CreateCdRomDeviceObjectExit;
493: }
494:
495: //
496: // Indicate that IRPs should include MDLs.
497: //
498:
499: deviceObject->Flags |= DO_DIRECT_IO;
500:
501: //
502: // Set up required stack size in device object.
503: //
504:
505: deviceObject->StackSize = PortDeviceObject->StackSize + 1;
506:
507: deviceExtension = deviceObject->DeviceExtension;
508:
509: //
510: // Allocate spinlock for split request completion.
511: //
512:
513: KeInitializeSpinLock(&deviceExtension->SplitRequestSpinLock);
514:
515: //
516: // This is the physical device.
517: //
518:
519: deviceExtension->PhysicalDevice = deviceObject;
520:
521: //
522: // Copy port device object to device extension.
523: //
524:
525: deviceExtension->PortDeviceObject = PortDeviceObject;
526:
527: //
528: // Set the alignment requirements for the device based on the
529: // host adapter requirements
530: //
531:
532: if (PortDeviceObject->AlignmentRequirement > deviceObject->AlignmentRequirement) {
533: deviceObject->AlignmentRequirement = PortDeviceObject->AlignmentRequirement;
534: }
535:
536: //
537: // Save address of port driver capabilities.
538: //
539:
540: deviceExtension->PortCapabilities = PortCapabilities;
541:
542: //
543: // Disable synchronous transfer for CDROM requests.
544: //
545:
546: deviceExtension->SrbFlags = SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
547:
548: //
549: // Allocate request sense buffer.
550: //
551:
552: senseData = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE);
553:
554: if (senseData == NULL) {
555:
556: //
557: // The buffer cannot be allocated.
558: //
559:
560: status = STATUS_INSUFFICIENT_RESOURCES;
561: goto CreateCdRomDeviceObjectExit;
562: }
563:
564: //
565: // Set the sense data pointer in the device extension.
566: //
567:
568: deviceExtension->SenseData = senseData;
569:
570: //
571: // CDROMs are not partitionable so starting offset is 0.
572: //
573:
574: deviceExtension->StartingOffset.LowPart = 0;
575: deviceExtension->StartingOffset.HighPart = 0;
576:
577: //
578: // Path/TargetId/LUN describes a device location on the SCSI bus.
579: // This information comes from the LunInfo buffer.
580: //
581:
582: deviceExtension->PortNumber = PortNumber;
583: deviceExtension->PathId = LunInfo->PathId;
584: deviceExtension->TargetId = LunInfo->TargetId;
585: deviceExtension->Lun = LunInfo->Lun;
586:
587: //
588: // Set timeout value in seconds.
589: //
590:
591: deviceExtension->TimeOutValue = SCSI_CDROM_TIMEOUT;
592:
593: //
594: // Back pointer to device object.
595: //
596:
597: deviceExtension->DeviceObject = deviceObject;
598:
599: //
600: // Create a symbolic link from the cdrom name to the corresponding
601: // ARC name, to be used if we're booting off the cdrom. This will
602: // fail if it's not system initialization time; that's fine. The
603: // ARC name looks something like \ArcName\scsi(0)cdrom(0)fdisk(0).
604: //
605:
606: sprintf(arcNameBuffer,
607: "\\ArcName\\scsi(%d)cdrom(%d)fdisk(%d)",
608: PortNumber,
609: LunInfo->TargetId + LunInfo->PathId * SCSI_MAXIMUM_TARGETS_PER_BUS,
610: LunInfo->Lun);
611:
612: RtlInitString(&arcNameString, arcNameBuffer);
613:
614: status = RtlAnsiStringToUnicodeString(&arcUnicodeString,
615: &arcNameString,
616: TRUE);
617:
618: if (!NT_SUCCESS(status)) {
619:
620: DebugPrint((1,
621: "CreateCdRomDeviceObjects: Cannot convert string %s\n",
622: arcNameBuffer));
623:
624: RtlFreeUnicodeString(&ntUnicodeString);
625:
626: goto CreateCdRomDeviceObjectExit;
627: }
628:
629: IoAssignArcName(&arcUnicodeString, &ntUnicodeString);
630:
631: RtlFreeUnicodeString(&ntUnicodeString);
632: RtlFreeUnicodeString(&arcUnicodeString);
633:
634: //
635: // Allocate buffer for drive geometry.
636: //
637:
638: deviceExtension->DiskGeometry =
639: ExAllocatePool(NonPagedPool, sizeof(DISK_GEOMETRY));
640:
641: if (deviceExtension->DiskGeometry == NULL) {
642:
643: status = STATUS_INSUFFICIENT_RESOURCES;
644: goto CreateCdRomDeviceObjectExit;
645: }
646:
647: //
648: // Scan for Scsi controllers that require special processing.
649: //
650:
651: ScanForSpecial(deviceObject,
652: (PINQUIRYDATA) LunInfo->InquiryData,
653: PortCapabilities);
654:
655: //
656: // Do READ CAPACITY. This SCSI command
657: // returns the last sector address on the device
658: // and the bytes per sector.
659: // These are used to calculate the drive capacity
660: // in bytes.
661: //
662:
663: status = ScsiClassReadDriveCapacity(deviceObject);
664:
665: if ((!NT_SUCCESS(status)) ||
666: (deviceExtension->DiskGeometry->BytesPerSector == 0)) {
667:
668: DebugPrint((1,
669: "CreateCdRomDeviceObjects: Can't read capacity for device %s\n",
670: ntNameBuffer));
671:
672: //
673: // Set disk geometry to default values (per ISO 9660).
674: //
675:
676: deviceExtension->DiskGeometry->BytesPerSector = 2048;
677: deviceExtension->SectorShift = 11;
678:
679: }
680:
681: return(STATUS_SUCCESS);
682:
683: CreateCdRomDeviceObjectExit:
684:
685: //
686: // Release the device since an error occured.
687: //
688:
689: ScsiClassClaimDevice(
690: PortDeviceObject,
691: LunInfo,
692: TRUE,
693: NULL
694: );
695:
696: if (senseData != NULL) {
697: ExFreePool(senseData);
698: }
699:
700: if (deviceExtension->DiskGeometry != NULL) {
701: ExFreePool(deviceExtension->DiskGeometry);
702: }
703:
704: if (deviceObject != NULL) {
705: IoDeleteDevice(deviceObject);
706: }
707:
708:
709: return status;
710:
711: } // end CreateCdromDeviceObject()
712:
713:
714: NTSTATUS
715: ScsiCdRomOpenClose(
716: IN PDEVICE_OBJECT DeviceObject,
717: IN PIRP Irp
718: )
719:
720: /*++
721:
722: Routine Description:
723:
724: This routine is called to establish a connection to the CDROM
725: class driver. It does no more than return STATUS_SUCCESS.
726:
727: Arguments:
728:
729: DeviceObject - Device object for CDROM drive
730: Irp - Open or Close request packet
731:
732: Return Value:
733:
734: NT Status - STATUS_SUCCESS
735:
736: --*/
737:
738: {
739: //
740: // Set status in Irp.
741: //
742:
743: Irp->IoStatus.Status = STATUS_SUCCESS;
744:
745: //
746: // Complete request at raised IRQ.
747: //
748:
749: IoCompleteRequest(Irp, IO_NO_INCREMENT);
750: return STATUS_SUCCESS;
751:
752: } // end ScsiCdRomOpenClose()
753:
754:
755: NTSTATUS
756: ScsiCdRomRead(
757: IN PDEVICE_OBJECT DeviceObject,
758: IN PIRP Irp
759: )
760:
761: /*++
762:
763: Routine Description:
764:
765: This is the entry called by the I/O system for read requests.
766: It builds the SRB and sends it to the port driver.
767:
768: Arguments:
769:
770: DeviceObject - the system object for the device.
771: Irp - IRP involved.
772:
773: Return Value:
774:
775: NT Status
776:
777: --*/
778:
779: {
780: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
781: PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
782: ULONG transferByteCount = currentIrpStack->Parameters.Read.Length;
783: LARGE_INTEGER startingOffset;
784: ULONG maximumTransferLength =
785: deviceExtension->PortCapabilities->MaximumTransferLength;
786: ULONG transferPages;
787:
788: //
789: // If the cd is playing music then reject this request.
790: //
791:
792: if (PLAY_ACTIVE(deviceExtension)) {
793: Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
794: IoCompleteRequest(Irp, IO_NO_INCREMENT);
795: return STATUS_DEVICE_BUSY;
796: }
797:
798: //
799: // Check if volume needs verification.
800: //
801:
802: if ((DeviceObject->Flags & DO_VERIFY_VOLUME) &&
803: !(currentIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME)) {
804:
805: //
806: // if DO_VERIFY_VOLUME bit is set
807: // in device object flags, fail request.
808: //
809:
810: DebugPrint((2,"ScsiCdRomRead: Volume verfication needed\n"));
811:
812: IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
813:
814: Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
815: Irp->IoStatus.Information = 0;
816:
817: IoCompleteRequest(Irp, IO_NO_INCREMENT);
818: return STATUS_VERIFY_REQUIRED;
819: }
820:
821: //
822: // Verify parameters of this request.
823: // Check that ending sector is on disc and
824: // that number of bytes to transfer is a multiple of
825: // the sector size.
826: //
827:
828: startingOffset = LiFromUlong(transferByteCount);
829: startingOffset = LiAdd(startingOffset,
830: currentIrpStack->Parameters.Read.ByteOffset);
831:
832: if (LiGtr( startingOffset, deviceExtension->PartitionLength) ||
833: (transferByteCount & deviceExtension->DiskGeometry->BytesPerSector - 1)) {
834:
835: DebugPrint((1,"ScsiCdRomRead: Invalid I/O parameters\n"));
836:
837: //
838: // Fail request with status of invalid parameters.
839: //
840:
841: Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
842:
843: IoCompleteRequest(Irp, IO_NO_INCREMENT);
844: return STATUS_INVALID_PARAMETER;
845: }
846:
847: //
848: // Mark IRP with status pending.
849: //
850:
851: IoMarkIrpPending(Irp);
852:
853: //
854: // Calculate number of pages in this transfer.
855: //
856:
857: transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(
858: MmGetMdlVirtualAddress(Irp->MdlAddress),
859: currentIrpStack->Parameters.Read.Length);
860:
861: //
862: // Check if request length is greater than the maximum number of
863: // bytes that the hardware can transfer.
864: //
865:
866: if (currentIrpStack->Parameters.Read.Length > maximumTransferLength ||
867: transferPages > deviceExtension->PortCapabilities->MaximumPhysicalPages) {
868:
869: DebugPrint((2,"ScsiCdromRead: Request greater than maximum\n"));
870: DebugPrint((2,"ScsiCdromRead: Maximum is %lx\n",
871: maximumTransferLength));
872: DebugPrint((2,"ScsiCdromRead: Byte count is %lx\n",
873: currentIrpStack->Parameters.Read.Length));
874:
875: transferPages =
876: deviceExtension->PortCapabilities->MaximumPhysicalPages - 1;
877:
878: if (maximumTransferLength > transferPages << PAGE_SHIFT ) {
879: maximumTransferLength = transferPages << PAGE_SHIFT;
880: }
881:
882: //
883: // Check that maximum transfer size is not zero.
884: //
885:
886: if (maximumTransferLength == 0) {
887: maximumTransferLength = PAGE_SIZE;
888: }
889:
890: //
891: // Mark IRP with status pending.
892: //
893:
894: IoMarkIrpPending(Irp);
895:
896: //
897: // Request greater than port driver maximum.
898: // Break up into smaller routines.
899: //
900:
901: ScsiClassSplitRequest(DeviceObject, Irp, maximumTransferLength);
902:
903:
904: return STATUS_PENDING;
905: }
906:
907: //
908: // Build SRB and CDB for this IRP.
909: //
910:
911: ScsiClassBuildRequest(DeviceObject, Irp);
912:
913: //
914: // Return the results of the call to the port driver.
915: //
916:
917: return IoCallDriver(deviceExtension->PortDeviceObject, Irp);
918:
919: } // end ScsiCdRomRead()
920:
921:
922: NTSTATUS
923: ScsiCdRomDeviceControl(
924: IN PDEVICE_OBJECT DeviceObject,
925: IN PIRP Irp
926: )
927:
928: /*++
929:
930: Routine Description:
931:
932: This is the NT device control handler for CDROMs.
933:
934: Arguments:
935:
936: DeviceObject - for this CDROM
937:
938: Irp - IO Request packet
939:
940: Return Value:
941:
942: NTSTATUS
943:
944: --*/
945:
946: {
947: PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
948: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
949: SCSI_REQUEST_BLOCK srb;
950: PCDB cdb = (PCDB)srb.Cdb;
951: PVOID outputBuffer;
952: ULONG bytesTransferred = 0;
953: NTSTATUS status;
954: NTSTATUS status2;
955:
956: RetryControl:
957:
958: //
959: // Zero the SRB on stack.
960: //
961:
962: RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
963:
964: Irp->IoStatus.Information = 0;
965:
966: switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
967:
968: case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
969:
970: DebugPrint((2,"ScsiCdRomDeviceControl: Get drive geometry\n"));
971:
972: if ( irpStack->Parameters.DeviceIoControl.OutputBufferLength <
973: sizeof( DISK_GEOMETRY ) ) {
974:
975: status = STATUS_INFO_LENGTH_MISMATCH;
976: break;
977: }
978:
979: //
980: // Issue ReadCapacity to update device extension
981: // with information for current media.
982: //
983:
984: status = ScsiClassReadDriveCapacity(DeviceObject);
985:
986: if ((!NT_SUCCESS(status)) ||
987: (deviceExtension->DiskGeometry->BytesPerSector == 0)) {
988:
989: //
990: // Set disk geometry to default values (per ISO 9660).
991: //
992:
993: deviceExtension->DiskGeometry->BytesPerSector = 2048;
994: deviceExtension->SectorShift = 11;
995: }
996:
997: //
998: // Copy drive geometry information from device extension.
999: //
1000:
1001: RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
1002: deviceExtension->DiskGeometry,
1003: sizeof(DISK_GEOMETRY));
1004:
1005: status = STATUS_SUCCESS;
1006: Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
1007:
1008: break;
1009:
1010: case IOCTL_CDROM_GET_LAST_SESSION:
1011:
1012: //
1013: // Set format to return first and last session numbers.
1014: //
1015:
1016: cdb->READ_TOC.Format = GET_LAST_SESSION;
1017:
1018: //
1019: // Fall through to READ TOC code.
1020: //
1021:
1022: case IOCTL_CDROM_READ_TOC:
1023:
1024: {
1025: PCDROM_TOC toc = Irp->AssociatedIrp.SystemBuffer;
1026: ULONG transferBytes;
1027:
1028: DebugPrint((2,"CdRomDeviceControl: Read TOC\n"));
1029:
1030: //
1031: // If the cd is playing music then reject this request.
1032: //
1033:
1034: if (CdRomIsPlayActive(DeviceObject)) {
1035: Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
1036: IoCompleteRequest(Irp, IO_NO_INCREMENT);
1037: return STATUS_DEVICE_BUSY;
1038: }
1039:
1040: //
1041: // Read TOC is 10 byte CDB.
1042: //
1043:
1044: srb.CdbLength = 10;
1045:
1046: cdb->READ_TOC.OperationCode = SCSIOP_READ_TOC;
1047:
1048: if (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_READ_TOC) {
1049:
1050: //
1051: // Use MSF addressing if not request for session information.
1052: //
1053:
1054: cdb->READ_TOC.Msf = CDB_USE_MSF;
1055: }
1056:
1057: //
1058: // Start at beginning of disc.
1059: //
1060:
1061: cdb->READ_TOC.StartingTrack = 0;
1062:
1063: //
1064: // Set size of TOC structure.
1065: //
1066:
1067: transferBytes =
1068: irpStack->Parameters.Read.Length >
1069: sizeof(CDROM_TOC) ? sizeof(CDROM_TOC):
1070: irpStack->Parameters.Read.Length;
1071:
1072: cdb->READ_TOC.AllocationLength[0] = (UCHAR) (transferBytes >> 8);
1073: cdb->READ_TOC.AllocationLength[1] = (UCHAR) (transferBytes & 0xFF);
1074:
1075: cdb->READ_TOC.Control = 0;
1076:
1077: //
1078: // Set timeout value.
1079: //
1080:
1081: srb.TimeOutValue = deviceExtension->TimeOutValue;
1082:
1083: status = ScsiClassSendSrbSynchronous(DeviceObject,
1084: &srb,
1085: toc,
1086: transferBytes,
1087: FALSE);
1088:
1089: //
1090: // Check for data underrun.
1091: //
1092:
1093: if (status==STATUS_DATA_OVERRUN) {
1094: status = STATUS_SUCCESS;
1095: }
1096:
1097: Irp->IoStatus.Information = srb.DataTransferLength;
1098: }
1099:
1100: break;
1101:
1102: case IOCTL_CDROM_PLAY_AUDIO_MSF:
1103:
1104: {
1105: PCDROM_PLAY_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
1106:
1107: //
1108: // Play Audio MSF
1109: //
1110:
1111: DebugPrint((2,"ScsiCdRomDeviceControl: Play audio MSF\n"));
1112:
1113: if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
1114: sizeof(CDROM_PLAY_AUDIO_MSF)) {
1115:
1116: //
1117: // Indicate unsuccessful status.
1118: //
1119:
1120: status = STATUS_BUFFER_TOO_SMALL;
1121: break;
1122: }
1123:
1124: cdb->PLAY_AUDIO_MSF.OperationCode = SCSIOP_PLAY_AUDIO_MSF;
1125:
1126: cdb->PLAY_AUDIO_MSF.StartingM = inputBuffer->StartingM;
1127: cdb->PLAY_AUDIO_MSF.StartingS = inputBuffer->StartingS;
1128: cdb->PLAY_AUDIO_MSF.StartingF = inputBuffer->StartingF;
1129:
1130: cdb->PLAY_AUDIO_MSF.EndingM = inputBuffer->EndingM;
1131: cdb->PLAY_AUDIO_MSF.EndingS = inputBuffer->EndingS;
1132: cdb->PLAY_AUDIO_MSF.EndingF = inputBuffer->EndingF;
1133:
1134: srb.CdbLength = 10;
1135:
1136: //
1137: // Set timeout value.
1138: //
1139:
1140: srb.TimeOutValue = deviceExtension->TimeOutValue;
1141:
1142: status = ScsiClassSendSrbSynchronous(DeviceObject,
1143: &srb,
1144: NULL,
1145: 0,
1146: FALSE);
1147:
1148: if (NT_SUCCESS(status)) {
1149: PLAY_ACTIVE(deviceExtension) = TRUE;
1150: }
1151: }
1152:
1153: break;
1154:
1155: case IOCTL_CDROM_SEEK_AUDIO_MSF:
1156:
1157: {
1158: PCDROM_SEEK_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
1159:
1160: //
1161: // Seek Audio MSF
1162: //
1163:
1164: DebugPrint((2,"ScsiCdRomDeviceControl: Seek audio MSF\n"));
1165:
1166: if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
1167: sizeof(CDROM_SEEK_AUDIO_MSF)) {
1168:
1169: //
1170: // Indicate unsuccessful status.
1171: //
1172:
1173: status = STATUS_BUFFER_TOO_SMALL;
1174: break;
1175: }
1176:
1177: cdb->PLAY_AUDIO_MSF.OperationCode = SCSIOP_PLAY_AUDIO_MSF;
1178:
1179: cdb->PLAY_AUDIO_MSF.StartingM = inputBuffer->M;
1180: cdb->PLAY_AUDIO_MSF.StartingS = inputBuffer->S;
1181: cdb->PLAY_AUDIO_MSF.StartingF = inputBuffer->F;
1182:
1183: cdb->PLAY_AUDIO_MSF.EndingM = inputBuffer->M;
1184: cdb->PLAY_AUDIO_MSF.EndingS = inputBuffer->S;
1185: cdb->PLAY_AUDIO_MSF.EndingF = inputBuffer->F;
1186:
1187: srb.CdbLength = 10;
1188:
1189: //
1190: // Set timeout value.
1191: //
1192:
1193: srb.TimeOutValue = deviceExtension->TimeOutValue;
1194:
1195: status = ScsiClassSendSrbSynchronous(DeviceObject,
1196: &srb,
1197: NULL,
1198: 0,
1199: FALSE);
1200:
1201: }
1202:
1203: break;
1204:
1205: case IOCTL_CDROM_PAUSE_AUDIO:
1206:
1207: //
1208: // Pause audio
1209: //
1210:
1211: DebugPrint((2, "ScsiCdRomDeviceControl: Pause audio\n"));
1212:
1213: PLAY_ACTIVE(deviceExtension) = FALSE;
1214:
1215: cdb->PAUSE_RESUME.OperationCode = SCSIOP_PAUSE_RESUME;
1216:
1217: cdb->PAUSE_RESUME.Action = CDB_AUDIO_PAUSE;
1218:
1219: srb.CdbLength = 10;
1220:
1221: //
1222: // Set timeout value.
1223: //
1224:
1225: srb.TimeOutValue = deviceExtension->TimeOutValue;
1226:
1227: status = ScsiClassSendSrbSynchronous(DeviceObject,
1228: &srb,
1229: NULL,
1230: 0,
1231: FALSE);
1232:
1233: break;
1234:
1235: case IOCTL_CDROM_RESUME_AUDIO:
1236:
1237: //
1238: // Resume audio
1239: //
1240:
1241: DebugPrint((2, "ScsiCdRomDeviceControl: Resume audio\n"));
1242:
1243: cdb->PAUSE_RESUME.OperationCode = SCSIOP_PAUSE_RESUME;
1244:
1245: cdb->PAUSE_RESUME.Action = CDB_AUDIO_RESUME;
1246:
1247: srb.CdbLength = 10;
1248:
1249: //
1250: // Set timeout value.
1251: //
1252:
1253: srb.TimeOutValue = deviceExtension->TimeOutValue;
1254:
1255: status = ScsiClassSendSrbSynchronous(DeviceObject,
1256: &srb,
1257: NULL,
1258: 0,
1259: FALSE);
1260:
1261: break;
1262:
1263: case IOCTL_CDROM_READ_Q_CHANNEL:
1264:
1265: {
1266:
1267: PSUB_Q_CHANNEL_DATA userChannelData =
1268: Irp->AssociatedIrp.SystemBuffer;
1269: PCDROM_SUB_Q_DATA_FORMAT inputBuffer =
1270: Irp->AssociatedIrp.SystemBuffer;
1271: PSUB_Q_CHANNEL_DATA subQPtr;
1272:
1273: //
1274: // Allocate buffer for subq channel information.
1275: //
1276:
1277: subQPtr = ExAllocatePool(NonPagedPoolCacheAligned,
1278: sizeof(SUB_Q_CHANNEL_DATA));
1279:
1280: if (!subQPtr) {
1281: status = STATUS_INSUFFICIENT_RESOURCES;
1282: Irp->IoStatus.Information = 0;
1283: break;
1284: }
1285:
1286: //
1287: // Read Subchannel Q
1288: //
1289:
1290: DebugPrint((2,
1291: "ScsiCdRomDeviceControl: Read channel Q Format %u\n", inputBuffer->Format ));
1292:
1293: cdb->SUBCHANNEL.OperationCode = SCSIOP_READ_SUB_CHANNEL;
1294:
1295: //
1296: // Always logical unit 0, but only use MSF addressing
1297: // for IOCTL_CDROM_CURRENT_POSITION
1298: //
1299:
1300: if (inputBuffer->Format==IOCTL_CDROM_CURRENT_POSITION)
1301: cdb->SUBCHANNEL.Msf = CDB_USE_MSF;
1302:
1303: //
1304: // Return subchannel data
1305: //
1306:
1307: cdb->SUBCHANNEL.SubQ = CDB_SUBCHANNEL_BLOCK;
1308:
1309: //
1310: // Specify format of informatin to return
1311: //
1312:
1313: cdb->SUBCHANNEL.Format = inputBuffer->Format;
1314:
1315: //
1316: // Specify which track to access (only used by Track ISRC reads)
1317: //
1318:
1319: if (inputBuffer->Format==IOCTL_CDROM_TRACK_ISRC)
1320: cdb->SUBCHANNEL.TrackNumber = inputBuffer->Track;
1321:
1322: //
1323: // Set size of channel data -- however, this is dependent on
1324: // what information we are requesting (which Format)
1325: //
1326:
1327: switch( inputBuffer->Format ) {
1328:
1329: case IOCTL_CDROM_CURRENT_POSITION:
1330: bytesTransferred = sizeof(SUB_Q_CURRENT_POSITION);
1331: break;
1332:
1333: case IOCTL_CDROM_MEDIA_CATALOG:
1334: bytesTransferred = sizeof(SUB_Q_MEDIA_CATALOG_NUMBER);
1335: break;
1336:
1337: case IOCTL_CDROM_TRACK_ISRC:
1338: bytesTransferred = sizeof(SUB_Q_TRACK_ISRC);
1339: break;
1340: }
1341:
1342: cdb->SUBCHANNEL.AllocationLength[0] = (UCHAR) (bytesTransferred >> 8);
1343: cdb->SUBCHANNEL.AllocationLength[1] = (UCHAR) (bytesTransferred & 0xFF);
1344:
1345: srb.CdbLength = 10;
1346:
1347: //
1348: // Set timeout value.
1349: //
1350:
1351: srb.TimeOutValue = deviceExtension->TimeOutValue;
1352:
1353: status = ScsiClassSendSrbSynchronous(DeviceObject,
1354: &srb,
1355: subQPtr,
1356: bytesTransferred,
1357: FALSE);
1358:
1359: if (NT_SUCCESS(status)) {
1360: #if DBG
1361: switch( inputBuffer->Format ) {
1362:
1363: case IOCTL_CDROM_CURRENT_POSITION:
1364: DebugPrint((3,"ScsiCdromDeviceControl: Audio Status is %u\n", subQPtr->CurrentPosition.Header.AudioStatus ));
1365: DebugPrint((3,"ScsiCdromDeviceControl: ADR = 0x%x\n", subQPtr->CurrentPosition.ADR ));
1366: DebugPrint((3,"ScsiCdromDeviceControl: Control = 0x%x\n", subQPtr->CurrentPosition.Control ));
1367: DebugPrint((3,"ScsiCdromDeviceControl: Track = %u\n", subQPtr->CurrentPosition.TrackNumber ));
1368: DebugPrint((3,"ScsiCdromDeviceControl: Index = %u\n", subQPtr->CurrentPosition.IndexNumber ));
1369: break;
1370:
1371: case IOCTL_CDROM_MEDIA_CATALOG:
1372: DebugPrint((3,"ScsiCdromDeviceControl: Audio Status is %u\n", subQPtr->MediaCatalog.Header.AudioStatus ));
1373: DebugPrint((3,"ScsiCdromDeviceControl: Mcval is %u\n", subQPtr->MediaCatalog.Mcval ));
1374: break;
1375:
1376: case IOCTL_CDROM_TRACK_ISRC:
1377: DebugPrint((3,"ScsiCdromDeviceControl: Audio Status is %u\n", subQPtr->TrackIsrc.Header.AudioStatus ));
1378: DebugPrint((3,"ScsiCdromDeviceControl: Tcval is %u\n", subQPtr->TrackIsrc.Tcval ));
1379: break;
1380:
1381: }
1382: #endif
1383:
1384: //
1385: // Update the play active status.
1386: //
1387:
1388: if (subQPtr->CurrentPosition.Header.AudioStatus == AUDIO_STATUS_IN_PROGRESS) {
1389:
1390: PLAY_ACTIVE(deviceExtension) = TRUE;
1391:
1392: } else {
1393:
1394: PLAY_ACTIVE(deviceExtension) = FALSE;
1395:
1396: }
1397:
1398: //
1399: // Check if output buffer is large enough to contain
1400: // the data.
1401: //
1402:
1403: if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1404: bytesTransferred) {
1405:
1406: bytesTransferred =
1407: irpStack->Parameters.DeviceIoControl.OutputBufferLength;
1408: }
1409:
1410: RtlMoveMemory(userChannelData,
1411: subQPtr,
1412: bytesTransferred);
1413:
1414: Irp->IoStatus.Information = bytesTransferred;
1415: } else {
1416:
1417: PLAY_ACTIVE(deviceExtension) = FALSE;
1418:
1419: }
1420:
1421: ExFreePool(subQPtr);
1422:
1423: break;
1424:
1425: }
1426:
1427: case IOCTL_CDROM_GET_CONTROL:
1428:
1429: DebugPrint((2, "ScsiCdRomDeviceControl: Get audio control\n"));
1430:
1431: //
1432: // Verify user buffer is large enough for the data.
1433: //
1434:
1435: if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1436: sizeof(CDROM_AUDIO_CONTROL)) {
1437:
1438: //
1439: // Indicate unsuccessful status and no data transferred.
1440: //
1441:
1442: status = STATUS_BUFFER_TOO_SMALL;
1443: Irp->IoStatus.Information = 0;
1444:
1445: } else {
1446:
1447: PAUDIO_OUTPUT audioOutput;
1448: PCDROM_AUDIO_CONTROL audioControl = Irp->AssociatedIrp.SystemBuffer;
1449:
1450: //
1451: // Allocate buffer for volume control information.
1452: //
1453:
1454: outputBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
1455: MODE_DATA_SIZE);
1456:
1457: if (!outputBuffer) {
1458: status = STATUS_INSUFFICIENT_RESOURCES;
1459: Irp->IoStatus.Information = 0;
1460: break;
1461: }
1462:
1463: //
1464: // Get audio control information
1465: //
1466:
1467: cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
1468: cdb->MODE_SENSE.PageCode = CDROM_AUDIO_CONTROL_PAGE;
1469: cdb->MODE_SENSE.AllocationLength = MODE_DATA_SIZE;
1470:
1471: //
1472: // Disable block descriptors.
1473: //
1474:
1475: cdb->MODE_SENSE.Dbd = TRUE;
1476:
1477: srb.CdbLength = 6;
1478:
1479: //
1480: // Set timeout value.
1481: //
1482:
1483: srb.TimeOutValue = deviceExtension->TimeOutValue;
1484:
1485: status = ScsiClassSendSrbSynchronous(DeviceObject,
1486: &srb,
1487: outputBuffer,
1488: MODE_DATA_SIZE,
1489: FALSE);
1490:
1491: if (SRB_STATUS(srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
1492: status = STATUS_SUCCESS;
1493: }
1494:
1495: if (NT_SUCCESS(status)) {
1496:
1497: audioOutput = ScsiClassFindModePage( outputBuffer,
1498: srb.DataTransferLength,
1499: CDROM_AUDIO_CONTROL_PAGE);
1500: //
1501: // Verify the page is as big as expected.
1502: //
1503:
1504: bytesTransferred = (PCHAR) audioOutput - (PCHAR) outputBuffer +
1505: sizeof(AUDIO_OUTPUT);
1506:
1507: if (audioOutput != NULL &&
1508: srb.DataTransferLength >= bytesTransferred) {
1509:
1510: audioControl->LbaFormat = audioOutput->LbaFormat;
1511:
1512: audioControl->LogicalBlocksPerSecond =
1513: (audioOutput->LogicalBlocksPerSecond[0] << (UCHAR)8) |
1514: audioOutput->LogicalBlocksPerSecond[1];
1515:
1516: Irp->IoStatus.Information = sizeof(CDROM_AUDIO_CONTROL);
1517:
1518: } else {
1519: status = STATUS_INVALID_DEVICE_REQUEST;
1520: }
1521:
1522: }
1523:
1524: ExFreePool(outputBuffer);
1525: }
1526:
1527: break;
1528:
1529: case IOCTL_CDROM_GET_VOLUME:
1530:
1531: DebugPrint((2, "ScsiCdRomDeviceControl: Get volume control\n"));
1532:
1533: //
1534: // Verify user buffer is large enough for data.
1535: //
1536:
1537: if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1538: sizeof(VOLUME_CONTROL)) {
1539:
1540: //
1541: // Indicate unsuccessful status and no data transferred.
1542: //
1543:
1544: status = STATUS_BUFFER_TOO_SMALL;
1545: Irp->IoStatus.Information = 0;
1546:
1547: } else {
1548:
1549: PAUDIO_OUTPUT audioOutput;
1550: PVOLUME_CONTROL volumeControl = Irp->AssociatedIrp.SystemBuffer;
1551: ULONG i;
1552:
1553: //
1554: // Allocate buffer for volume control information.
1555: //
1556:
1557: outputBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
1558: MODE_DATA_SIZE);
1559:
1560: if (!outputBuffer) {
1561: status = STATUS_INSUFFICIENT_RESOURCES;
1562: Irp->IoStatus.Information = 0;
1563: break;
1564: }
1565:
1566: //
1567: // In case not as much as expected is returned zero
1568: // all of this.
1569: //
1570:
1571: RtlZeroMemory(outputBuffer, MODE_DATA_SIZE);
1572:
1573: //
1574: // Get volume control information
1575: //
1576:
1577: cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
1578: cdb->MODE_SENSE.PageCode = CDROM_AUDIO_CONTROL_PAGE;
1579: cdb->MODE_SENSE.AllocationLength = MODE_DATA_SIZE;
1580:
1581: srb.CdbLength = 6;
1582:
1583: //
1584: // Set timeout value.
1585: //
1586:
1587: srb.TimeOutValue = deviceExtension->TimeOutValue;
1588:
1589: status = ScsiClassSendSrbSynchronous(DeviceObject,
1590: &srb,
1591: outputBuffer,
1592: MODE_DATA_SIZE,
1593: FALSE);
1594:
1595: if (SRB_STATUS(srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
1596: status = STATUS_SUCCESS;
1597: }
1598:
1599: if (NT_SUCCESS(status)) {
1600:
1601: audioOutput = ScsiClassFindModePage( outputBuffer,
1602: srb.DataTransferLength,
1603: CDROM_AUDIO_CONTROL_PAGE);
1604:
1605: //
1606: // Verify the page is as big as expected.
1607: //
1608:
1609: bytesTransferred = (PCHAR) audioOutput - (PCHAR) outputBuffer +
1610: sizeof(AUDIO_OUTPUT);
1611:
1612: if (audioOutput != NULL &&
1613: srb.DataTransferLength >= bytesTransferred) {
1614:
1615: for (i=0; i<4; i++) {
1616: volumeControl->PortVolume[i] =
1617: audioOutput->PortOutput[i].Volume;
1618: }
1619:
1620: //
1621: // Set bytes transferred in IRP.
1622: //
1623:
1624: Irp->IoStatus.Information = sizeof(VOLUME_CONTROL);
1625:
1626: } else {
1627: status = STATUS_INVALID_DEVICE_REQUEST;
1628: }
1629:
1630: }
1631:
1632: //
1633: // Free buffer.
1634: //
1635:
1636: ExFreePool(outputBuffer);
1637: }
1638:
1639: break;
1640:
1641: case IOCTL_CDROM_SET_VOLUME:
1642:
1643: DebugPrint((2, "ScsiCdRomDeviceControl: Set volume control\n"));
1644:
1645: {
1646:
1647: PAUDIO_OUTPUT audioOutput;
1648: PAUDIO_OUTPUT audioInput;
1649: PVOID inputBuffer;
1650: PVOLUME_CONTROL volumeControl = Irp->AssociatedIrp.SystemBuffer;
1651: ULONG i;
1652:
1653: if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
1654: sizeof(VOLUME_CONTROL)) {
1655:
1656: //
1657: // Indicate unsuccessful status.
1658: //
1659:
1660: status = STATUS_BUFFER_TOO_SMALL;
1661: break;
1662: }
1663:
1664: //
1665: // Get the current audio contorl information so that the
1666: // port control information can be filled in.
1667: // Allocate buffer for volume control information.
1668: //
1669:
1670: inputBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
1671: MODE_DATA_SIZE);
1672:
1673: if (!inputBuffer) {
1674: status = STATUS_INSUFFICIENT_RESOURCES;
1675: Irp->IoStatus.Information = 0;
1676: break;
1677: }
1678:
1679: //
1680: // In case not as much as expected is returned zero
1681: // all of this.
1682: //
1683:
1684: RtlZeroMemory(inputBuffer, MODE_DATA_SIZE);
1685:
1686: //
1687: // Get volume control information
1688: //
1689:
1690: cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
1691: cdb->MODE_SENSE.PageCode = CDROM_AUDIO_CONTROL_PAGE;
1692: cdb->MODE_SENSE.AllocationLength = MODE_DATA_SIZE;
1693:
1694: srb.CdbLength = 6;
1695:
1696: //
1697: // Set timeout value.
1698: //
1699:
1700: srb.TimeOutValue = deviceExtension->TimeOutValue;
1701:
1702: status = ScsiClassSendSrbSynchronous(DeviceObject,
1703: &srb,
1704: inputBuffer,
1705: MODE_DATA_SIZE,
1706: FALSE);
1707:
1708: if (SRB_STATUS(srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
1709: status = STATUS_SUCCESS;
1710: }
1711:
1712: if (NT_SUCCESS(status)) {
1713:
1714: audioInput = ScsiClassFindModePage( inputBuffer,
1715: srb.DataTransferLength,
1716: CDROM_AUDIO_CONTROL_PAGE);
1717:
1718: if (audioInput == NULL) {
1719: status = STATUS_INVALID_DEVICE_REQUEST;
1720: }
1721:
1722: //
1723: // Verify the page is as big as expected.
1724: //
1725:
1726: i = (PCHAR) audioInput - (PCHAR) inputBuffer + sizeof(AUDIO_OUTPUT);
1727:
1728: if (srb.DataTransferLength < i) {
1729: status = STATUS_INVALID_DEVICE_REQUEST;
1730: }
1731:
1732: }
1733:
1734: if (!NT_SUCCESS(status)) {
1735:
1736: //
1737: // Free buffer.
1738: //
1739:
1740: ExFreePool(inputBuffer);
1741:
1742: break;
1743: }
1744:
1745: //
1746: // Mode select buffer is the size of the audio page plus a
1747: // mode parameter header.
1748: //
1749:
1750: bytesTransferred = sizeof(AUDIO_OUTPUT) + sizeof(MODE_PARAMETER_HEADER);
1751:
1752: //
1753: // Allocate buffer for volume control information.
1754: //
1755:
1756: outputBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
1757: bytesTransferred);
1758:
1759: if (!outputBuffer) {
1760: status = STATUS_INSUFFICIENT_RESOURCES;
1761: Irp->IoStatus.Information = 0;
1762: break;
1763: }
1764:
1765: //
1766: // Zero the buffer. The mode parameter header will be left as zeros.
1767: // Also clear the srb again.
1768: //
1769:
1770: RtlZeroMemory(outputBuffer, bytesTransferred);
1771: RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
1772:
1773: //
1774: // Set volume control information
1775: //
1776:
1777: cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
1778: cdb->MODE_SELECT.ParameterListLength = (UCHAR) bytesTransferred;
1779: cdb->MODE_SELECT.PFBit = 1;
1780:
1781: srb.CdbLength = 6;
1782:
1783: audioOutput = (PAUDIO_OUTPUT) ((PCHAR) outputBuffer
1784: + sizeof(MODE_PARAMETER_HEADER));
1785:
1786: //
1787: // Fill in the volume setting and the port control.
1788: //
1789:
1790: for (i=0; i<4; i++) {
1791: audioOutput->PortOutput[i].Volume =
1792: volumeControl->PortVolume[i];
1793: audioOutput->PortOutput[i].ChannelSelection =
1794: audioInput->PortOutput[i].ChannelSelection;
1795: }
1796:
1797: audioOutput->CodePage = CDROM_AUDIO_CONTROL_PAGE;
1798: audioOutput->ParameterLength = sizeof(AUDIO_OUTPUT) - 2;
1799: audioOutput->Immediate = MODE_SELECT_IMMEDIATE;
1800:
1801: //
1802: // Set timeout value.
1803: //
1804:
1805: srb.TimeOutValue = deviceExtension->TimeOutValue;
1806:
1807: status = ScsiClassSendSrbSynchronous(DeviceObject,
1808: &srb,
1809: outputBuffer,
1810: bytesTransferred,
1811: TRUE);
1812:
1813: //
1814: // Set bytes transferred in IRP.
1815: //
1816:
1817: Irp->IoStatus.Information = sizeof(VOLUME_CONTROL);
1818:
1819: //
1820: // Free buffers.
1821: //
1822:
1823: ExFreePool(inputBuffer);
1824: ExFreePool(outputBuffer);
1825:
1826: break;
1827: }
1828:
1829: case IOCTL_CDROM_STOP_AUDIO:
1830:
1831: //
1832: // Stop play.
1833: //
1834:
1835: DebugPrint((2, "ScsiCdRomDeviceControl: Stop audio\n"));
1836:
1837: PLAY_ACTIVE(deviceExtension) = FALSE;
1838:
1839: cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
1840:
1841: cdb->START_STOP.Immediate = 1;
1842: cdb->START_STOP.Start = 0;
1843: cdb->START_STOP.LoadEject = 0;
1844:
1845: srb.CdbLength = 6;
1846:
1847: //
1848: // Set timeout value.
1849: //
1850:
1851: srb.TimeOutValue = deviceExtension->TimeOutValue;
1852:
1853: status = ScsiClassSendSrbSynchronous(DeviceObject,
1854: &srb,
1855: NULL,
1856: 0,
1857: FALSE);
1858: break;
1859:
1860: case IOCTL_CDROM_CHECK_VERIFY:
1861:
1862: srb.CdbLength = 6;
1863:
1864: cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
1865:
1866: //
1867: // Set timeout value.
1868: //
1869:
1870: srb.TimeOutValue = deviceExtension->TimeOutValue * 2;
1871:
1872: status = ScsiClassSendSrbSynchronous(DeviceObject,
1873: &srb,
1874: NULL,
1875: 0,
1876: FALSE);
1877:
1878: //
1879: // If the status is verify required, redo the test unit ready to
1880: // verify that the cd-rom is done spinning up.
1881: // ScsiClassSendSrbSynchronous will wait for a while for the device to
1882: // spin up.
1883: //
1884:
1885: if (status == STATUS_VERIFY_REQUIRED) {
1886:
1887: srb.CdbLength = 6;
1888:
1889: cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
1890:
1891: //
1892: // Set timeout value.
1893: //
1894:
1895: srb.TimeOutValue = deviceExtension->TimeOutValue * 2;
1896:
1897: status2 = ScsiClassSendSrbSynchronous(DeviceObject,
1898: &srb,
1899: NULL,
1900: 0,
1901: FALSE);
1902:
1903: DebugPrint((1, "ScsiCdromDeviceControl: Status from second test unit ready is: %lx\n", status2));
1904: }
1905:
1906: //
1907: // Update the play active flag.
1908: //
1909:
1910: if (!CdRomIsPlayActive(DeviceObject) &&
1911: LiEqlZero(deviceExtension->PartitionLength)) {
1912:
1913: //
1914: // If play is not active and the volume needs verification then
1915: // get read capicity again.
1916: //
1917:
1918: status2 = ScsiClassReadDriveCapacity(DeviceObject);
1919:
1920: if ((!NT_SUCCESS(status2)) ||
1921: (deviceExtension->DiskGeometry->BytesPerSector == 0)) {
1922:
1923: //
1924: // Set disk geometry to default values (per ISO 9660).
1925: //
1926:
1927: deviceExtension->DiskGeometry->BytesPerSector = 2048;
1928: deviceExtension->SectorShift = 11;
1929: }
1930: }
1931:
1932: break;
1933:
1934: default:
1935:
1936: //
1937: // Pass the request to the common device control routine.
1938: //
1939:
1940: return(ScsiClassDeviceControl(DeviceObject, Irp));
1941:
1942: break;
1943:
1944: } // end switch()
1945:
1946: if (status == STATUS_VERIFY_REQUIRED) {
1947:
1948: //
1949: // If the status is verified required and the this request
1950: // should bypass verify required then retry the request.
1951: //
1952:
1953: if (irpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME) {
1954:
1955: status = STATUS_IO_DEVICE_ERROR;
1956: goto RetryControl;
1957:
1958: }
1959:
1960: }
1961:
1962: if (IoIsErrorUserInduced(status)) {
1963:
1964: IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
1965:
1966: }
1967:
1968: //
1969: // Update IRP with completion status.
1970: //
1971:
1972: Irp->IoStatus.Status = status;
1973:
1974: //
1975: // Complete the request.
1976: //
1977:
1978: IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1979: DebugPrint((2, "ScsiCdromDeviceControl: Status is %lx\n", status));
1980: return status;
1981:
1982: } // end ScsiCdromDeviceControl()
1983:
1984:
1985: VOID
1986: ScanForSpecial(
1987: PDEVICE_OBJECT DeviceObject,
1988: PINQUIRYDATA InquiryData,
1989: PIO_SCSI_CAPABILITIES PortCapabilities
1990: )
1991:
1992: /*++
1993:
1994: Routine Description:
1995:
1996: This function checks to see if an SCSI logical unit requires an special
1997: initialization or error processing.
1998:
1999: Arguments:
2000:
2001: DeviceObject - Supplies the device object to be tested.
2002:
2003: InquiryData - Supplies the inquiry data returned by the device of interest.
2004:
2005: PortCapabilities - Supplies the capabilities of the device object.
2006:
2007: Return Value:
2008:
2009: None.
2010:
2011: --*/
2012:
2013: {
2014: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
2015:
2016: //
2017: // Look for a Hitachi CDR-1750. Read-ahead must be disabled in order
2018: // to get this cdrom drive to work on scsi adapters that use PIO.
2019: //
2020:
2021: if ((strncmp(InquiryData->VendorId, "HITACHI CDR-1750S", strlen("HITACHI CDR-1750S")) == 0 ||
2022: strncmp(InquiryData->VendorId, "HITACHI CDR-3650/1650S", strlen("HITACHI CDR-3650/1650S")) == 0)
2023: && PortCapabilities->AdapterUsesPio) {
2024:
2025: DebugPrint((1, "ScsiCdrom ScanForSpecial: Found Hitachi CDR-1750S.\n"));
2026:
2027: //
2028: // Setup an error handler to reinitialize the cd rom after it is reset.
2029: //
2030:
2031: deviceExtension->ClassError = HitachProcessError;
2032: }
2033:
2034: return;
2035: }
2036:
2037: VOID
2038: HitachProcessError(
2039: PDEVICE_OBJECT DeviceObject,
2040: PSCSI_REQUEST_BLOCK Srb,
2041: NTSTATUS *Status,
2042: BOOLEAN *Retry
2043: )
2044: /*++
2045:
2046: Routine Description:
2047:
2048: This routine checks the type of error. If the error indicates CD-ROM the
2049: CD-ROM needs to be reinitialized then a Mode sense command is sent to the
2050: device. This command disables read-ahead for the device.
2051:
2052: Arguments:
2053:
2054: DeviceObject - Supplies a pointer to the device object.
2055:
2056: Srb - Supplies a pointer to the failing Srb.
2057:
2058: Status - Not used.
2059:
2060: Retry - Not used.
2061:
2062: Return Value:
2063:
2064: None.
2065:
2066: --*/
2067:
2068: {
2069: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
2070: PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer;
2071: LARGE_INTEGER largeInt = LiFromUlong(1);
2072: PUCHAR modePage;
2073: PIO_STACK_LOCATION irpStack;
2074: PIRP irp;
2075: PSCSI_REQUEST_BLOCK srb;
2076: PCOMPLETION_CONTEXT context;
2077: PCDB cdb;
2078: ULONG alignment;
2079:
2080: UNREFERENCED_PARAMETER(Status);
2081: UNREFERENCED_PARAMETER(Retry);
2082:
2083: //
2084: // Check the status. The initialization command only needs to be sent
2085: // if UNIT ATTENTION is returned.
2086: //
2087:
2088: if (!(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID)) {
2089:
2090: //
2091: // The drive does not require reinitialization.
2092: //
2093:
2094: return;
2095: }
2096:
2097: //
2098: // Found a bad HITACHI cd-rom. These devices do not work with PIO
2099: // adapters when read-ahead is enabled. Read-ahead is disabled by
2100: // a mode select command. The mode select page code is zero and the
2101: // length is 6 bytes. All of the other bytes should be zero.
2102: //
2103:
2104:
2105: if ((senseBuffer->SenseKey & 0xf) == SCSI_SENSE_UNIT_ATTENTION) {
2106:
2107: DebugPrint((1, "HitachiProcessError: Reinitializing the CD-ROM.\n"));
2108:
2109: //
2110: // Send the special mode select command to disable read-ahead
2111: // on the CD-ROM reader.
2112: //
2113:
2114: alignment = DeviceObject->AlignmentRequirement ?
2115: DeviceObject->AlignmentRequirement : 1;
2116:
2117: context = ExAllocatePool(
2118: NonPagedPool,
2119: sizeof(COMPLETION_CONTEXT) + HITACHI_MODE_DATA_SIZE + alignment
2120: );
2121:
2122: if (context == NULL) {
2123:
2124: //
2125: // If there is not enough memory to fulfill this request,
2126: // simply return. A subsequent retry will fail and another
2127: // chance to start the unit.
2128: //
2129:
2130: return;
2131: }
2132:
2133: context->DeviceObject = DeviceObject;
2134: srb = &context->Srb;
2135:
2136: RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
2137:
2138: //
2139: // Write length to SRB.
2140: //
2141:
2142: srb->Length = SCSI_REQUEST_BLOCK_SIZE;
2143:
2144: //
2145: // Set up SCSI bus address.
2146: //
2147:
2148: srb->PathId = deviceExtension->PathId;
2149: srb->TargetId = deviceExtension->TargetId;
2150: srb->Lun = deviceExtension->Lun;
2151:
2152: srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
2153: srb->TimeOutValue = deviceExtension->TimeOutValue;
2154:
2155: //
2156: // Set the transfer length.
2157: //
2158:
2159: srb->DataTransferLength = HITACHI_MODE_DATA_SIZE;
2160: srb->SrbFlags = SRB_FLAGS_DATA_OUT | SRB_FLAGS_DISABLE_AUTOSENSE | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
2161:
2162: //
2163: // The data buffer must be aligned.
2164: //
2165:
2166: srb->DataBuffer = (PVOID) (((ULONG) (context + 1) + (alignment - 1)) &
2167: ~(alignment - 1));
2168:
2169:
2170: //
2171: // Build the HITACHI read-ahead mode select CDB.
2172: //
2173:
2174: srb->CdbLength = 6;
2175: cdb = (PCDB)srb->Cdb;
2176: cdb->MODE_SENSE.LogicalUnitNumber = srb->Lun;
2177: cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SELECT;
2178: cdb->MODE_SENSE.AllocationLength = HITACHI_MODE_DATA_SIZE;
2179:
2180: //
2181: // Initialize the mode sense data.
2182: //
2183:
2184: modePage = srb->DataBuffer;
2185:
2186: RtlZeroMemory(modePage, HITACHI_MODE_DATA_SIZE);
2187:
2188: //
2189: // Set the page length field to 6.
2190: //
2191:
2192: modePage[5] = 6;
2193:
2194: //
2195: // Build the asynchronous request to be sent to the port driver.
2196: //
2197:
2198: irp = IoBuildAsynchronousFsdRequest(IRP_MJ_WRITE,
2199: DeviceObject,
2200: srb->DataBuffer,
2201: srb->DataTransferLength,
2202: &largeInt,
2203: NULL);
2204:
2205: IoSetCompletionRoutine(irp,
2206: (PIO_COMPLETION_ROUTINE)ScsiClassAsynchronousCompletion,
2207: context,
2208: TRUE,
2209: TRUE,
2210: TRUE);
2211:
2212: irpStack = IoGetNextIrpStackLocation(irp);
2213:
2214: irpStack->MajorFunction = IRP_MJ_SCSI;
2215:
2216: srb->OriginalRequest = irp;
2217:
2218: //
2219: // Save SRB address in next stack for port driver.
2220: //
2221:
2222: irpStack->Parameters.Scsi.Srb = (PVOID)srb;
2223:
2224: //
2225: // Set up IRP Address.
2226: //
2227:
2228: (VOID)IoCallDriver(deviceExtension->PortDeviceObject, irp);
2229:
2230: }
2231: }
2232:
2233: BOOLEAN
2234: CdRomIsPlayActive(
2235: IN PDEVICE_OBJECT DeviceObject
2236: )
2237:
2238: /*++
2239:
2240: Routine Description:
2241:
2242: This routine determines if the cd is currently playing music.
2243:
2244: Arguments:
2245:
2246: DeviceObject - Device object to test.
2247:
2248: Return Value:
2249:
2250: TRUE if the device is playing music.
2251:
2252: --*/
2253: {
2254: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
2255: PIRP irp;
2256: IO_STATUS_BLOCK ioStatus;
2257: KEVENT event;
2258: NTSTATUS status;
2259: PSUB_Q_CURRENT_POSITION currentBuffer;
2260:
2261: if (!PLAY_ACTIVE(deviceExtension)) {
2262: return(FALSE);
2263: }
2264:
2265: currentBuffer = ExAllocatePool(NonPagedPoolCacheAligned, sizeof(SUB_Q_CURRENT_POSITION));
2266:
2267: if (currentBuffer == NULL) {
2268: return(FALSE);
2269: }
2270:
2271: ((PCDROM_SUB_Q_DATA_FORMAT) currentBuffer)->Format = IOCTL_CDROM_CURRENT_POSITION;
2272: ((PCDROM_SUB_Q_DATA_FORMAT) currentBuffer)->Track = 0;
2273:
2274: //
2275: // Create notification event object to be used to signal the
2276: // request completion.
2277: //
2278:
2279: KeInitializeEvent(&event, NotificationEvent, FALSE);
2280:
2281: //
2282: // Build the synchronous request to be sent to the port driver
2283: // to perform the request.
2284: //
2285:
2286: irp = IoBuildDeviceIoControlRequest(IOCTL_CDROM_READ_Q_CHANNEL,
2287: deviceExtension->DeviceObject,
2288: currentBuffer,
2289: sizeof(CDROM_SUB_Q_DATA_FORMAT),
2290: currentBuffer,
2291: sizeof(SUB_Q_CURRENT_POSITION),
2292: FALSE,
2293: &event,
2294: &ioStatus);
2295:
2296: if (irp == NULL) {
2297: ExFreePool(currentBuffer);
2298: return FALSE;
2299: }
2300:
2301: //
2302: // Pass request to port driver and wait for request to complete.
2303: //
2304:
2305: status = IoCallDriver(deviceExtension->DeviceObject, irp);
2306:
2307: if (status == STATUS_PENDING) {
2308: KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
2309: status = ioStatus.Status;
2310: }
2311:
2312: if (!NT_SUCCESS(status)) {
2313: ExFreePool(currentBuffer);
2314: return FALSE;
2315: }
2316:
2317: ExFreePool(currentBuffer);
2318:
2319: return(PLAY_ACTIVE(deviceExtension));
2320:
2321: }
2322:
2323:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.