|
|
1.1 root 1: /*++
2:
3: Copyright (c) 1992, 1993 Microsoft Corporation
4:
5: Module Name:
6:
7: audio.c
8:
9: Abstract:
10:
11: This driver filters scsi-2 cdrom audio commands for non-scsi-2
12: compliant cdrom drives. At initialization, the driver scans the
13: scsi bus for a recognized non-scsi-2 cdrom drive, and if one is
14: found attached, installs itself to intercept IO_DEVICE_CONTROL
15: requests for this drive.
16:
17: Author:
18:
19: Rick Turner
20:
21: Environment:
22:
23: kernel mode only
24:
25: Notes:
26:
27: Revision History:
28:
29:
30: --*/
31:
32: #include "ntddk.h"
33: #include "scsi.h"
34: #include "stdio.h"
35: #include "stdarg.h"
36:
37: #include "cdaudio.h"
38:
39:
40: //
41: // Function declarations
42: //
43:
44: NTSTATUS
45: DriverEntry (
46: IN PDRIVER_OBJECT DriverObject,
47: IN PUNICODE_STRING RegistryPath
48: );
49:
50: NTSTATUS
51: CdAudioInitialize(
52: IN PDRIVER_OBJECT DriverObject
53: );
54:
55: NTSTATUS
56: CdAudioCreate(
57: IN PDEVICE_OBJECT DeviceObject,
58: IN PIRP Irp
59: );
60:
61: NTSTATUS
62: CdAudioReadWrite(
63: IN PDEVICE_OBJECT DeviceObject,
64: IN PIRP Irp
65: );
66:
67: NTSTATUS
68: CdAudioDeviceControl(
69: IN PDEVICE_OBJECT DeviceObject,
70: IN PIRP Irp
71: );
72:
73: NTSTATUS
74: CdAudioSendToNextDriver(
75: IN PDEVICE_OBJECT DeviceObject,
76: IN PIRP Irp
77: );
78:
79: BOOLEAN
80: CdAudioIsPlayActive(
81: IN PDEVICE_OBJECT DeviceObject
82: );
83:
84: NTSTATUS
85: CdAudioNECDeviceControl(
86: IN PDEVICE_OBJECT DeviceObject,
87: IN PIRP Irp
88: );
89:
90: NTSTATUS
91: CdAudioNECInterpretSenseInfo(
92: IN PDEVICE_OBJECT DeviceObject,
93: IN PSCSI_REQUEST_BLOCK Srb,
94: IN UCHAR MajorFunctionCode,
95: IN ULONG IoDeviceCode,
96: IN ULONG RetryCount,
97: OUT NTSTATUS *Status
98: );
99:
100: NTSTATUS
101: CdAudioNECSendSrbSynchronous(
102: PDEVICE_OBJECT DeviceObject,
103: PSCSI_REQUEST_BLOCK Srb,
104: PVOID BufferAddress,
105: ULONG BufferLength,
106: BOOLEAN WriteToDevice
107: );
108:
109: NTSTATUS
110: CdAudioPioneerDeviceControl(
111: IN PDEVICE_OBJECT DeviceObject,
112: IN PIRP Irp
113: );
114:
115: NTSTATUS
116: CdAudioDenonDeviceControl(
117: IN PDEVICE_OBJECT DeviceObject,
118: IN PIRP Irp
119: );
120:
121: NTSTATUS
122: CdAudioHitatchiSendPauseCommand(
123: IN PDEVICE_OBJECT DeviceObject
124: );
125:
126: NTSTATUS
127: CdAudioHitatchiDeviceControl(
128: IN PDEVICE_OBJECT DeviceObject,
129: IN PIRP Irp
130: );
131:
132: NTSTATUS
133: CdAudio535DeviceControl(
134: IN PDEVICE_OBJECT DeviceObject,
135: IN PIRP Irp
136: );
137:
138:
139: NTSTATUS
140: CdAudio435DeviceControl(
141: IN PDEVICE_OBJECT DeviceObject,
142: IN PIRP Irp
143: );
144:
145:
146: NTSTATUS
147: CdAudioIoCompletion(
148: IN PDEVICE_OBJECT DeviceObject,
149: IN PIRP Irp,
150: IN PVOID Context
151: );
152:
153: //
154: // from class.h
155: //
156:
157: NTSTATUS
158: ScsiClassSendSrbSynchronous(
159: PDEVICE_OBJECT DeviceObject,
160: PSCSI_REQUEST_BLOCK Srb,
161: PVOID BufferAddress,
162: ULONG BufferLength,
163: BOOLEAN WriteToDevice
164: );
165:
166: VOID
167: ScsiClassReleaseQueue(
168: IN PDEVICE_OBJECT DeviceObject
169: );
170:
171: //
172: // define for private CdDump
173: //
174:
175: int
176: sprintf(
177: char *s,
178: const char *format,
179: ...
180: );
181:
182:
183: NTSTATUS
184: DriverEntry(
185: IN PDRIVER_OBJECT DriverObject,
186: IN PUNICODE_STRING RegistryPath
187: )
188:
189: {
190: return CdAudioInitialize(DriverObject);
191: }
192:
193:
194:
195: NTSTATUS
196: CdAudioInitialize(
197: IN PDRIVER_OBJECT DriverObject
198: )
199:
200: /*++
201:
202: Routine Description:
203:
204: Initialize CdAudio driver.
205: This is the system initialization entry point when
206: the driver is linked into the kernel.
207:
208: Arguments:
209:
210: DriverObject
211:
212: Return Value:
213:
214: NTSTATUS
215:
216: --*/
217:
218: {
219: PCONFIGURATION_INFORMATION configurationInformation;
220: UCHAR deviceNameBuffer[64];
221: ANSI_STRING deviceName;
222: UNICODE_STRING unicodeDeviceName;
223: PDEVICE_OBJECT cdaudioDevice;
224: PCD_DEVICE_EXTENSION deviceExtension;
225: NTSTATUS status;
226: ULONG disks,activedisks;
227: SCSI_REQUEST_BLOCK srb;
228: PCDB cdb = (PCDB)srb.Cdb;
229: PUCHAR inquiryDataPtr;
230:
231: //
232: // Set up the device driver entry points.
233: //
234:
235: DriverObject->MajorFunction[IRP_MJ_CREATE] = CdAudioCreate;
236: DriverObject->MajorFunction[IRP_MJ_READ] = CdAudioReadWrite;
237: DriverObject->MajorFunction[IRP_MJ_WRITE] = CdAudioReadWrite;
238: DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = CdAudioDeviceControl;
239:
240: //
241: // Get the configuration information for this driver.
242: //
243:
244: configurationInformation = IoGetConfigurationInformation();
245:
246: CdDump((1, "CdAudioInitialize: Found %d CdRom drives\n",
247: configurationInformation->CdRomCount));
248:
249: //
250: // Find disk devices.
251: //
252:
253: activedisks = 0;
254: for (disks = 0; disks < configurationInformation->CdRomCount; disks++) {
255:
256:
257: //
258: // Create device name for CdAudio (one per CdRom).
259: //
260:
261: sprintf(deviceNameBuffer,
262: "\\Device\\CdAudio%d",
263: disks);
264: CdDump(( 5, "CdAudioInitialize: Checking \\Device\\CdRom%d\n",
265: disks ));
266: RtlInitAnsiString(&deviceName,
267: deviceNameBuffer);
268: RtlAnsiStringToUnicodeString(&unicodeDeviceName,
269: &deviceName,
270: TRUE);
271:
272: //
273: // Create the device object for CdAudio.
274: //
275:
276: status = IoCreateDevice(DriverObject,
277: sizeof(CD_DEVICE_EXTENSION),
278: &unicodeDeviceName,
279: FILE_DEVICE_CD_ROM,
280: 0,
281: FALSE,
282: &cdaudioDevice);
283:
284: RtlFreeUnicodeString(&unicodeDeviceName);
285:
286: if (!NT_SUCCESS(status)) {
287: CdDump((1, "CdAudioInitialize: IoCreateDevice( \"%s\" ) failed, 0x%lX\n",
288: deviceNameBuffer, status));
289: continue;
290: }
291:
292: //
293: // Point device extension back at device object.
294: //
295:
296: deviceExtension = cdaudioDevice->DeviceExtension;
297: deviceExtension->DeviceObject = cdaudioDevice;
298:
299: //
300: // Attach to cdrom drive. This call links the newly created
301: // device to the target device, returning the target device
302: // object.
303: //
304:
305: sprintf(deviceNameBuffer,
306: "\\Device\\CdRom%d",
307: disks);
308: RtlInitAnsiString(&deviceName,
309: deviceNameBuffer);
310: RtlAnsiStringToUnicodeString(&unicodeDeviceName,
311: &deviceName,
312: TRUE);
313: status = IoAttachDevice(cdaudioDevice,
314: &unicodeDeviceName,
315: &deviceExtension->TargetDeviceObject);
316: RtlFreeUnicodeString(&unicodeDeviceName);
317:
318: if (!NT_SUCCESS(status)) {
319: IoDeleteDevice(cdaudioDevice);
320: CdDump((1, "CdAudioInialize: IoAttachDevice( \"%s\" ) failed, 0x%lX\n",
321: deviceNameBuffer, status));
322: continue;
323: }
324:
325: //
326: // Initialize the class device extension. This is used by the
327: // class commands such as ScsiClassSendSrbSynchronous. The only fields used
328: // are the port device object pointer which is set to the attached
329: // device. The DeviceNumber, DeviceObject, and TimeOutVlaue are also
330: // used. The logical unit address will be set the the lower driver.
331: //
332:
333: deviceExtension->ClassDeviceExtension.DeviceObject = cdaudioDevice;
334: deviceExtension->ClassDeviceExtension.DeviceNumber = disks;
335: deviceExtension->ClassDeviceExtension.PortDeviceObject =
336: deviceExtension->TargetDeviceObject;
337: deviceExtension->ClassDeviceExtension.TimeOutValue = AUDIO_TIMEOUT;
338:
339: //
340: // Indicate to drivers above us that we want IRPs
341: // with MDLs, so we can pass them directly on to
342: // scsicdrm.sys when we don't handle the call.
343: //
344:
345: cdaudioDevice->Flags |= DO_DIRECT_IO;
346:
347: //
348: // Check to see if we want to install for this
349: // cdrom drive. Build up cdb/srb, and send it
350: // to this drive.
351: //
352:
353: //
354: // Zero CDB in SRB on stack
355: //
356:
357: RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
358:
359: //
360: // Fill in CDB for INQUIRY to CDROM
361: //
362:
363: cdb->CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY;
364: cdb->CDB6INQUIRY.AllocationLength = INQUIRYDATABUFFERSIZE;
365:
366: //
367: // Allocate buffer for returned inquiry data
368: //
369:
370: inquiryDataPtr = (PUCHAR)ExAllocatePool( NonPagedPoolCacheAligned,
371: INQUIRYDATABUFFERSIZE
372: );
373:
374: //
375: // Set length of CDB
376: //
377:
378: srb.CdbLength = 6;
379:
380: //
381: // Set timeout value.
382: //
383:
384: srb.TimeOutValue = AUDIO_TIMEOUT;
385:
386: status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
387: &srb,
388: inquiryDataPtr,
389: INQUIRYDATABUFFERSIZE,
390: FALSE
391: );
392:
393: if (!NT_SUCCESS(status)) {
394:
395: CdDump(( 1, "CdAudioInitialize: Inquiry failed! (0x%lx)\n",
396: status ));
397:
398: ExFreePool( inquiryDataPtr );
399: IoDetachDevice(deviceExtension->TargetDeviceObject);
400: IoDeleteDevice(cdaudioDevice);
401:
402: } else {
403:
404: //
405: // Initialize device extension data
406: //
407:
408: deviceExtension->Active = CDAUDIO_NOT_ACTIVE;
409: deviceExtension->Paused = CDAUDIO_NOT_PAUSED;
410: deviceExtension->PausedM = 0;
411: deviceExtension->PausedS = 0;
412: deviceExtension->PausedF = 0;
413: deviceExtension->LastEndM = 0;
414: deviceExtension->LastEndS = 0;
415: deviceExtension->LastEndF = 0;
416:
417: //
418: // Check for NEC drive
419: //
420:
421: if ((inquiryDataPtr[8] =='N') &&
422: (inquiryDataPtr[9] =='E') &&
423: (inquiryDataPtr[10]=='C')) {
424:
425: deviceExtension->Active = CDAUDIO_NEC;
426: CdDump(( 3, "CdAudioInitialize: %s is a NEC drive.\n",
427: deviceNameBuffer ));
428: }
429:
430: //
431: // Check for PIONEER DRM-6xx drive
432: //
433:
434: if ((inquiryDataPtr[8] =='P') &&
435: (inquiryDataPtr[9] =='I') &&
436: (inquiryDataPtr[10]=='O') &&
437: (inquiryDataPtr[23]=='D') &&
438: (inquiryDataPtr[24]=='R') &&
439: (inquiryDataPtr[25]=='M') &&
440: (inquiryDataPtr[27]=='6')) {
441:
442: deviceExtension->Active = CDAUDIO_PIONEER;
443: CdDump(( 3, "CdAudioInitialize: %s is a PIONEER DRM-6xx drive.\n",
444: deviceNameBuffer ));
445: }
446:
447: //
448: // Check for DENON drive
449: //
450:
451: if ((inquiryDataPtr[8] =='D') &&
452: (inquiryDataPtr[9] =='E') &&
453: (inquiryDataPtr[10]=='N') &&
454: (inquiryDataPtr[16]=='D') &&
455: (inquiryDataPtr[17]=='R') &&
456: (inquiryDataPtr[18]=='D') &&
457: (inquiryDataPtr[20]=='2') &&
458: (inquiryDataPtr[21]=='5') &&
459: (inquiryDataPtr[22]=='X')) {
460:
461: deviceExtension->Active = CDAUDIO_DENON;
462: CdDump(( 3, "CdAudioInitialize: %s is a DENON DRD-25X drive.\n",
463: deviceNameBuffer ));
464: }
465:
466: //
467: // Check for Chinon CDS-535
468: //
469:
470: if ((inquiryDataPtr[8] =='C') &&
471: (inquiryDataPtr[9] =='H') &&
472: (inquiryDataPtr[10]=='I') &&
473: (inquiryDataPtr[11]=='N') &&
474: (inquiryDataPtr[12]=='O') &&
475: (inquiryDataPtr[13]=='N') &&
476: (inquiryDataPtr[27]=='5') &&
477: (inquiryDataPtr[28]=='3') &&
478: (inquiryDataPtr[29]=='5') &&
479: (inquiryDataPtr[32]=='Q')) {
480:
481: deviceExtension->Active = CDAUDIO_CDS535;
482: CdDump(( 3, "CdAudioInitialize: %s is a Chinon CDS-535 drive.\n",
483: deviceNameBuffer ));
484: }
485:
486: //
487: // Check for Chinon CDS-435 or CDS-431
488: // (willing to handle versions M/N, S/U, and H)
489:
490: if ((inquiryDataPtr[8] =='C') &&
491: (inquiryDataPtr[9] =='H') &&
492: (inquiryDataPtr[10]=='I') &&
493: (inquiryDataPtr[11]=='N') &&
494: (inquiryDataPtr[12]=='O') &&
495: (inquiryDataPtr[13]=='N') &&
496: (inquiryDataPtr[27]=='4') &&
497: (inquiryDataPtr[28]=='3') &&
498: ((inquiryDataPtr[29]=='5') || (inquiryDataPtr[29]=='1')) &&
499: ((inquiryDataPtr[32]=='M') ||
500: (inquiryDataPtr[32]=='N') ||
501: (inquiryDataPtr[32]=='S') ||
502: (inquiryDataPtr[32]=='U') ||
503: (inquiryDataPtr[32]=='H')
504: )) {
505:
506: deviceExtension->Active = CDAUDIO_CDS435;
507: CdDump(( 3, "CdAudioInitialize: %s is a Chinon CDS-435/431 drive.\n",
508: deviceNameBuffer ));
509: }
510:
511: //
512: // Check for HITATCHI drives
513: //
514:
515: if ((inquiryDataPtr[8] =='H') &&
516: (inquiryDataPtr[9] =='I') &&
517: (inquiryDataPtr[10]=='T') &&
518: (inquiryDataPtr[16]=='C') &&
519: (inquiryDataPtr[17]=='D') &&
520: (inquiryDataPtr[18]=='R')) {
521:
522: //
523: // It's a Hitatchi drive...is it one we want to
524: // handle...?
525: //
526:
527: if ( ((inquiryDataPtr[20]=='1') &&
528: (inquiryDataPtr[21]=='7') &&
529: (inquiryDataPtr[22]=='5') &&
530: (inquiryDataPtr[23]=='0') &&
531: (inquiryDataPtr[24]=='S')) ||
532:
533: ((inquiryDataPtr[20]=='1') &&
534: (inquiryDataPtr[21]=='6') &&
535: (inquiryDataPtr[22]=='5') &&
536: (inquiryDataPtr[23]=='0') &&
537: (inquiryDataPtr[24]=='S')) ||
538:
539: ((inquiryDataPtr[20]=='3') &&
540: (inquiryDataPtr[21]=='6') &&
541: (inquiryDataPtr[22]=='5') &&
542: (inquiryDataPtr[23]=='0'))
543:
544: ) {
545:
546: //
547: // Yes, we want to handle this HITATCHI drive...
548: //
549:
550: deviceExtension->Active = CDAUDIO_HITATCHI;
551: inquiryDataPtr[25] = (UCHAR)0;
552: CdDump(( 3,
553: "CdAudioInitialize: %s is a HITATCHI %s drive.\n",
554: deviceNameBuffer, &inquiryDataPtr[16] ));
555: }
556:
557: }
558:
559: ExFreePool( inquiryDataPtr );
560:
561: //
562: // Check to see if we attached to ANY drives.
563: //
564:
565: if (deviceExtension->Active==CDAUDIO_NOT_ACTIVE) {
566:
567: IoDetachDevice(deviceExtension->TargetDeviceObject);
568: IoDeleteDevice(cdaudioDevice);
569: CdDump((1, "CdAudioInitialize: failed attach to %s\n",
570: deviceNameBuffer));
571:
572: } else
573:
574: activedisks++;
575:
576: } // end inquiry was successful
577:
578: } // end for (disks ...)
579:
580: CdDump((1, "CdAudioInitialize: Done searching all cdrom drives\n"));
581:
582: if (activedisks==0)
583:
584: return STATUS_NO_SUCH_DEVICE;
585:
586: else
587:
588: return STATUS_SUCCESS;
589:
590: } // end CdAudioInitialize()
591:
592:
593: NTSTATUS
594: CdAudioCreate(
595: IN PDEVICE_OBJECT DeviceObject,
596: IN PIRP Irp
597: )
598:
599: /*++
600:
601: Routine Description:
602:
603: This routine serves create commands. It does no more than
604: establish the drivers existance by returning status success.
605:
606: Arguments:
607:
608: DeviceObject
609: IRP
610:
611: Return Value:
612:
613: NT Status
614:
615: --*/
616:
617: {
618: UNREFERENCED_PARAMETER(DeviceObject);
619:
620: Irp->IoStatus.Status = STATUS_SUCCESS;
621:
622: IoCompleteRequest(Irp, 0);
623: return STATUS_SUCCESS;
624:
625: } // end CdAudioCreate()
626:
627:
628: NTSTATUS
629: CdAudioReadWrite(
630: IN PDEVICE_OBJECT DeviceObject,
631: IN PIRP Irp
632: )
633:
634: /*++
635:
636: Routine Description:
637:
638: This is the driver entry point for read and write requests
639: to the cdrom. Since we only want to trap device control requests,
640: we will just pass these requests on to the original driver.
641:
642: Arguments:
643:
644: DeviceObject - pointer to device object for disk partition
645: Irp - NT IO Request Packet
646:
647: Return Value:
648:
649: NTSTATUS - status of request
650:
651: --*/
652:
653: {
654: PCD_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
655:
656: //
657: // If the cd is playing music then reject this request.
658: //
659:
660: if (deviceExtension->PlayActive) {
661: Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
662: IoCompleteRequest(Irp, IO_NO_INCREMENT);
663: return STATUS_DEVICE_BUSY;
664: }
665:
666: //
667: // simply return status of driver below us...
668: //
669:
670: return CdAudioSendToNextDriver( DeviceObject, Irp );
671:
672: } // end CdAudioReadWrite()
673:
674:
675: NTSTATUS
676: CdAudioDeviceControl(
677: PDEVICE_OBJECT DeviceObject,
678: PIRP Irp
679: )
680:
681: /*++
682:
683: Routine Description:
684:
685: This routine is called by the I/O subsystem for device controls.
686:
687: Arguments:
688:
689: DeviceObject
690: Irp
691:
692: Return Value:
693:
694: NTSTATUS
695:
696: --*/
697:
698: {
699: PCD_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
700: NTSTATUS status;
701:
702: switch( deviceExtension->Active ) {
703:
704: case CDAUDIO_NOT_ACTIVE:
705: CdDump(( 3,
706: "CdAudioDeviceControl: NOT ACTIVE for this drive.\n"
707: ));
708: status = CdAudioSendToNextDriver( DeviceObject, Irp );
709: break;
710:
711: case CDAUDIO_NEC:
712: status = CdAudioNECDeviceControl( DeviceObject, Irp );
713: break;
714:
715: case CDAUDIO_PIONEER:
716: status = CdAudioPioneerDeviceControl( DeviceObject, Irp );
717: break;
718:
719: case CDAUDIO_DENON:
720: status = CdAudioDenonDeviceControl( DeviceObject, Irp );
721: break;
722:
723: case CDAUDIO_HITATCHI:
724: status = CdAudioHitatchiDeviceControl( DeviceObject, Irp );
725: break;
726:
727: case CDAUDIO_CDS535:
728: status = CdAudio535DeviceControl( DeviceObject, Irp );
729: break;
730:
731: case CDAUDIO_CDS435:
732: status = CdAudio435DeviceControl( DeviceObject, Irp );
733: break;
734:
735: default:
736: CdDump(( 1,
737: "CdAudioDeviceControl: Active==UNKNOWN!!! This is bad!\n"
738: ));
739: status = STATUS_UNSUCCESSFUL;
740:
741: }
742:
743: return status;
744:
745: } // end CdAudioDeviceControl()
746:
747:
748:
749: NTSTATUS
750: CdAudioSendToNextDriver(
751: PDEVICE_OBJECT DeviceObject,
752: PIRP Irp
753: )
754:
755: /*++
756:
757: Routine Description:
758:
759: This routine is sends the Irp to the next driver in line
760: when the Irp is not processed by this driver.
761:
762: Arguments:
763:
764: DeviceObject
765: Irp
766:
767: Return Value:
768:
769: NTSTATUS
770:
771: --*/
772:
773: {
774: PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
775: PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
776: PCD_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
777:
778: //
779: // Copy stack parameters to next stack.
780: //
781:
782: RtlMoveMemory(nextIrpStack,
783: currentIrpStack,
784: sizeof(IO_STACK_LOCATION));
785:
786: //
787: // Set IRP so IoComplete calls our completion routine.
788: //
789:
790: IoSetCompletionRoutine(Irp,
791: CdAudioIoCompletion,
792: deviceExtension,
793: TRUE,
794: TRUE,
795: TRUE);
796:
797: //
798: // Pass unrecognized device control requests
799: // down to next driver layer.
800: //
801:
802: return IoCallDriver(deviceExtension->TargetDeviceObject, Irp);
803:
804: }
805:
806: NTSTATUS
807: CdAudioIoCompletion(
808: IN PDEVICE_OBJECT DeviceObject,
809: IN PIRP Irp,
810: IN PVOID Context
811: )
812:
813: /*++
814:
815: Routine Description:
816:
817: This routine is called when the I/O request has completed.
818:
819: Arguments:
820:
821: DeviceObject - SimBad device object.
822: Irp - Completed request.
823: Context - not used. Set up to also be a pointer to the DeviceObject.
824:
825: Return Value:
826:
827: NTSTATUS
828:
829: --*/
830:
831: {
832: UNREFERENCED_PARAMETER(Context);
833: UNREFERENCED_PARAMETER(DeviceObject);
834:
835:
836: //
837: // If pending is returned for this Irp then mark current stack
838: // as pending
839: //
840:
841: if (Irp->PendingReturned) {
842:
843: IoMarkIrpPending( Irp );
844:
845: }
846:
847: return Irp->IoStatus.Status;
848:
849: }
850:
851: BOOLEAN
852: CdAudioIsPlayActive(
853: IN PDEVICE_OBJECT DeviceObject
854: )
855:
856: /*++
857:
858: Routine Description:
859:
860: This routine determines if the cd is currently playing music.
861:
862: Arguments:
863:
864: DeviceObject - Device object to test.
865:
866: Return Value:
867:
868: TRUE if the device is playing music.
869:
870: --*/
871: {
872: PCD_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
873: PIRP irp;
874: IO_STATUS_BLOCK ioStatus;
875: KEVENT event;
876: NTSTATUS status;
877: PSUB_Q_CURRENT_POSITION currentBuffer;
878: BOOLEAN returnValue;
879:
880: if (!deviceExtension->PlayActive) {
881: return(FALSE);
882: }
883:
884: currentBuffer = ExAllocatePool(NonPagedPoolCacheAligned, sizeof(SUB_Q_CURRENT_POSITION));
885:
886: if (currentBuffer == NULL) {
887: return(FALSE);
888: }
889:
890: ((PCDROM_SUB_Q_DATA_FORMAT) currentBuffer)->Format = IOCTL_CDROM_CURRENT_POSITION;
891: ((PCDROM_SUB_Q_DATA_FORMAT) currentBuffer)->Track = 0;
892:
893: //
894: // Create notification event object to be used to signal the
895: // request completion.
896: //
897:
898: KeInitializeEvent(&event, NotificationEvent, FALSE);
899:
900: //
901: // Build the synchronous request to be sent to the port driver
902: // to perform the request.
903: //
904:
905: irp = IoBuildDeviceIoControlRequest(IOCTL_CDROM_READ_Q_CHANNEL,
906: deviceExtension->DeviceObject,
907: currentBuffer,
908: sizeof(CDROM_SUB_Q_DATA_FORMAT),
909: currentBuffer,
910: sizeof(SUB_Q_CURRENT_POSITION),
911: FALSE,
912: &event,
913: &ioStatus);
914:
915: if (irp == NULL) {
916: ExFreePool(currentBuffer);
917: return FALSE;
918: }
919:
920: //
921: // Pass request to port driver and wait for request to complete.
922: //
923:
924: status = IoCallDriver(deviceExtension->DeviceObject, irp);
925:
926: if (status == STATUS_PENDING) {
927: KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
928: status = ioStatus.Status;
929: }
930:
931: if (!NT_SUCCESS(status)) {
932: ExFreePool(currentBuffer);
933: return FALSE;
934: }
935:
936: if (currentBuffer->Header.AudioStatus == AUDIO_STATUS_IN_PROGRESS) {
937:
938: returnValue = TRUE;
939: } else {
940: returnValue = FALSE;
941: deviceExtension->PlayActive = FALSE;
942: }
943:
944: ExFreePool(currentBuffer);
945:
946: return(returnValue);
947:
948:
949: }
950:
951:
952: NTSTATUS
953: CdAudioNECInterpretSenseInfo(
954: IN PDEVICE_OBJECT DeviceObject,
955: IN PSCSI_REQUEST_BLOCK Srb,
956: IN UCHAR MajorFunctionCode,
957: IN ULONG IoDeviceCode,
958: IN ULONG RetryCount,
959: OUT NTSTATUS *Status
960: )
961:
962: /*++
963:
964: Routine Description:
965:
966: This routine interprets the data returned from the SCSI
967: request sense. It determines the status to return in the
968: IRP and whether this request can be retried.
969:
970: Arguments:
971:
972: DeviceObject - Supplies the device object associated with this request.
973:
974: Srb - Supplies the scsi request block which failed.
975:
976: MajorFunctionCode - Supplies the function code to be used for logging.
977:
978: IoDeviceCode - Supplies the device code to be used for logging.
979:
980: Status - Returns the status for the request.
981:
982: Return Value:
983:
984: BOOLEAN TRUE: Drivers should retry this request.
985: FALSE: Drivers should not retry this request.
986:
987: --*/
988:
989: {
990: PCD_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
991: PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer;
992: PIRP irp = Srb->OriginalRequest;
993: BOOLEAN retry;
994: BOOLEAN logError;
995: ULONG uniqueId;
996: NTSTATUS logStatus;
997: PIO_ERROR_LOG_PACKET errorLogEntry;
998: ULONG badSector;
999:
1000: logError = FALSE;
1001: retry = TRUE;
1002: badSector = 0;
1003:
1004: //
1005: // Check that request sense buffer is valid.
1006: //
1007:
1008: if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) {
1009:
1010: CdDump((1,"CdAudioNECInterpretSenseInfo: Error code is %x\n",
1011: senseBuffer->ErrorCode));
1012:
1013: CdDump((1,"CdAudioNECInterpretSenseInfo: Sense key is %x\n",
1014: senseBuffer->SenseKey));
1015:
1016: CdDump((1,"CdAudioNECInterpretSenseInfo: Additional sense code is %x\n",
1017: senseBuffer->CommandSpecificInformation[1]));
1018:
1019: switch (senseBuffer->SenseKey & 0xf) {
1020:
1021: case SCSI_SENSE_NOT_READY:
1022:
1023: CdDump((1,"CdAudioNECInterpretSenseInfo: Device not ready\n"));
1024:
1025: *Status = STATUS_DEVICE_NOT_READY;
1026:
1027: retry = TRUE;
1028:
1029: switch (senseBuffer->CommandSpecificInformation[1]) {
1030:
1031: case NEC_SCSI_ERROR_NO_DISC:
1032: CdDump(( 1, "CdAudioNECInterpretSenseInfo: No disc in drive\n" ));
1033: *Status = STATUS_NO_MEDIA_IN_DEVICE;
1034: retry = FALSE;
1035: break;
1036:
1037: case NEC_SCSI_ERROR_ILLEGAL_DISC:
1038: CdDump(( 1, "CdAudioNECInterpretSenseInfo: Unrecognized media\n" ));
1039: *Status = STATUS_UNRECOGNIZED_MEDIA;
1040: retry = FALSE;
1041: break;
1042:
1043: case NEC_SCSI_ERROR_TRAY_OPEN:
1044: CdDump(( 1, "CdAudioNECInterpretSenseInfo: Tray open\n" ));
1045: *Status = STATUS_NO_MEDIA_IN_DEVICE;
1046: retry = FALSE;
1047: break;
1048:
1049: } // end switch
1050:
1051: break;
1052:
1053: case SCSI_SENSE_DATA_PROTECT:
1054:
1055: CdDump((1,
1056: "CdAudioNECInterpretSenseInfo: Media write protected\n"));
1057:
1058: *Status = STATUS_MEDIA_WRITE_PROTECTED;
1059:
1060: retry = FALSE;
1061:
1062: break;
1063:
1064: case SCSI_SENSE_MEDIUM_ERROR:
1065:
1066: CdDump((1,"CdAudioNECInterpretSenseInfo: Bad media\n"));
1067: *Status = STATUS_DEVICE_DATA_ERROR;
1068:
1069: retry = TRUE;
1070: logError = TRUE;
1071: uniqueId = 256;
1072: logStatus = IO_ERR_BAD_BLOCK;
1073: switch (senseBuffer->CommandSpecificInformation[1]) {
1074:
1075: case NEC_SCSI_ERROR_SEEK_ERROR:
1076: CdDump(( 1, "CdAudioNECInterpretSenseInfo: Sector not found\n" ));
1077: *Status = STATUS_NONEXISTENT_SECTOR;
1078: retry = FALSE;
1079: break;
1080: case NEC_SCSI_ERROR_MUSIC_AREA:
1081: CdDump((1,"CdAudioNECInterpretSenseInfo: Music area\n"));
1082: break;
1083:
1084: case NEC_SCSI_ERROR_DATA_AREA:
1085: CdDump((1,"CdAudioNECInterpretSenseInfo: Data area\n"));
1086: break;
1087:
1088:
1089: } // end switch
1090: break;
1091:
1092: case SCSI_SENSE_HARDWARE_ERROR:
1093:
1094: CdDump((1,"CdAudioNECInterpretSenseInfo: Hardware error\n"));
1095: *Status = STATUS_IO_DEVICE_ERROR;
1096:
1097: retry = TRUE;
1098: logError = TRUE;
1099: uniqueId = 257;
1100: logStatus = IO_ERR_CONTROLLER_ERROR;
1101: switch (senseBuffer->CommandSpecificInformation[1]) {
1102:
1103: case NEC_SCSI_ERROR_PARITY_ERROR:
1104: CdDump(( 1, "CdAudioNECInterpretSenseInfo: Parity error\n" ));
1105: *Status = STATUS_PARITY_ERROR;
1106: retry = FALSE;
1107: break;
1108:
1109: } // end switch
1110:
1111: break;
1112:
1113: case SCSI_SENSE_ILLEGAL_REQUEST:
1114:
1115: CdDump((1,
1116: "CdAudioNECInterpretSenseInfo: Illegal SCSI request\n"));
1117:
1118: *Status = STATUS_INVALID_DEVICE_REQUEST;
1119:
1120: switch (senseBuffer->AdditionalSenseCode) {
1121:
1122: case NEC_SCSI_ERROR_INVALID_COMMAND:
1123: CdDump((1,
1124: "CdAudioNECInterpretSenseInfo: Illegal command\n"));
1125: break;
1126:
1127: case NEC_SCSI_ERROR_INVALID_ADDRESS:
1128: CdDump((1,
1129: "CdAudioNECInterpretSenseInfo: Illegal block address\n"));
1130: *Status = STATUS_NONEXISTENT_SECTOR;
1131: break;
1132:
1133: case NEC_SCSI_ERROR_END_OF_VOLUME:
1134: CdDump((1,
1135: "CdAudioNECInterpretSenseInfo: Volume overflow\n"));
1136: *Status = STATUS_NONEXISTENT_SECTOR;
1137: break;
1138:
1139: case NEC_SCSI_ERROR_MEDIA_CHANGED:
1140: case NEC_SCSI_ERROR_DEVICE_RESET:
1141: CdDump((1,
1142: "CdAudioNECInterpretSenseInfo: Media Changed or device reset\n"));
1143:
1144: if (DeviceObject->Vpb->Flags & VPB_MOUNTED &&
1145: DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
1146:
1147: //
1148: // Set bit to indicate that media may have changed
1149: // and volume needs verification.
1150: //
1151:
1152: DeviceObject->Flags |= DO_VERIFY_VOLUME;
1153:
1154: *Status = STATUS_VERIFY_REQUIRED;
1155:
1156: retry = FALSE;
1157:
1158: } else {
1159: *Status = STATUS_IO_DEVICE_ERROR;
1160:
1161: retry = TRUE;
1162:
1163: }
1164: break;
1165:
1166:
1167: } // end switch ...
1168:
1169: retry = FALSE;
1170:
1171: break;
1172:
1173: case SCSI_SENSE_UNIT_ATTENTION:
1174:
1175: CdDump((3,"CdAudioNECInterpretSenseInfo: Unit attention\n"));
1176:
1177: if (DeviceObject->Vpb->Flags & VPB_MOUNTED &&
1178: DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
1179:
1180: //
1181: // Set bit to indicate that media may have changed
1182: // and volume needs verification.
1183: //
1184:
1185: DeviceObject->Flags |= DO_VERIFY_VOLUME;
1186:
1187: *Status = STATUS_VERIFY_REQUIRED;
1188:
1189: retry = FALSE;
1190:
1191: } else {
1192: *Status = STATUS_IO_DEVICE_ERROR;
1193:
1194: retry = TRUE;
1195:
1196: }
1197:
1198: break;
1199:
1200: case SCSI_SENSE_ABORTED_COMMAND:
1201:
1202: CdDump((1,"CdAudioNECInterpretSenseInfo: Command aborted\n"));
1203:
1204: *Status = STATUS_IO_DEVICE_ERROR;
1205:
1206: retry = TRUE;
1207:
1208: break;
1209:
1210: case SCSI_SENSE_RECOVERED_ERROR:
1211: CdDump((1,"CdAudioNECInterpretSenseInfo: Recovered error\n"));
1212: *Status = STATUS_SUCCESS;
1213: retry = FALSE;
1214: logError = TRUE;
1215: uniqueId = 258;
1216: logStatus = IO_ERR_CONTROLLER_ERROR;
1217: break;
1218:
1219: case SCSI_SENSE_NO_SENSE:
1220: CdDump((1,
1221: "CdAudioNECInterpretSenseInfo: No specific sense key\n"));
1222: *Status = STATUS_IO_DEVICE_ERROR;
1223: retry = TRUE;
1224: break;
1225:
1226: case SCSI_SENSE_BLANK_CHECK:
1227: CdDump((1,
1228: "CdAudioNECInterpretSenseInfo: Media blank check\n"));
1229: *Status = STATUS_NO_DATA_DETECTED;
1230: retry = FALSE;
1231: break;
1232:
1233: default:
1234:
1235: CdDump((1,
1236: "CdAudioNECInterpretSenseInfo: Unrecognized sense code\n"));
1237: *Status = STATUS_IO_DEVICE_ERROR;
1238: retry = TRUE;
1239:
1240: } // end switch
1241:
1242: } else {
1243:
1244: //
1245: // Request sense buffer not valid. No sense information
1246: // to pinpoint the error. Return general request fail.
1247: //
1248:
1249: CdDump((1,"CdAudioNECInterpretSenseInfo: Request sense info not valid\n"));
1250: retry = TRUE;
1251:
1252: switch (SRB_STATUS(Srb->SrbStatus)) {
1253: case SRB_STATUS_INVALID_LUN:
1254: case SRB_STATUS_INVALID_TARGET_ID:
1255: case SRB_STATUS_NO_DEVICE:
1256: case SRB_STATUS_NO_HBA:
1257: *Status = STATUS_NO_SUCH_DEVICE;
1258: retry = FALSE;
1259: break;
1260:
1261: case SRB_STATUS_COMMAND_TIMEOUT:
1262: case SRB_STATUS_TIMEOUT:
1263: *Status = STATUS_IO_TIMEOUT;
1264: break;
1265:
1266: case SRB_STATUS_SELECTION_TIMEOUT:
1267: *Status = STATUS_DEVICE_NOT_CONNECTED;
1268: break;
1269:
1270: case SRB_STATUS_DATA_OVERRUN:
1271: *Status = STATUS_DATA_OVERRUN;
1272: retry = FALSE;
1273: break;
1274:
1275: case SRB_STATUS_PHASE_SEQUENCE_FAILURE:
1276: *Status = STATUS_IO_DEVICE_ERROR;
1277:
1278: //
1279: // If there was phase sequence error then limit the number of
1280: // retries.
1281: //
1282:
1283: if (RetryCount > 1 ) {
1284: retry = FALSE;
1285: }
1286:
1287: break;
1288:
1289: case SRB_STATUS_REQUEST_FLUSHED:
1290:
1291: //
1292: // If the status needs verification bit is set. Then set
1293: // the status to need verificaiton and no retry; otherwise,
1294: // just retry the request.
1295: //
1296:
1297: if (DeviceObject->Flags & DO_VERIFY_VOLUME) {
1298:
1299: *Status = STATUS_VERIFY_REQUIRED;
1300: retry = FALSE;
1301: } else {
1302: *Status = STATUS_IO_DEVICE_ERROR;
1303: retry = TRUE;
1304:
1305: }
1306:
1307: break;
1308:
1309: default:
1310: *Status = STATUS_IO_DEVICE_ERROR;
1311: break;
1312:
1313: }
1314:
1315: }
1316:
1317: //
1318: // If there is a class specific error handler call it.
1319: //
1320:
1321: // if (deviceExtension->ClassError != NULL) {
1322: //
1323: // deviceExtension->ClassError(
1324: // DeviceObject,
1325: // Srb
1326: // );
1327: // }
1328:
1329: if (logError) {
1330:
1331: errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
1332: DeviceObject,
1333: sizeof(IO_ERROR_LOG_PACKET) + 5 * sizeof(ULONG)
1334: );
1335:
1336: if (errorLogEntry == NULL) {
1337:
1338: return retry;
1339:
1340: }
1341:
1342: if (retry && RetryCount < MAXIMUM_RETRIES) {
1343: errorLogEntry->FinalStatus = STATUS_SUCCESS;
1344: } else {
1345: errorLogEntry->FinalStatus = *Status;
1346: }
1347:
1348: errorLogEntry->ErrorCode = logStatus;
1349: errorLogEntry->SequenceNumber = 0;
1350: errorLogEntry->MajorFunctionCode = MajorFunctionCode;
1351: errorLogEntry->IoControlCode = IoDeviceCode;
1352: errorLogEntry->RetryCount = RetryCount;
1353: errorLogEntry->DumpDataSize = 5 * sizeof(ULONG);
1354: errorLogEntry->UniqueErrorValue = uniqueId;
1355: errorLogEntry->DumpDataSize = 5 * sizeof(ULONG);
1356: errorLogEntry->DumpData[0] = Srb->PathId;
1357: errorLogEntry->DumpData[1] = Srb->TargetId;
1358: errorLogEntry->DumpData[2] = Srb->Lun;
1359: errorLogEntry->DumpData[3] = 0;
1360: errorLogEntry->DumpData[4] = Srb->SrbStatus << 8 | Srb->ScsiStatus;
1361: errorLogEntry->DumpData[5] = senseBuffer->SenseKey << 16 |
1362: senseBuffer->AdditionalSenseCode << 8 |
1363: senseBuffer->AdditionalSenseCodeQualifier;
1364:
1365: IoWriteErrorLogEntry(errorLogEntry);
1366: }
1367:
1368: return retry;
1369:
1370: } // end InterpretSenseInfo()
1371:
1372: NTSTATUS
1373: CdAudioNECSendSrbSynchronous(
1374: PDEVICE_OBJECT DeviceObject,
1375: PSCSI_REQUEST_BLOCK Srb,
1376: PVOID BufferAddress,
1377: ULONG BufferLength,
1378: BOOLEAN WriteToDevice
1379: )
1380:
1381: /*++
1382:
1383: Routine Description:
1384:
1385: This routine is called by SCSI device controls to complete an
1386: SRB and send it to the port driver synchronously (ie wait for
1387: completion).
1388: The CDB is already completed along with the SRB CDB size and
1389: request timeout value.
1390:
1391: Arguments:
1392:
1393: Device Object
1394: SRB
1395: Buffer address and length (if transfer)
1396: WriteToDevice
1397:
1398: Return Value:
1399:
1400: NTSTATUS
1401:
1402: --*/
1403:
1404: {
1405: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
1406: IO_STATUS_BLOCK ioStatus;
1407: PIRP irp;
1408: PIO_STACK_LOCATION irpStack;
1409: KEVENT event;
1410: PUCHAR senseInfoBuffer;
1411: LARGE_INTEGER largeInt = RtlConvertUlongToLargeInteger(0);
1412: ULONG retryCount = MAXIMUM_RETRIES;
1413: NTSTATUS status;
1414: BOOLEAN retry;
1415:
1416: //
1417: // Write length to SRB.
1418: //
1419:
1420: Srb->Length = SCSI_REQUEST_BLOCK_SIZE;
1421:
1422: //
1423: // Set SCSI bus address.
1424: //
1425:
1426: Srb->PathId = deviceExtension->PathId;
1427: Srb->TargetId = deviceExtension->TargetId;
1428: Srb->Lun = deviceExtension->Lun;
1429:
1430: Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1431:
1432: //
1433: // BUGBUG: This is a violation of the SCSI spec but it is required for
1434: // some targets.
1435: //
1436:
1437: Srb->Cdb[1] |= deviceExtension->Lun << 5;
1438:
1439: //
1440: // Enable auto request sense.
1441: //
1442:
1443: Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
1444:
1445: //
1446: // Sense buffer is in non-paged pool.
1447: //
1448:
1449: senseInfoBuffer = ExAllocatePool( NonPagedPoolCacheAligned,
1450: SENSE_BUFFER_SIZE
1451: );
1452:
1453: if (senseInfoBuffer == NULL) {
1454:
1455: CdDump((1,
1456: "CdAudioNECSendSrbSynchronous: Can't allocate request sense buffer\n"));
1457: return(STATUS_INSUFFICIENT_RESOURCES);
1458: }
1459:
1460: Srb->SenseInfoBuffer = senseInfoBuffer;
1461:
1462: Srb->DataBuffer = BufferAddress;
1463:
1464: //
1465: // Start retries here.
1466: //
1467:
1468: retry:
1469:
1470: if (BufferAddress != NULL) {
1471:
1472: //
1473: // Build the synchronous request with data transfer.
1474: //
1475:
1476: irp = IoBuildSynchronousFsdRequest(
1477: WriteToDevice ? IRP_MJ_WRITE : IRP_MJ_READ,
1478: deviceExtension->PortDeviceObject,
1479: BufferAddress,
1480: BufferLength,
1481: &largeInt,
1482: &event,
1483: &ioStatus);
1484:
1485: if (irp == NULL) {
1486: ExFreePool(senseInfoBuffer);
1487: CdDump((1, "CdAudioNECSendSrbSynchronous: Can't allocate Irp\n"));
1488: return(STATUS_INSUFFICIENT_RESOURCES);
1489: }
1490:
1491: //
1492: // Set read flag.
1493: //
1494:
1495: Srb->SrbFlags = WriteToDevice ? SRB_FLAGS_DATA_OUT : SRB_FLAGS_DATA_IN;
1496:
1497: } else {
1498:
1499: //
1500: // Build synchronous request with no transfer.
1501: //
1502:
1503: irp = IoBuildDeviceIoControlRequest(
1504: IRP_MJ_DEVICE_CONTROL,
1505: deviceExtension->PortDeviceObject,
1506: NULL,
1507: 0,
1508: NULL,
1509: 0,
1510: TRUE,
1511: &event,
1512: &ioStatus
1513: );
1514:
1515: if (irp == NULL) {
1516: ExFreePool(senseInfoBuffer);
1517: CdDump((1, "ScsiClassSendSrbSynchronous: Can't allocate Irp\n"));
1518: return(STATUS_INSUFFICIENT_RESOURCES);
1519: }
1520:
1521: //
1522: // Clear flags.
1523: //
1524:
1525: Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;
1526: }
1527:
1528: //
1529: // Disable synchronous transfer for these requests.
1530: //
1531:
1532: Srb->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
1533:
1534: //
1535: // Set the event object to the unsignaled state.
1536: // It will be used to signal request completion.
1537: //
1538:
1539: KeInitializeEvent(&event, NotificationEvent, FALSE);
1540:
1541: //
1542: // Set the transfer length.
1543: //
1544:
1545: Srb->DataTransferLength = BufferLength;
1546:
1547: //
1548: // Zero out status.
1549: //
1550:
1551: Srb->ScsiStatus = Srb->SrbStatus = 0;
1552:
1553: Srb->NextSrb = 0;
1554:
1555: //
1556: // Get next stack location and
1557: // set major function code.
1558: //
1559:
1560: irpStack = IoGetNextIrpStackLocation(irp);
1561:
1562: irpStack->MajorFunction = IRP_MJ_SCSI;
1563:
1564: //
1565: // Set up SRB for execute scsi request.
1566: // Save SRB address in next stack for port driver.
1567: //
1568:
1569: irpStack->Parameters.Others.Argument1 = (PVOID)Srb;
1570:
1571: //
1572: // Set up IRP Address.
1573: //
1574:
1575: Srb->OriginalRequest = irp;
1576:
1577: //
1578: // No need to check the following 2 returned statuses as
1579: // SRB will have ending status.
1580: //
1581:
1582: status = IoCallDriver(deviceExtension->PortDeviceObject, irp);
1583:
1584: if (status == STATUS_PENDING) {
1585: KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
1586: }
1587:
1588: //
1589: // Check that request completed without error.
1590: //
1591:
1592: if (SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS) {
1593:
1594: //
1595: // Release the queue if it is frozen.
1596: //
1597:
1598: if (Srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
1599: ScsiClassReleaseQueue(DeviceObject);
1600: }
1601:
1602: //
1603: // Update status and determine if request should be retried.
1604: //
1605:
1606: retry = CdAudioNECInterpretSenseInfo(
1607: DeviceObject,
1608: Srb,
1609: IRP_MJ_SCSI,
1610: 0,
1611: MAXIMUM_RETRIES - retryCount,
1612: &status
1613: );
1614:
1615: if (retry) {
1616:
1617: if ((status == STATUS_DEVICE_NOT_READY && ((PSENSE_DATA) senseInfoBuffer)
1618: ->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY) ||
1619: SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SELECTION_TIMEOUT) {
1620:
1621: LARGE_INTEGER delay;
1622:
1623: //
1624: // Delay for 2 seconds.
1625: //
1626:
1627: delay.LowPart = - ( 10 * 1000 * 1000 * 2 );
1628: delay.HighPart = -1;
1629:
1630:
1631: //
1632: // Stall for a while to let the controller spinup.
1633: //
1634:
1635: (VOID) KeDelayExecutionThread(
1636: KernelMode,
1637: FALSE,
1638: &delay
1639: );
1640:
1641: }
1642:
1643:
1644: //
1645: // If retries are not exhausted then
1646: // retry this operation.
1647: //
1648:
1649: if (retryCount--) {
1650: goto retry;
1651: }
1652: }
1653:
1654: } else {
1655:
1656: status = STATUS_SUCCESS;
1657: }
1658:
1659: ExFreePool(senseInfoBuffer);
1660: return status;
1661:
1662: } // end CdAudioNECSendSrbSynchronous()
1663:
1664:
1665: NTSTATUS
1666: CdAudioNECDeviceControl(
1667: PDEVICE_OBJECT DeviceObject,
1668: PIRP Irp
1669: )
1670:
1671: /*++
1672:
1673: Routine Description:
1674:
1675: This routine is called by CdAudioDeviceControl to handle
1676: audio IOCTLs sent to NEC cdrom drives.
1677:
1678: Arguments:
1679:
1680: DeviceObject
1681: Irp
1682:
1683: Return Value:
1684:
1685: NTSTATUS
1686:
1687: --*/
1688:
1689: {
1690: PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
1691: PCD_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
1692: PCDROM_TOC cdaudioDataOut = Irp->AssociatedIrp.SystemBuffer;
1693: SCSI_REQUEST_BLOCK srb;
1694: PNEC_CDB cdb = (PNEC_CDB)srb.Cdb;
1695: NTSTATUS status;
1696: ULONG i,bytesTransfered;
1697: PUCHAR Toc;
1698: ULONG retryCount = 0;
1699: ULONG address;
1700: LARGE_INTEGER delay;
1701:
1702:
1703: NECRestart:
1704:
1705: //
1706: // Clear out cdb
1707: //
1708:
1709: RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
1710:
1711: //
1712: // What IOCTL do we need to execute?
1713: //
1714:
1715: switch (currentIrpStack->Parameters.DeviceIoControl.IoControlCode) {
1716:
1717: case IOCTL_CDROM_GET_LAST_SESSION:
1718:
1719: CdDump(( 2,
1720: "CdAudioNECDeviceControl: IOCTL_CDROM_GET_LAST_SESSION received.\n"
1721: ));
1722:
1723: if (currentIrpStack->Parameters.Read.Length <
1724: FIELD_OFFSET(CDROM_TOC, TrackData[1])) {
1725: status = STATUS_INFO_LENGTH_MISMATCH;
1726: break;
1727:
1728: }
1729:
1730:
1731: //
1732: // If the cd is playing music then reject this request.
1733: //
1734:
1735: if (CdAudioIsPlayActive(DeviceObject)) {
1736: status = STATUS_DEVICE_BUSY;
1737: break;
1738: }
1739:
1740: //
1741: // Allocate storage to hold TOC from disc
1742: //
1743:
1744: Toc = (PUCHAR)ExAllocatePool( NonPagedPoolCacheAligned,
1745: NEC_CDROM_TOC_SIZE
1746: );
1747:
1748: if (Toc==NULL) {
1749:
1750: status = STATUS_INSUFFICIENT_RESOURCES;
1751: goto SetStatusAndReturn;
1752:
1753: }
1754:
1755: //
1756: // Set up defaults
1757: //
1758:
1759: RtlZeroMemory( Toc, NEC_CDROM_TOC_SIZE );
1760: srb.CdbLength = 10;
1761:
1762: //
1763: // Fill in CDB
1764: //
1765:
1766: cdb->NEC_READ_TOC.OperationCode = NEC_READ_TOC_CODE;
1767: cdb->NEC_READ_TOC.Type = NEC_TRANSFER_WHOLE_TOC;
1768: cdb->NEC_READ_TOC.TrackNumber = NEC_TOC_TYPE_SESSION;
1769: srb.TimeOutValue = AUDIO_TIMEOUT;
1770: status = CdAudioNECSendSrbSynchronous(
1771: deviceExtension->DeviceObject,
1772: &srb,
1773: Toc,
1774: NEC_CDROM_TOC_SIZE,
1775: FALSE
1776: );
1777:
1778: if (!NT_SUCCESS(status) && (status!=STATUS_DATA_OVERRUN)) {
1779:
1780: CdDump(( 1,
1781: "CdAudioNECDeviceControl: READ_TOC error (0x%08lX)\n",
1782: status ));
1783:
1784:
1785: if (SRB_STATUS(srb.SrbStatus)!=SRB_STATUS_DATA_OVERRUN) {
1786:
1787: CdDump(( 1, "CdAudioNECDeviceControl: SRB ERROR (0x%lX)\n",
1788: srb.SrbStatus ));
1789: ExFreePool( Toc );
1790: goto SetStatusAndReturn;
1791: }
1792:
1793: } else {
1794:
1795: status = STATUS_SUCCESS;
1796: }
1797:
1798: //
1799: // Translate data into our format.
1800: //
1801:
1802: bytesTransfered = FIELD_OFFSET(CDROM_TOC, TrackData[1]);
1803: Irp->IoStatus.Information = bytesTransfered;
1804:
1805: RtlZeroMemory(cdaudioDataOut, bytesTransfered);
1806:
1807: cdaudioDataOut->Length[0] = bytesTransfered >> 8;
1808: cdaudioDataOut->Length[1] = (bytesTransfered & 0xFF);
1809:
1810: //
1811: // Determine if this is a multisession cd.
1812: //
1813:
1814: if (*((ULONG UNALIGNED *) &Toc[14]) == 0) {
1815:
1816: //
1817: // This is a single session disk. Just return.
1818: //
1819:
1820: ExFreePool(Toc);
1821: break;
1822: }
1823:
1824: //
1825: // Fake the session information.
1826: //
1827:
1828: cdaudioDataOut->FirstTrack = 1;
1829: cdaudioDataOut->LastTrack = 2;
1830:
1831: CdDump(( 4,
1832: "CdAudioNECDeviceControl: Tracks %d - %d, (0x%lX bytes)\n",
1833: cdaudioDataOut->FirstTrack,
1834: cdaudioDataOut->LastTrack,
1835: bytesTransfered
1836: ));
1837:
1838:
1839: //
1840: // Grab Information for the last session.
1841: //
1842:
1843: cdaudioDataOut->TrackData[0].Reserved = 0;
1844: cdaudioDataOut->TrackData[0].Control =
1845: ((Toc[2] & 0x0F) << 4) | (Toc[2] >> 4);
1846: cdaudioDataOut->TrackData[0].TrackNumber = 1;
1847:
1848: cdaudioDataOut->TrackData[0].Reserved1 = 0;
1849:
1850: //
1851: // Convert the minutes, seconds and frames to an absolute block
1852: // address. The formula comes from NEC.
1853: //
1854:
1855: address = (BCD_TO_DEC(Toc[15]) * 60 + BCD_TO_DEC(Toc[16])) * 75 + BCD_TO_DEC(Toc[17]);
1856:
1857: //
1858: // Put the address in big-endian in the the user's TOC.
1859: //
1860:
1861: cdaudioDataOut->TrackData[0].Address[0] = (UCHAR) (address >> 24);
1862: cdaudioDataOut->TrackData[0].Address[1] = (UCHAR) (address >> 16);
1863: cdaudioDataOut->TrackData[0].Address[2] = (UCHAR) (address >> 8);
1864: cdaudioDataOut->TrackData[0].Address[3] = (UCHAR) address;
1865:
1866: //
1867: // Free storage now that we've stored it elsewhere
1868: //
1869:
1870: ExFreePool( Toc );
1871: break;
1872:
1873: case IOCTL_CDROM_READ_TOC:
1874:
1875: CdDump(( 2,
1876: "CdAudioNECDeviceControl: IOCTL_CDROM_READ_TOC received.\n"
1877: ));
1878:
1879: //
1880: // If the cd is playing music then reject this request.
1881: //
1882:
1883: if (CdAudioIsPlayActive(DeviceObject)) {
1884: status = STATUS_DEVICE_BUSY;
1885: break;
1886: }
1887:
1888: //
1889: // Allocate storage to hold TOC from disc
1890: //
1891:
1892: Toc = (PUCHAR)ExAllocatePool( NonPagedPoolCacheAligned,
1893: NEC_CDROM_TOC_SIZE
1894: );
1895:
1896: if (Toc==NULL) {
1897:
1898: status = STATUS_INSUFFICIENT_RESOURCES;
1899: goto SetStatusAndReturn;
1900:
1901: }
1902:
1903: CdDump(( 4,
1904: "CdAudioNECDeviceControl: Toc = 0x%lX cdaudioDataOut = 0x%lX\n",
1905: Toc, cdaudioDataOut
1906: ));
1907:
1908: //
1909: // Set up defaults
1910: //
1911:
1912: RtlZeroMemory( Toc, NEC_CDROM_TOC_SIZE );
1913: srb.CdbLength = 10;
1914:
1915: //
1916: // Fill in CDB
1917: //
1918:
1919: cdb->NEC_READ_TOC.OperationCode = NEC_READ_TOC_CODE;
1920: cdb->NEC_READ_TOC.Type = NEC_TRANSFER_WHOLE_TOC;
1921: srb.TimeOutValue = AUDIO_TIMEOUT;
1922: status = CdAudioNECSendSrbSynchronous(
1923: deviceExtension->DeviceObject,
1924: &srb,
1925: Toc,
1926: NEC_CDROM_TOC_SIZE,
1927: FALSE
1928: );
1929:
1930: if (!NT_SUCCESS(status) && (status!=STATUS_DATA_OVERRUN)) {
1931:
1932: CdDump(( 1,
1933: "CdAudioNECDeviceControl: READ_TOC error (0x%08lX)\n",
1934: status ));
1935:
1936:
1937: if (SRB_STATUS(srb.SrbStatus)!=SRB_STATUS_DATA_OVERRUN) {
1938:
1939: CdDump(( 1, "CdAudioNECDeviceControl: SRB ERROR (0x%lX)\n",
1940: srb.SrbStatus ));
1941: ExFreePool( Toc );
1942: goto SetStatusAndReturn;
1943: }
1944:
1945: } else {
1946:
1947: status = STATUS_SUCCESS;
1948: }
1949:
1950: //
1951: // Translate data into our format.
1952: //
1953:
1954: bytesTransfered =
1955: currentIrpStack->Parameters.Read.Length > sizeof(CDROM_TOC) ?
1956: sizeof(CDROM_TOC) : currentIrpStack->Parameters.Read.Length;
1957: Irp->IoStatus.Information = bytesTransfered;
1958:
1959: cdaudioDataOut->Length[0] = bytesTransfered >> 8;
1960: cdaudioDataOut->Length[1] = (bytesTransfered & 0xFF);
1961: cdaudioDataOut->FirstTrack = BCD_TO_DEC(Toc[9]);
1962: cdaudioDataOut->LastTrack = BCD_TO_DEC(Toc[19]);
1963:
1964: CdDump(( 4,
1965: "CdAudioNECDeviceControl: Tracks %d - %d, (0x%lX bytes)\n",
1966: cdaudioDataOut->FirstTrack,
1967: cdaudioDataOut->LastTrack,
1968: bytesTransfered
1969: ));
1970:
1971:
1972: for( i=0;
1973: i<=( (ULONG)cdaudioDataOut->LastTrack -
1974: (ULONG)cdaudioDataOut->FirstTrack );
1975: i++
1976: ) {
1977:
1978: //
1979: // Grab Information for each track
1980: //
1981:
1982: cdaudioDataOut->TrackData[i].Reserved = 0;
1983: cdaudioDataOut->TrackData[i].Control =
1984: ((Toc[(i*10)+32] & 0x0F) << 4) | (Toc[(i*10)+32] >> 4);
1985: cdaudioDataOut->TrackData[i].TrackNumber =
1986: (i + cdaudioDataOut->FirstTrack);
1987:
1988: cdaudioDataOut->TrackData[i].Reserved1 = 0;
1989: cdaudioDataOut->TrackData[i].Address[0] = 0;
1990: cdaudioDataOut->TrackData[i].Address[1] = BCD_TO_DEC((Toc[(i*10)+39]));
1991: cdaudioDataOut->TrackData[i].Address[2] = BCD_TO_DEC((Toc[(i*10)+40]));
1992: cdaudioDataOut->TrackData[i].Address[3] = BCD_TO_DEC((Toc[(i*10)+41]));
1993:
1994: CdDump(( 4,
1995: "CdAudioNECDeviceControl: Track %d %d:%d:%d\n",
1996: cdaudioDataOut->TrackData[i].TrackNumber,
1997: cdaudioDataOut->TrackData[i].Address[1],
1998: cdaudioDataOut->TrackData[i].Address[2],
1999: cdaudioDataOut->TrackData[i].Address[3]
2000: ));
2001:
2002:
2003:
2004: }
2005:
2006: //
2007: // Fake "lead out track" info
2008: //
2009:
2010: cdaudioDataOut->TrackData[i].Reserved = 0;
2011: cdaudioDataOut->TrackData[i].Control = 0x10;
2012: cdaudioDataOut->TrackData[i].TrackNumber = 0xaa;
2013: cdaudioDataOut->TrackData[i].Reserved1 = 0;
2014: cdaudioDataOut->TrackData[i].Address[0] = 0;
2015: cdaudioDataOut->TrackData[i].Address[1] = BCD_TO_DEC(Toc[29]);
2016: cdaudioDataOut->TrackData[i].Address[2] = BCD_TO_DEC(Toc[30]);
2017: cdaudioDataOut->TrackData[i].Address[3] = BCD_TO_DEC(Toc[31]);
2018:
2019: CdDump(( 4,
2020: "CdAudioNECDeviceControl: Track %d %d:%d:%d\n",
2021: cdaudioDataOut->TrackData[i].TrackNumber,
2022: cdaudioDataOut->TrackData[i].Address[1],
2023: cdaudioDataOut->TrackData[i].Address[2],
2024: cdaudioDataOut->TrackData[i].Address[3]
2025: ));
2026:
2027: //
2028: // Free storage now that we've stored it elsewhere
2029: //
2030:
2031: ExFreePool( Toc );
2032: break;
2033:
2034: case IOCTL_CDROM_STOP_AUDIO:
2035:
2036: deviceExtension->PlayActive = FALSE;
2037:
2038: //
2039: // Same as scsi-2 spec, so just send to default driver
2040: //
2041:
2042: return CdAudioSendToNextDriver( DeviceObject, Irp );
2043: break;
2044:
2045: case IOCTL_CDROM_PLAY_AUDIO_MSF:
2046: {
2047:
2048: PCDROM_PLAY_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
2049:
2050: CdDump(( 3,
2051: "CdAudioNECDeviceControl: IOCTL_CDROM_PLAY_AUDIO_MSF received.\n"
2052: ));
2053:
2054: //
2055: // First, seek to Starting MSF and enter play mode.
2056: //
2057:
2058: srb.CdbLength = 10;
2059: srb.TimeOutValue = AUDIO_TIMEOUT;
2060: cdb->NEC_PLAY_AUDIO.OperationCode = NEC_AUDIO_TRACK_SEARCH_CODE;
2061: cdb->NEC_PLAY_AUDIO.PlayMode = NEC_ENTER_PLAY_MODE;
2062: cdb->NEC_PLAY_AUDIO.Minute = DEC_TO_BCD(inputBuffer->StartingM);
2063: cdb->NEC_PLAY_AUDIO.Second = DEC_TO_BCD(inputBuffer->StartingS);
2064: cdb->NEC_PLAY_AUDIO.Frame = DEC_TO_BCD(inputBuffer->StartingF);
2065: cdb->NEC_PLAY_AUDIO.Control = NEC_TYPE_ATIME;
2066:
2067: CdDump(( 3,
2068: "CdAudioNECDeviceControl: play start MSF is BCD(%x:%x:%x)\n",
2069: cdb->NEC_PLAY_AUDIO.Minute,
2070: cdb->NEC_PLAY_AUDIO.Second,
2071: cdb->NEC_PLAY_AUDIO.Frame
2072: ));
2073:
2074:
2075: status = CdAudioNECSendSrbSynchronous(deviceExtension->DeviceObject,
2076: &srb,
2077: NULL,
2078: 0,
2079: FALSE
2080: );
2081: if (NT_SUCCESS(status)) {
2082:
2083: //
2084: // Indicate the play actition is active.
2085: //
2086:
2087: deviceExtension->PlayActive = TRUE;
2088:
2089: //
2090: // Now, set the termination point for the play operation
2091: //
2092:
2093: RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
2094: cdb->NEC_PLAY_AUDIO.OperationCode = NEC_PLAY_AUDIO_CODE;
2095: cdb->NEC_PLAY_AUDIO.PlayMode = NEC_PLAY_STEREO;
2096: cdb->NEC_PLAY_AUDIO.Minute = DEC_TO_BCD(inputBuffer->EndingM);
2097: cdb->NEC_PLAY_AUDIO.Second = DEC_TO_BCD(inputBuffer->EndingS);
2098: cdb->NEC_PLAY_AUDIO.Frame = DEC_TO_BCD(inputBuffer->EndingF);
2099: cdb->NEC_PLAY_AUDIO.Control = NEC_TYPE_ATIME;
2100:
2101: CdDump(( 3,
2102: "CdAudioNECDeviceControl: play end MSF is BCD(%x:%x:%x)\n",
2103: cdb->NEC_PLAY_AUDIO.Minute,
2104: cdb->NEC_PLAY_AUDIO.Second,
2105: cdb->NEC_PLAY_AUDIO.Frame
2106: ));
2107:
2108: status = CdAudioNECSendSrbSynchronous(
2109: deviceExtension->DeviceObject,
2110: &srb,
2111: NULL,
2112: 0,
2113: FALSE
2114: );
2115:
2116:
2117: }
2118: }
2119: break;
2120:
2121: case IOCTL_CDROM_SEEK_AUDIO_MSF:
2122: {
2123:
2124: PCDROM_SEEK_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
2125:
2126: CdDump(( 3,
2127: "CdAudioNECDeviceControl: IOCTL_CDROM_SEEK_AUDIO_MSF received.\n"
2128: ));
2129:
2130: //
2131: // seek to MSF and enter pause (still) mode.
2132: //
2133:
2134: srb.CdbLength = 10;
2135: srb.TimeOutValue = AUDIO_TIMEOUT;
2136: cdb->NEC_SEEK_AUDIO.OperationCode = NEC_AUDIO_TRACK_SEARCH_CODE;
2137: cdb->NEC_SEEK_AUDIO.Minute = DEC_TO_BCD(inputBuffer->M);
2138: cdb->NEC_SEEK_AUDIO.Second = DEC_TO_BCD(inputBuffer->S);
2139: cdb->NEC_SEEK_AUDIO.Frame = DEC_TO_BCD(inputBuffer->F);
2140: cdb->NEC_SEEK_AUDIO.Control = NEC_TYPE_ATIME;
2141: CdDump(( 4,
2142: "CdAudioNECDeviceControl: seek MSF is %d:%d:%d\n",
2143: cdb->NEC_SEEK_AUDIO.Minute,
2144: cdb->NEC_SEEK_AUDIO.Second,
2145: cdb->NEC_SEEK_AUDIO.Frame
2146: ));
2147:
2148: status = CdAudioNECSendSrbSynchronous(
2149: deviceExtension->DeviceObject,
2150: &srb,
2151: NULL,
2152: 0,
2153: FALSE
2154: );
2155:
2156: }
2157: break;
2158:
2159: case IOCTL_CDROM_PAUSE_AUDIO:
2160:
2161: CdDump(( 3,
2162: "CdAudioNECDeviceControl: IOCTL_CDROM_PAUSE_AUDIO received.\n"
2163: ));
2164:
2165: deviceExtension->PlayActive = FALSE;
2166:
2167: //
2168: // Enter pause (still ) mode
2169: //
2170:
2171: srb.CdbLength = 10;
2172: srb.TimeOutValue = AUDIO_TIMEOUT;
2173: cdb->NEC_PAUSE_AUDIO.OperationCode = NEC_STILL_CODE;
2174: status = CdAudioNECSendSrbSynchronous(
2175: deviceExtension->DeviceObject,
2176: &srb,
2177: NULL,
2178: 0,
2179: FALSE
2180: );
2181:
2182: break;
2183:
2184: case IOCTL_CDROM_RESUME_AUDIO:
2185:
2186: CdDump(( 3,
2187: "CdAudioNECDeviceControl: IOCTL_CDROM_RESUME_AUDIO received.\n"
2188: ));
2189:
2190: //
2191: // Resume play
2192: //
2193:
2194: srb.CdbLength = 10;
2195: srb.TimeOutValue = AUDIO_TIMEOUT;
2196: cdb->NEC_PLAY_AUDIO.OperationCode = NEC_PLAY_AUDIO_CODE;
2197: cdb->NEC_PLAY_AUDIO.PlayMode = NEC_PLAY_STEREO;
2198: cdb->NEC_PLAY_AUDIO.Control = NEC_TYPE_NO_CHANGE;
2199: status = CdAudioNECSendSrbSynchronous(
2200: deviceExtension->DeviceObject,
2201: &srb,
2202: NULL,
2203: 0,
2204: FALSE
2205: );
2206: break;
2207:
2208: case IOCTL_CDROM_READ_Q_CHANNEL:
2209: {
2210:
2211: PSUB_Q_CURRENT_POSITION userPtr =
2212: Irp->AssociatedIrp.SystemBuffer;
2213: PUCHAR SubQPtr =
2214: ExAllocatePool( NonPagedPoolCacheAligned,
2215: NEC_Q_CHANNEL_TRANSFER_SIZE
2216: );
2217:
2218: CdDump(( 5,
2219: "CdAudioNECDeviceControl: IOCTL_CDROM_READ_Q_CHANNEL received.\n"
2220: ));
2221:
2222: if (SubQPtr==NULL) {
2223:
2224: CdDump(( 1,
2225: "CdAudioNECDeviceControl: READ_Q_CHANNEL, SubQPtr==NULL!\n"
2226: ));
2227:
2228: status = STATUS_INSUFFICIENT_RESOURCES;
2229: RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
2230: goto SetStatusAndReturn;
2231:
2232: }
2233:
2234: RtlZeroMemory( SubQPtr, NEC_Q_CHANNEL_TRANSFER_SIZE );
2235:
2236: if ( ((PCDROM_SUB_Q_DATA_FORMAT)userPtr)->Format!=
2237: IOCTL_CDROM_CURRENT_POSITION) {
2238:
2239: CdDump(( 1,
2240: "CdAudioNECDeviceControl: READ_Q_CHANNEL, illegal Format (%d)\n",
2241: ((PCDROM_SUB_Q_DATA_FORMAT)userPtr)->Format
2242: ));
2243:
2244: ExFreePool( SubQPtr );
2245: status = STATUS_UNSUCCESSFUL;
2246: RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
2247: goto SetStatusAndReturn;
2248: }
2249:
2250: NECSeek:
2251:
2252: //
2253: // Set up to read Q Channel
2254: //
2255:
2256: srb.CdbLength = 10;
2257: srb.TimeOutValue = AUDIO_TIMEOUT;
2258: cdb->NEC_READ_Q_CHANNEL.OperationCode = NEC_READ_SUB_Q_CHANNEL_CODE;
2259: cdb->NEC_READ_Q_CHANNEL.TransferSize = NEC_Q_CHANNEL_TRANSFER_SIZE; // Transfer Length
2260: CdDump(( 4, "CdAudioNECDeviceControl: cdb = 0x%lx srb = 0x%x SubQPtr = 0x%lx\n",
2261: cdb,
2262: &srb,
2263: SubQPtr
2264: ));
2265: #if DBG
2266: if (CdAudioDebug>5) {
2267:
2268: DbgBreakPoint();
2269:
2270: }
2271: #endif
2272: status = CdAudioNECSendSrbSynchronous(
2273: deviceExtension->DeviceObject,
2274: &srb,
2275: SubQPtr,
2276: NEC_Q_CHANNEL_TRANSFER_SIZE,
2277: FALSE
2278: );
2279: CdDump(( 4, "CdAudioNECDeviceControl: READ_Q_CHANNEL, status is 0x%lX\n",
2280: status
2281: ));
2282:
2283: if ((NT_SUCCESS(status)) || (status==STATUS_DATA_OVERRUN)) {
2284:
2285: userPtr->Header.Reserved = 0;
2286: if (SubQPtr[0]==0x00)
2287: userPtr->Header.AudioStatus = AUDIO_STATUS_IN_PROGRESS;
2288: else if (SubQPtr[0]==0x01) {
2289:
2290: userPtr->Header.AudioStatus = AUDIO_STATUS_PAUSED;
2291: deviceExtension->PlayActive = FALSE;
2292: } else if (SubQPtr[0]==0x02) {
2293: userPtr->Header.AudioStatus = AUDIO_STATUS_PAUSED;
2294: deviceExtension->PlayActive = FALSE;
2295: } else if (SubQPtr[0]==0x03) {
2296:
2297: userPtr->Header.AudioStatus = AUDIO_STATUS_PLAY_COMPLETE;
2298: deviceExtension->PlayActive = FALSE;
2299:
2300: } else {
2301: deviceExtension->PlayActive = FALSE;
2302:
2303: }
2304:
2305: userPtr->Header.DataLength[0] = 0;
2306: userPtr->Header.DataLength[0] = 12;
2307:
2308: userPtr->FormatCode = 0x01;
2309: userPtr->Control = SubQPtr[1] & 0x0F;
2310: userPtr->ADR = 0;
2311: userPtr->TrackNumber = BCD_TO_DEC(SubQPtr[2]);
2312: userPtr->IndexNumber = BCD_TO_DEC(SubQPtr[3]);
2313: userPtr->AbsoluteAddress[0] = 0;
2314: userPtr->AbsoluteAddress[1] = BCD_TO_DEC((SubQPtr[7]));
2315: userPtr->AbsoluteAddress[2] = BCD_TO_DEC((SubQPtr[8]));
2316: userPtr->AbsoluteAddress[3] = BCD_TO_DEC((SubQPtr[9]));
2317: userPtr->TrackRelativeAddress[0] = 0;
2318: userPtr->TrackRelativeAddress[1] = BCD_TO_DEC((SubQPtr[4]));
2319: userPtr->TrackRelativeAddress[2] = BCD_TO_DEC((SubQPtr[5]));
2320: userPtr->TrackRelativeAddress[3] = BCD_TO_DEC((SubQPtr[6]));
2321: Irp->IoStatus.Information = 16;
2322: CdDump(( 5,
2323: "CdAudioNECDeviceControl: <SubQPtr> Status = 0x%lx, [%x %x:%x] (%x:%x:%x)\n",
2324: SubQPtr[0],
2325: SubQPtr[2],
2326: SubQPtr[4],
2327: SubQPtr[5],
2328: SubQPtr[7],
2329: SubQPtr[8],
2330: SubQPtr[9]
2331: ));
2332: CdDump(( 5,
2333: "CdAudioNECDeviceControl: <userPtr> Status = 0x%lx, [%d %d:%d] (%d:%d:%d)\n",
2334: userPtr->Header.AudioStatus,
2335: userPtr->TrackNumber,
2336: userPtr->TrackRelativeAddress[1],
2337: userPtr->TrackRelativeAddress[2],
2338: userPtr->AbsoluteAddress[1],
2339: userPtr->AbsoluteAddress[2],
2340: userPtr->AbsoluteAddress[3]
2341: ));
2342:
2343: //
2344: // Sometimes the NEC will return a bogus value for track number.
2345: // if this occurs just retry.
2346: //
2347:
2348: if (userPtr->TrackNumber > MAXIMUM_NUMBER_TRACKS) {
2349:
2350: //
2351: // Delay for .5 seconds.
2352: //
2353:
2354: delay = LiFromLong( - 10 * 1000 * 100 * 5 );
2355:
2356: //
2357: // Stall for a while to let the controller spinup.
2358: //
2359:
2360: KeDelayExecutionThread(KernelMode,
2361: FALSE,
2362: &delay);
2363:
2364: if (retryCount++ < MAXIMUM_RETRIES) {
2365: goto NECSeek;
2366: } else {
2367: status = STATUS_DEVICE_PROTOCOL_ERROR;
2368: }
2369:
2370: } else {
2371: status = STATUS_SUCCESS;
2372: }
2373:
2374: } else {
2375:
2376: RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
2377: CdDump(( 1,
2378: "CdAudioNECDeviceControl: READ_Q_CHANNEL failed (0x%08lX)\n",
2379: status
2380: ));
2381:
2382: }
2383:
2384: ExFreePool( SubQPtr );
2385:
2386: }
2387: break;
2388:
2389: case IOCTL_CDROM_EJECT_MEDIA:
2390:
2391: CdDump(( 3,
2392: "CdAudioNECDeviceControl: IOCTL_CDROM_EJECT_MEDIA received.\n"
2393: ));
2394:
2395: deviceExtension->PlayActive = FALSE;
2396:
2397: //
2398: // Set up to read Q Channel
2399: //
2400:
2401: srb.CdbLength = 10;
2402: srb.TimeOutValue = AUDIO_TIMEOUT;
2403: cdb->NEC_EJECT.OperationCode = NEC_EJECT_CODE;
2404: status = CdAudioNECSendSrbSynchronous(
2405: deviceExtension->DeviceObject,
2406: &srb,
2407: NULL,
2408: 0,
2409: FALSE
2410: );
2411:
2412: CdDump(( 3,
2413: "CdAudioNECDeviceControl: invalidating cached TOC!\n"
2414: ));
2415: break;
2416:
2417: case IOCTL_CDROM_GET_CONTROL:
2418: case IOCTL_CDROM_GET_VOLUME:
2419: case IOCTL_CDROM_SET_VOLUME:
2420:
2421: CdDump(( 3, "CdAudioNECDeviceControl: Not Supported yet.\n" ));
2422: status = STATUS_INVALID_DEVICE_REQUEST;
2423: break;
2424:
2425: case IOCTL_CDROM_CHECK_VERIFY:
2426:
2427: //
2428: // Update the play active flag.
2429: //
2430:
2431: CdAudioIsPlayActive(DeviceObject);
2432:
2433: //
2434: // Fall through and pass the request to the next driver.
2435: //
2436:
2437: default:
2438:
2439: CdDump(( 5,
2440: "CdAudioNECDeviceControl: Unsupported device IOCTL (0x%lX)\n",
2441: currentIrpStack->Parameters.DeviceIoControl.IoControlCode
2442: ));
2443: return CdAudioSendToNextDriver( DeviceObject, Irp );
2444: break;
2445:
2446: } // end switch( IOCTL )
2447:
2448: SetStatusAndReturn:
2449:
2450: //
2451: // set status code and return
2452: //
2453:
2454: if (status == STATUS_VERIFY_REQUIRED) {
2455:
2456:
2457: //
2458: // If the status is verified required and the this request
2459: // should bypass verify required then retry the request.
2460: //
2461:
2462: if (currentIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME) {
2463:
2464: status = STATUS_IO_DEVICE_ERROR;
2465: goto NECRestart;
2466:
2467: }
2468:
2469: IoSetHardErrorOrVerifyDevice( Irp,
2470: deviceExtension->TargetDeviceObject
2471: );
2472:
2473: Irp->IoStatus.Information = 0;
2474: }
2475:
2476: Irp->IoStatus.Status = status;
2477: IoCompleteRequest(Irp, IO_NO_INCREMENT);
2478: return status;
2479:
2480: }
2481:
2482:
2483: NTSTATUS
2484: CdAudioPioneerDeviceControl(
2485: PDEVICE_OBJECT DeviceObject,
2486: PIRP Irp
2487: )
2488:
2489: /*++
2490:
2491: Routine Description:
2492:
2493: This routine is called by CdAudioDeviceControl to handle
2494: audio IOCTLs sent to PIONEER DRM-6xx cdrom drives.
2495:
2496: Arguments:
2497:
2498: DeviceObject
2499: Irp
2500:
2501: Return Value:
2502:
2503: NTSTATUS
2504:
2505: --*/
2506:
2507: {
2508: PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
2509: PCD_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
2510: PCDROM_TOC cdaudioDataOut = Irp->AssociatedIrp.SystemBuffer;
2511: SCSI_REQUEST_BLOCK srb;
2512: PPNR_CDB cdb = (PPNR_CDB)srb.Cdb;
2513: NTSTATUS status;
2514: ULONG i,bytesTransfered,retry;
2515: PUCHAR Toc;
2516:
2517: PioneerRestart:
2518:
2519: //
2520: // Clear out cdb
2521: //
2522:
2523: RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
2524:
2525: //
2526: // What IOCTL do we need to execute?
2527: //
2528:
2529: switch (currentIrpStack->Parameters.DeviceIoControl.IoControlCode) {
2530:
2531: case IOCTL_CDROM_READ_TOC:
2532: CdDump(( 3,
2533: "CdAudioPioneerDeviceControl: IOCTL_CDROM_READ_TOC received.\n"
2534: ));
2535:
2536: //
2537: // If the cd is playing music then reject this request.
2538: //
2539:
2540: if (CdAudioIsPlayActive(DeviceObject)) {
2541: status = STATUS_DEVICE_BUSY;
2542: break;
2543: }
2544:
2545: //
2546: // Allocate storage to hold TOC from disc
2547: //
2548:
2549: Toc = (PUCHAR)ExAllocatePool( NonPagedPoolCacheAligned,
2550: CDROM_TOC_SIZE
2551: );
2552:
2553: if (Toc==NULL) {
2554:
2555: status = STATUS_INSUFFICIENT_RESOURCES;
2556: goto SetStatusAndReturn;
2557:
2558: }
2559:
2560: //
2561: // Set up defaults
2562: //
2563:
2564: RtlZeroMemory( Toc, CDROM_TOC_SIZE );
2565:
2566: //
2567: // mount this disc (via START/STOP unit), which is
2568: // necessary since we don't know which is the
2569: // currently loaded disc.
2570: //
2571:
2572: cdb->PNR_START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
2573: cdb->PNR_START_STOP.Start = 1;
2574: srb.CdbLength = 6;
2575: srb.TimeOutValue = AUDIO_TIMEOUT;
2576: status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
2577: &srb,
2578: NULL,
2579: 0,
2580: FALSE
2581: );
2582:
2583: if (!NT_SUCCESS(status)) {
2584:
2585: CdDump(( 1,
2586: "CdAudioPioneerDeviceControl: Start Unit failed (0x%lx)\n",
2587: status ));
2588: ExFreePool( Toc );
2589: goto SetStatusAndReturn;
2590:
2591: }
2592:
2593: //
2594: // Get first and last tracks
2595: //
2596:
2597: RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
2598: srb.CdbLength = 10;
2599: cdb->PNR_READ_TOC.OperationCode = PIONEER_READ_TOC_CODE;
2600: cdb->PNR_READ_TOC.AssignedLength[1] = PIONEER_TRANSFER_SIZE;
2601: cdb->PNR_READ_TOC.Type = PIONEER_READ_FIRST_AND_LAST;
2602: srb.TimeOutValue = AUDIO_TIMEOUT;
2603: status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
2604: &srb,
2605: Toc,
2606: PIONEER_TRANSFER_SIZE,
2607: FALSE
2608: );
2609:
2610: if (!NT_SUCCESS(status)) {
2611:
2612: CdDump(( 1,
2613: "CdAudioPioneerDeviceControl: ReadTOC, First/Last Tracks failed (0x%lx)\n",
2614: status ));
2615: ExFreePool( Toc );
2616: goto SetStatusAndReturn;
2617:
2618: }
2619:
2620: cdaudioDataOut->FirstTrack = BCD_TO_DEC(Toc[0]);
2621: cdaudioDataOut->LastTrack = BCD_TO_DEC(Toc[1]);
2622:
2623: //
2624: // Now, get info about each track
2625: //
2626:
2627: for( i=0;
2628: i<=( (ULONG)cdaudioDataOut->LastTrack -
2629: (ULONG)cdaudioDataOut->FirstTrack );
2630: i++
2631: ) {
2632:
2633: //
2634: // Get TOC info for this track
2635: //
2636:
2637: RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
2638: cdb->PNR_READ_TOC.OperationCode = PIONEER_READ_TOC_CODE;
2639: cdb->PNR_READ_TOC.TrackNumber = DEC_TO_BCD((i+cdaudioDataOut->FirstTrack)); // track
2640: cdb->PNR_READ_TOC.AssignedLength[1] = PIONEER_TRANSFER_SIZE;
2641: cdb->PNR_READ_TOC.Type = PIONEER_READ_TRACK_INFO;
2642: srb.TimeOutValue = AUDIO_TIMEOUT;
2643: status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
2644: &srb,
2645: Toc,
2646: PIONEER_TRANSFER_SIZE,
2647: FALSE
2648: );
2649:
2650: if (!NT_SUCCESS(status)) {
2651:
2652: CdDump(( 1,
2653: "CdAudioPioneerDeviceControl: ReadTOC, Track #%d, failed (0x%lx)\n",
2654: i+cdaudioDataOut->FirstTrack,
2655: status ));
2656: ExFreePool( Toc );
2657: goto SetStatusAndReturn;
2658:
2659: }
2660:
2661: cdaudioDataOut->TrackData[i].Reserved = 0;
2662: cdaudioDataOut->TrackData[i].Control = Toc[0];
2663: cdaudioDataOut->TrackData[i].TrackNumber =
2664: (i + cdaudioDataOut->FirstTrack);
2665: cdaudioDataOut->TrackData[i].Reserved1 = 0;
2666: cdaudioDataOut->TrackData[i].Address[0]=0;
2667: cdaudioDataOut->TrackData[i].Address[1]=BCD_TO_DEC(Toc[1]);
2668: cdaudioDataOut->TrackData[i].Address[2]=BCD_TO_DEC(Toc[2]);
2669: cdaudioDataOut->TrackData[i].Address[3]=BCD_TO_DEC(Toc[3]);
2670:
2671: }
2672:
2673: //
2674: // Get info for lead out track
2675: //
2676:
2677: RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
2678: cdb->PNR_READ_TOC.OperationCode = PIONEER_READ_TOC_CODE;
2679: cdb->PNR_READ_TOC.AssignedLength[1] = PIONEER_TRANSFER_SIZE;
2680: cdb->PNR_READ_TOC.Type = PIONEER_READ_LEAD_OUT_INFO;
2681: srb.TimeOutValue = AUDIO_TIMEOUT;
2682: status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
2683: &srb,
2684: Toc,
2685: PIONEER_TRANSFER_SIZE,
2686: FALSE
2687: );
2688:
2689: if (!NT_SUCCESS(status)) {
2690:
2691: CdDump(( 1,
2692: "CdAudioPioneerDeviceControl: ReadTOC, read LeadOutTrack failed (0x%lx)\n",
2693: status ));
2694: ExFreePool( Toc );
2695: goto SetStatusAndReturn;
2696:
2697: }
2698:
2699: cdaudioDataOut->TrackData[i].Reserved = 0;
2700: cdaudioDataOut->TrackData[i].Control = 0x10;
2701: cdaudioDataOut->TrackData[i].TrackNumber = 0xaa;
2702: cdaudioDataOut->TrackData[i].Reserved1 = 0;
2703: cdaudioDataOut->TrackData[i].Address[0] = 0;
2704: cdaudioDataOut->TrackData[i].Address[1] = BCD_TO_DEC(Toc[0]);
2705: cdaudioDataOut->TrackData[i].Address[2] = BCD_TO_DEC(Toc[1]);
2706: cdaudioDataOut->TrackData[i].Address[3] = BCD_TO_DEC(Toc[2]);
2707:
2708: //
2709: // Set size of information transfered to
2710: // max size possible for CDROM Table of Contents
2711: //
2712:
2713: Irp->IoStatus.Information = CDROM_TOC_SIZE;
2714: cdaudioDataOut->Length[0] = CDROM_TOC_SIZE >> 8;
2715: cdaudioDataOut->Length[1] = CDROM_TOC_SIZE & 0xFF;
2716: break;
2717:
2718: case IOCTL_CDROM_STOP_AUDIO:
2719:
2720: CdDump(( 3,
2721: "CdAudioPioneerDeviceControl: IOCTL_CDROM_STOP_AUDIO received.\n"
2722: ));
2723:
2724:
2725: deviceExtension->PlayActive = FALSE;
2726:
2727: //
2728: // Same as scsi-2 spec, so just send to default driver
2729: //
2730:
2731: return CdAudioSendToNextDriver( DeviceObject, Irp );
2732: break;
2733:
2734: case IOCTL_CDROM_PLAY_AUDIO_MSF:
2735: {
2736:
2737: PCDROM_PLAY_AUDIO_MSF inputBuffer =
2738: Irp->AssociatedIrp.SystemBuffer;
2739:
2740: CdDump(( 3,
2741: "CdAudioPioneerDeviceControl: IOCTL_CDROM_PLAY_AUDIO_MSF received.\n"
2742: ));
2743:
2744:
2745: //
2746: // First, set play END point for the play operation
2747: //
2748:
2749: retry = 5;
2750: do {
2751:
2752: srb.CdbLength = 10;
2753: srb.TimeOutValue = AUDIO_TIMEOUT;
2754: cdb->PNR_SEEK_AUDIO.OperationCode = PIONEER_AUDIO_TRACK_SEARCH_CODE;
2755: cdb->PNR_SEEK_AUDIO.Minute = DEC_TO_BCD(inputBuffer->StartingM);
2756: cdb->PNR_SEEK_AUDIO.Second = DEC_TO_BCD(inputBuffer->StartingS);
2757: cdb->PNR_SEEK_AUDIO.Frame = DEC_TO_BCD(inputBuffer->StartingF);
2758: cdb->PNR_SEEK_AUDIO.Type = PIONEER_TYPE_ATIME;
2759: status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
2760: &srb,
2761: NULL,
2762: 0,
2763: FALSE
2764: );
2765:
2766: } while( !NT_SUCCESS(status) && ((retry--)>0) );
2767:
2768: if (NT_SUCCESS(status)) {
2769:
2770: //
2771: // Now, set play start position and start playing.
2772: //
2773:
2774: RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
2775: retry = 5;
2776: do {
2777: srb.CdbLength = 10;
2778: srb.TimeOutValue = AUDIO_TIMEOUT;
2779: cdb->PNR_PLAY_AUDIO.OperationCode = PIONEER_PLAY_AUDIO_CODE;
2780: cdb->PNR_PLAY_AUDIO.StopAddr = 1;
2781: cdb->PNR_PLAY_AUDIO.Minute = DEC_TO_BCD(inputBuffer->EndingM);
2782: cdb->PNR_PLAY_AUDIO.Second = DEC_TO_BCD(inputBuffer->EndingS);
2783: cdb->PNR_PLAY_AUDIO.Frame = DEC_TO_BCD(inputBuffer->EndingF);
2784: cdb->PNR_PLAY_AUDIO.Type = PIONEER_TYPE_ATIME;
2785: status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
2786: &srb,
2787: NULL,
2788: 0,
2789: FALSE
2790: );
2791: } while( !NT_SUCCESS(status) && ((retry--)>0) );
2792:
2793: if (NT_SUCCESS(status)) {
2794:
2795: //
2796: // Indicate the play actition is active.
2797: //
2798:
2799: deviceExtension->PlayActive = TRUE;
2800:
2801:
2802: }
2803:
2804: #if DBG
2805: if (!NT_SUCCESS(status)) {
2806: CdDump(( 1,
2807: "CdAudioPioneerDeviceControl: PLAY_AUDIO_MSF(stop) failed 0x%lx\n",
2808: status
2809: ));
2810:
2811: CdDump(( 3,
2812: "CdAudioPioneerDeviceControl: cdb = 0x%lx, srb = 0x%lx\n",
2813: cdb, &srb
2814: ));
2815:
2816: if (CdAudioDebug>2)
2817: DbgBreakPoint();
2818: }
2819: #endif
2820: }
2821: #if DBG
2822: else {
2823:
2824: CdDump(( 1,
2825: "CdAudioPioneerDeviceControl: PLAY_AUDIO_MSF(start) failed 0x%lx\n",
2826: status
2827: ));
2828: CdDump(( 3,
2829: "CdAudioPioneerDeviceControl: cdb = 0x%lx, srb = 0x%lx\n",
2830: cdb, &srb
2831: ));
2832:
2833: if (CdAudioDebug>2)
2834: DbgBreakPoint();
2835:
2836:
2837: }
2838: #endif
2839: }
2840: break;
2841:
2842: case IOCTL_CDROM_SEEK_AUDIO_MSF:
2843: {
2844:
2845: PCDROM_SEEK_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
2846:
2847: CdDump(( 1,
2848: "CdAudioPioneerDeviceControl: IOCTL_CDROM_SEEK_AUDIO_MSF received.\n"
2849: ));
2850:
2851:
2852: retry = 5;
2853: do {
2854:
2855: //
2856: // seek to MSF and enter pause (still) mode.
2857: //
2858:
2859: srb.CdbLength = 10;
2860: srb.TimeOutValue = AUDIO_TIMEOUT;
2861: cdb->PNR_SEEK_AUDIO.OperationCode = PIONEER_AUDIO_TRACK_SEARCH_CODE;
2862: cdb->PNR_SEEK_AUDIO.Minute = DEC_TO_BCD(inputBuffer->M);
2863: cdb->PNR_SEEK_AUDIO.Second = DEC_TO_BCD(inputBuffer->S);
2864: cdb->PNR_SEEK_AUDIO.Frame = DEC_TO_BCD(inputBuffer->F);
2865: cdb->PNR_SEEK_AUDIO.Type = PIONEER_TYPE_ATIME;
2866: CdDump(( 3,
2867: "CdAudioPioneerDeviceControl: Seek to MSF %d:%d:%d, BCD(%x:%x:%x)\n",
2868: inputBuffer->M,
2869: inputBuffer->S,
2870: inputBuffer->F,
2871: cdb->PNR_SEEK_AUDIO.Minute,
2872: cdb->PNR_SEEK_AUDIO.Second,
2873: cdb->PNR_SEEK_AUDIO.Frame
2874: ));
2875: CdDump(( 3,
2876: "CdAudioPioneerDeviceControl: Seek to MSF, cdb is 0x%x, srb is 0x%x\n",
2877: cdb,
2878: &srb
2879: ));
2880: #if DBG
2881: if (CdAudioDebug>2) {
2882:
2883: DbgBreakPoint();
2884:
2885: }
2886: #endif
2887: status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
2888: &srb,
2889: NULL,
2890: 0,
2891: FALSE
2892: );
2893:
2894: } while( !NT_SUCCESS(status) && ((retry--)>0) );
2895: #if DBG
2896: if (!NT_SUCCESS(status)) {
2897:
2898: CdDump(( 1, "CdAudioPioneerDeviceControl: Seek to MSF failed 0x%lx\n",
2899: status
2900: ));
2901:
2902: if (CdAudioDebug>5) {
2903:
2904: DbgBreakPoint();
2905:
2906: }
2907: }
2908: #endif
2909: }
2910: break;
2911:
2912: case IOCTL_CDROM_PAUSE_AUDIO:
2913:
2914: CdDump(( 3,
2915: "CdAudioPioneerDeviceControl: IOCTL_CDROM_PAUSE_AUDIO received.\n"
2916: ));
2917:
2918: deviceExtension->PlayActive = FALSE;
2919:
2920: //
2921: // Enter pause (still ) mode
2922: //
2923:
2924: srb.CdbLength = 10;
2925: srb.TimeOutValue = AUDIO_TIMEOUT;
2926: cdb->PNR_PAUSE_AUDIO.OperationCode = PIONEER_PAUSE_CODE;
2927: cdb->PNR_PAUSE_AUDIO.Pause = 1;
2928: status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
2929: &srb,
2930: NULL,
2931: 0,
2932: FALSE
2933: );
2934: break;
2935:
2936: case IOCTL_CDROM_RESUME_AUDIO:
2937:
2938: CdDump(( 3,
2939: "CdAudioPioneerDeviceControl: IOCTL_CDROM_RESUME_AUDIO received.\n"
2940: ));
2941:
2942:
2943: //
2944: // Resume Play
2945: //
2946:
2947: srb.CdbLength = 10;
2948: srb.TimeOutValue = AUDIO_TIMEOUT;
2949: cdb->PNR_PAUSE_AUDIO.OperationCode = PIONEER_PAUSE_CODE;
2950: status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
2951: &srb,
2952: NULL,
2953: 0,
2954: FALSE
2955: );
2956: break;
2957:
2958: case IOCTL_CDROM_READ_Q_CHANNEL:
2959: {
2960: PSUB_Q_CURRENT_POSITION userPtr =
2961: Irp->AssociatedIrp.SystemBuffer;
2962: PUCHAR SubQPtr =
2963: ExAllocatePool( NonPagedPoolCacheAligned,
2964: PIONEER_Q_CHANNEL_TRANSFER_SIZE
2965: );
2966:
2967: CdDump(( 5,
2968: "CdAudioPioneerDeviceControl: IOCTL_CDROM_READ_Q_CHANNEL received.\n"
2969: ));
2970:
2971: if (SubQPtr==NULL) {
2972:
2973: CdDump(( 1,
2974: "CdAudioPioneerDeviceControl: READ_Q_CHANNEL, SubQPtr==NULL!\n"
2975: ));
2976:
2977: RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
2978: status = STATUS_INSUFFICIENT_RESOURCES;
2979: goto SetStatusAndReturn;
2980:
2981: }
2982:
2983: if ( ((PCDROM_SUB_Q_DATA_FORMAT)userPtr)->Format!=
2984: IOCTL_CDROM_CURRENT_POSITION) {
2985:
2986: CdDump(( 1,
2987: "CdAudioPioneerDeviceControl: READ_Q_CHANNEL, Illegal Format (%d)!\n",
2988: ((PCDROM_SUB_Q_DATA_FORMAT)userPtr)->Format
2989: ));
2990:
2991: ExFreePool( SubQPtr );
2992: RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
2993: status = STATUS_INVALID_DEVICE_REQUEST;
2994: goto SetStatusAndReturn;
2995: }
2996:
2997: //
2998: // Read audio play status
2999: //
3000:
3001: retry = 5;
3002: do {
3003: srb.CdbLength = 10;
3004: srb.TimeOutValue = AUDIO_TIMEOUT;
3005: cdb->PNR_AUDIO_STATUS.OperationCode = PIONEER_AUDIO_STATUS_CODE;
3006: cdb->PNR_AUDIO_STATUS.AssignedLength = PIONEER_AUDIO_STATUS_TRANSFER_SIZE; // Transfer Length
3007: status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
3008: &srb,
3009: SubQPtr,
3010: 6,
3011: FALSE
3012: );
3013: } while( !NT_SUCCESS(status) && ((retry--)>0) && status != STATUS_DEVICE_NOT_READY);
3014: if (NT_SUCCESS(status)) {
3015:
3016: userPtr->Header.Reserved = 0;
3017: if (SubQPtr[0]==0x00)
3018: userPtr->Header.AudioStatus = AUDIO_STATUS_IN_PROGRESS;
3019: else if (SubQPtr[0]==0x01) {
3020: deviceExtension->PlayActive = FALSE;
3021: userPtr->Header.AudioStatus = AUDIO_STATUS_PAUSED;
3022: } else if (SubQPtr[0]==0x02) {
3023: deviceExtension->PlayActive = FALSE;
3024: userPtr->Header.AudioStatus = AUDIO_STATUS_PAUSED;
3025: } else if (SubQPtr[0]==0x03) {
3026:
3027: userPtr->Header.AudioStatus = AUDIO_STATUS_PLAY_COMPLETE;
3028: deviceExtension->PlayActive = FALSE;
3029:
3030: } else {
3031: deviceExtension->PlayActive = FALSE;
3032:
3033: }
3034:
3035: } else {
3036:
3037: CdDump(( 1,
3038: "CdAudioPioneerDeviceControl: read status code (Q) failed (0x%lx)\n",
3039: status
3040: ));
3041:
3042: RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
3043: ExFreePool( SubQPtr );
3044: goto SetStatusAndReturn;
3045:
3046: }
3047:
3048: //
3049: // Set up to read current position from Q Channel
3050: //
3051:
3052: RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
3053: retry = 5;
3054: do {
3055: srb.CdbLength = 10;
3056: srb.TimeOutValue = AUDIO_TIMEOUT;
3057: cdb->PNR_READ_Q_CHANNEL.OperationCode = PIONEER_READ_SUB_Q_CHANNEL_CODE;
3058: cdb->PNR_READ_Q_CHANNEL.AssignedLength = PIONEER_Q_CHANNEL_TRANSFER_SIZE; // Transfer Length
3059: status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
3060: &srb,
3061: SubQPtr,
3062: PIONEER_Q_CHANNEL_TRANSFER_SIZE,
3063: FALSE
3064: );
3065:
3066: } while( !NT_SUCCESS(status) && ((retry--)>0) );
3067:
3068: if (NT_SUCCESS(status)) {
3069:
3070: userPtr->Header.DataLength[0] = 0;
3071: userPtr->Header.DataLength[0] = 12;
3072:
3073: userPtr->FormatCode = 0x01;
3074: userPtr->Control = SubQPtr[0] & 0x0F;
3075: userPtr->ADR = 0;
3076: userPtr->TrackNumber = BCD_TO_DEC(SubQPtr[1]);
3077: userPtr->IndexNumber = BCD_TO_DEC(SubQPtr[2]);
3078: userPtr->AbsoluteAddress[0] = 0;
3079: userPtr->AbsoluteAddress[1] = BCD_TO_DEC((SubQPtr[6]));
3080: userPtr->AbsoluteAddress[2] = BCD_TO_DEC((SubQPtr[7]));
3081: userPtr->AbsoluteAddress[3] = BCD_TO_DEC((SubQPtr[8]));
3082: userPtr->TrackRelativeAddress[0] = 0;
3083: userPtr->TrackRelativeAddress[1] = BCD_TO_DEC((SubQPtr[3]));
3084: userPtr->TrackRelativeAddress[2] = BCD_TO_DEC((SubQPtr[4]));
3085: userPtr->TrackRelativeAddress[3] = BCD_TO_DEC((SubQPtr[5]));
3086: Irp->IoStatus.Information = 16;
3087:
3088: } else {
3089:
3090: RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
3091: CdDump(( 1,
3092: "CdAudioPioneerDeviceControl: read q channel failed (0x%lx)\n",
3093: status
3094: ));
3095:
3096:
3097: }
3098:
3099: ExFreePool( SubQPtr );
3100: }
3101: break;
3102:
3103: case IOCTL_CDROM_EJECT_MEDIA:
3104:
3105: CdDump(( 3,
3106: "CdAudioPioneerDeviceControl: IOCTL_CDROM_EJECT_MEDIA received.\n"
3107: ));
3108:
3109:
3110: deviceExtension->PlayActive = FALSE;
3111:
3112: //
3113: // Build cdb to eject cartridge
3114: //
3115:
3116: srb.CdbLength = 10;
3117: srb.TimeOutValue = AUDIO_TIMEOUT;
3118: cdb->PNR_EJECT.OperationCode = PIONEER_EJECT_CODE;
3119: status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
3120: &srb,
3121: NULL,
3122: 0,
3123: FALSE
3124: );
3125: break;
3126:
3127: case IOCTL_CDROM_GET_CONTROL:
3128: case IOCTL_CDROM_GET_VOLUME:
3129: case IOCTL_CDROM_SET_VOLUME:
3130:
3131: CdDump(( 3, "CdAudioPioneerDeviceControl: Not Supported yet.\n" ));
3132: status = STATUS_INVALID_DEVICE_REQUEST;
3133: break;
3134:
3135: case IOCTL_CDROM_CHECK_VERIFY:
3136:
3137: //
3138: // Update the play active flag.
3139: //
3140:
3141: CdAudioIsPlayActive(DeviceObject);
3142:
3143: default:
3144:
3145: CdDump((5,"CdAudioPioneerDeviceControl: Unsupported device IOCTL\n"));
3146: return CdAudioSendToNextDriver( DeviceObject, Irp );
3147: break;
3148:
3149:
3150:
3151: } // end switch( IOCTL )
3152:
3153: SetStatusAndReturn:
3154: //
3155: // set status code and return
3156: //
3157:
3158: if (status == STATUS_VERIFY_REQUIRED) {
3159:
3160: //
3161: // If the status is verified required and the this request
3162: // should bypass verify required then retry the request.
3163: //
3164:
3165: if (currentIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME) {
3166:
3167: status = STATUS_IO_DEVICE_ERROR;
3168: goto PioneerRestart;
3169:
3170: }
3171:
3172:
3173: IoSetHardErrorOrVerifyDevice( Irp,
3174: deviceExtension->TargetDeviceObject
3175: );
3176:
3177: Irp->IoStatus.Information = 0;
3178: }
3179:
3180: Irp->IoStatus.Status = status;
3181: IoCompleteRequest(Irp, IO_NO_INCREMENT);
3182: return status;
3183:
3184: }
3185:
3186:
3187: NTSTATUS
3188: CdAudioDenonDeviceControl(
3189: PDEVICE_OBJECT DeviceObject,
3190: PIRP Irp
3191: )
3192:
3193: /*++
3194:
3195: Routine Description:
3196:
3197: This routine is called by CdAudioDeviceControl to handle
3198: audio IOCTLs sent to DENON DRD-253 cdrom drive.
3199:
3200: Arguments:
3201:
3202: DeviceObject
3203: Irp
3204:
3205: Return Value:
3206:
3207: NTSTATUS
3208:
3209: --*/
3210:
3211: {
3212: PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
3213: PCD_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
3214: PCDROM_TOC cdaudioDataOut = Irp->AssociatedIrp.SystemBuffer;
3215: SCSI_REQUEST_BLOCK srb;
3216: PCDB cdb = (PCDB)srb.Cdb;
3217: NTSTATUS status;
3218: ULONG i,bytesTransfered;
3219: PUCHAR Toc;
3220:
3221: DenonRestart:
3222:
3223: //
3224: // Clear out cdb
3225: //
3226:
3227: RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
3228:
3229: //
3230: // What IOCTL do we need to execute?
3231: //
3232:
3233: switch (currentIrpStack->Parameters.DeviceIoControl.IoControlCode) {
3234:
3235: case IOCTL_CDROM_READ_TOC:
3236: CdDump(( 3,
3237: "CdAudioDenonDeviceControl: IOCTL_CDROM_READ_TOC received.\n"
3238: ));
3239:
3240: //
3241: // If the cd is playing music then reject this request.
3242: //
3243:
3244: if (CdAudioIsPlayActive(DeviceObject)) {
3245: status = STATUS_DEVICE_BUSY;
3246: break;
3247: }
3248:
3249:
3250: //
3251: // Allocate storage to hold TOC from disc
3252: //
3253:
3254: Toc = (PUCHAR)ExAllocatePool( NonPagedPoolCacheAligned,
3255: CDROM_TOC_SIZE
3256: );
3257:
3258: if (Toc==NULL) {
3259:
3260: status = STATUS_INSUFFICIENT_RESOURCES;
3261: goto SetStatusAndReturn;
3262:
3263: }
3264:
3265: //
3266: // Set up defaults
3267: //
3268:
3269: RtlZeroMemory( Toc, CDROM_TOC_SIZE );
3270:
3271: //
3272: // Fill in cdb for this operation
3273: //
3274:
3275: cdb->CDB6GENERIC.OperationCode = DENON_READ_TOC_CODE;
3276: srb.TimeOutValue = AUDIO_TIMEOUT;
3277: srb.CdbLength = 6;
3278: status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
3279: &srb,
3280: Toc,
3281: CDROM_TOC_SIZE,
3282: FALSE
3283: );
3284:
3285: if (!NT_SUCCESS(status) && (status!=STATUS_DATA_OVERRUN)) {
3286:
3287: CdDump(( 1,
3288: "CdAudioDenonDeviceControl: READ_TOC error (0x%08lX)\n",
3289: status ));
3290:
3291: if (SRB_STATUS(srb.SrbStatus)!=SRB_STATUS_DATA_OVERRUN) {
3292:
3293: CdDump(( 1, "CdAudioDenonDeviceControl: SRB ERROR (0x%lX)\n",
3294: srb.SrbStatus ));
3295: ExFreePool( Toc );
3296: goto SetStatusAndReturn;
3297: }
3298:
3299: }
3300:
3301: //
3302: // Set the status to success since data under runs are not an error.
3303: //
3304:
3305: status = STATUS_SUCCESS;
3306:
3307: //
3308: // Since the Denon manual didn't define the format of
3309: // the buffer returned from this call, here it is:
3310: //
3311: // Byte Data (4 byte "packets")
3312: //
3313: // 00 a0 FT 00 00 (FT == BCD of first track number on disc)
3314: // 04 a1 LT 00 00 (LT == BCD of last track number on disc)
3315: // 08 a2 MM SS FF (MM SS FF == BCD of total disc time, in MSF)
3316: //
3317: // For each track on disc:
3318: //
3319: // 0C XX MM SS FF (MM SS FF == BCD MSF start position of track XX)
3320: // 0C+4 XX+1 MM SS FF (MM SS FF == BCD MSF start position of track XX+1)
3321: //
3322: // etc., for each track
3323: //
3324:
3325: //
3326: // Translate data into our format
3327: //
3328:
3329: bytesTransfered =
3330: currentIrpStack->Parameters.Read.Length > srb.DataTransferLength ?
3331: srb.DataTransferLength : currentIrpStack->Parameters.Read.Length;
3332: Irp->IoStatus.Information = bytesTransfered;
3333: cdaudioDataOut->Length[0] = bytesTransfered >> 8;
3334: cdaudioDataOut->Length[1] = (bytesTransfered & 0xFF);
3335: cdaudioDataOut->FirstTrack = BCD_TO_DEC(Toc[1]);
3336: cdaudioDataOut->LastTrack = BCD_TO_DEC(Toc[5]);
3337:
3338: for( i=0;
3339: i<=( (ULONG)cdaudioDataOut->LastTrack -
3340: (ULONG)cdaudioDataOut->FirstTrack );
3341: i++
3342: ) {
3343:
3344: //
3345: // Grab Information for each track
3346: //
3347:
3348: cdaudioDataOut->TrackData[i].Reserved = 0;
3349: cdaudioDataOut->TrackData[i].Control = Toc[(i*4)+12];
3350: cdaudioDataOut->TrackData[i].TrackNumber =
3351: (i + cdaudioDataOut->FirstTrack);
3352:
3353: cdaudioDataOut->TrackData[i].Reserved1 = 0;
3354: cdaudioDataOut->TrackData[i].Address[0] = 0;
3355: cdaudioDataOut->TrackData[i].Address[1] =
3356: BCD_TO_DEC((Toc[(i*4)+13]));
3357: cdaudioDataOut->TrackData[i].Address[2] =
3358: BCD_TO_DEC((Toc[(i*4)+14]));
3359: cdaudioDataOut->TrackData[i].Address[3] =
3360: BCD_TO_DEC((Toc[(i*4)+15]));
3361:
3362: }
3363:
3364: //
3365: // Fake "lead out track" info
3366: //
3367:
3368: cdaudioDataOut->TrackData[i].Reserved = 0;
3369: cdaudioDataOut->TrackData[i].Control = 0;
3370: cdaudioDataOut->TrackData[i].TrackNumber = 0xaa;
3371: cdaudioDataOut->TrackData[i].Reserved1 = 0;
3372: cdaudioDataOut->TrackData[i].Address[0] = 0;
3373: cdaudioDataOut->TrackData[i].Address[1] = BCD_TO_DEC(Toc[9]);
3374: cdaudioDataOut->TrackData[i].Address[2] = BCD_TO_DEC(Toc[10]);
3375: cdaudioDataOut->TrackData[i].Address[3] = BCD_TO_DEC(Toc[11]);
3376:
3377: //
3378: // Clear out deviceExtension data
3379: //
3380:
3381: deviceExtension->Paused = CDAUDIO_NOT_PAUSED;
3382: deviceExtension->PausedM = 0;
3383: deviceExtension->PausedS = 0;
3384: deviceExtension->PausedF = 0;
3385: deviceExtension->LastEndM = 0;
3386: deviceExtension->LastEndS = 0;
3387: deviceExtension->LastEndF = 0;
3388:
3389: //
3390: // Free storage now that we've stored it elsewhere
3391: //
3392:
3393: ExFreePool( Toc );
3394: break;
3395:
3396: case IOCTL_CDROM_PLAY_AUDIO_MSF:
3397: case IOCTL_CDROM_STOP_AUDIO:
3398: {
3399:
3400: PCDROM_PLAY_AUDIO_MSF inputBuffer =
3401: Irp->AssociatedIrp.SystemBuffer;
3402:
3403: deviceExtension->PlayActive = FALSE;
3404:
3405: srb.CdbLength = 6;
3406: srb.TimeOutValue = AUDIO_TIMEOUT;
3407: cdb->CDB6GENERIC.OperationCode = DENON_STOP_AUDIO_CODE;
3408: status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
3409: &srb,
3410: NULL,
3411: 0,
3412: FALSE
3413: );
3414:
3415: if (NT_SUCCESS(status)) {
3416:
3417: deviceExtension->Paused = CDAUDIO_NOT_PAUSED;
3418: deviceExtension->PausedM = 0;
3419: deviceExtension->PausedS = 0;
3420: deviceExtension->PausedF = 0;
3421: deviceExtension->LastEndM = 0;
3422: deviceExtension->LastEndS = 0;
3423: deviceExtension->LastEndF = 0;
3424:
3425: } else {
3426:
3427: CdDump(( 3,
3428: "CdAudioDenonDeviceControl: STOP failed (0x%08lX)\n",
3429: status ));
3430:
3431: }
3432:
3433:
3434: if (currentIrpStack->Parameters.DeviceIoControl.IoControlCode ==
3435: IOCTL_CDROM_STOP_AUDIO
3436: ) {
3437:
3438: CdDump(( 3,
3439: "CdAudioDenonDeviceControl: IOCTL_CDROM_STOP_AUDIO received.\n"
3440: ));
3441:
3442: goto SetStatusAndReturn;
3443:
3444: }
3445:
3446: CdDump(( 3,
3447: "CdAudioDenonDeviceControl: IOCTL_CDROM_PLAY_AUDIO_MSF received.\n"
3448: ));
3449:
3450: //
3451: // Fill in cdb for this operation
3452: //
3453:
3454: srb.CdbLength = 10;
3455: srb.TimeOutValue = AUDIO_TIMEOUT;
3456: cdb->CDB10.OperationCode = DENON_PLAY_AUDIO_EXTENDED_CODE;
3457: cdb->CDB10.LogicalBlockByte0 = DEC_TO_BCD(inputBuffer->StartingM);
3458: cdb->CDB10.LogicalBlockByte1 = DEC_TO_BCD(inputBuffer->StartingS);
3459: cdb->CDB10.LogicalBlockByte2 = DEC_TO_BCD(inputBuffer->StartingF);
3460: cdb->CDB10.LogicalBlockByte3 = DEC_TO_BCD(inputBuffer->EndingM);
3461: cdb->CDB10.Reserved2 = DEC_TO_BCD(inputBuffer->EndingS);
3462: cdb->CDB10.TransferBlocksMsb = DEC_TO_BCD(inputBuffer->EndingF);
3463: status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
3464: &srb,
3465: NULL,
3466: 0,
3467: FALSE
3468: );
3469:
3470: if (NT_SUCCESS(status)) {
3471:
3472: //
3473: // Indicate the play actition is active.
3474: //
3475:
3476: deviceExtension->PlayActive = TRUE;
3477: deviceExtension->Paused = CDAUDIO_NOT_PAUSED;
3478:
3479: //
3480: // Set last play ending address for next pause command
3481: //
3482:
3483: deviceExtension->LastEndM = DEC_TO_BCD(inputBuffer->EndingM);
3484: deviceExtension->LastEndS = DEC_TO_BCD(inputBuffer->EndingS);
3485: deviceExtension->LastEndF = DEC_TO_BCD(inputBuffer->EndingF);
3486: CdDump(( 3,
3487: "CdAudioDenonDeviceControl: PLAY ==> BcdLastEnd set to (%x %x %x)\n",
3488: deviceExtension->LastEndM,
3489: deviceExtension->LastEndS,
3490: deviceExtension->LastEndF ));
3491:
3492: } else {
3493:
3494: CdDump(( 3,
3495: "CdAudioDenonDeviceControl: PLAY failed (0x%08lX)\n",
3496: status ));
3497:
3498: //
3499: // The Denon drive returns STATUS_INVALD_DEVICE_REQUEST
3500: // when we ask to play an invalid address, so we need
3501: // to map to STATUS_NONEXISTENT_SECTOR in order to be
3502: // consistent with the other drives.
3503: //
3504:
3505: if (status==STATUS_INVALID_DEVICE_REQUEST) {
3506:
3507: status = STATUS_NONEXISTENT_SECTOR;
3508: }
3509:
3510: }
3511: }
3512: break;
3513:
3514: case IOCTL_CDROM_SEEK_AUDIO_MSF:
3515: {
3516:
3517: PCDROM_SEEK_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
3518:
3519: CdDump(( 3,
3520: "CdAudioDenonDeviceControl: IOCTL_CDROM_SEEK_AUDIO_MSF received.\n"
3521: ));
3522:
3523: //
3524: // Fill in cdb for this operation
3525: //
3526:
3527: srb.CdbLength = 10;
3528: srb.TimeOutValue = AUDIO_TIMEOUT;
3529: cdb->CDB10.OperationCode = DENON_PLAY_AUDIO_EXTENDED_CODE;
3530: cdb->CDB10.LogicalBlockByte0 = DEC_TO_BCD(inputBuffer->M);
3531: cdb->CDB10.LogicalBlockByte1 = DEC_TO_BCD(inputBuffer->S);
3532: cdb->CDB10.LogicalBlockByte2 = DEC_TO_BCD(inputBuffer->F);
3533: cdb->CDB10.LogicalBlockByte3 = DEC_TO_BCD(inputBuffer->M);
3534: cdb->CDB10.Reserved2 = DEC_TO_BCD(inputBuffer->S);
3535: cdb->CDB10.TransferBlocksMsb = DEC_TO_BCD(inputBuffer->F);
3536: status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
3537: &srb,
3538: NULL,
3539: 0,
3540: FALSE
3541: );
3542:
3543: if (NT_SUCCESS(status)) {
3544:
3545: deviceExtension->Paused = CDAUDIO_PAUSED;
3546: deviceExtension->PausedM = DEC_TO_BCD(inputBuffer->M);
3547: deviceExtension->PausedS = DEC_TO_BCD(inputBuffer->S);
3548: deviceExtension->PausedF = DEC_TO_BCD(inputBuffer->F);
3549: deviceExtension->LastEndM = DEC_TO_BCD(inputBuffer->M);
3550: deviceExtension->LastEndS = DEC_TO_BCD(inputBuffer->S);
3551: deviceExtension->LastEndF = DEC_TO_BCD(inputBuffer->F);
3552: CdDump(( 3,
3553: "CdAudioDenonDeviceControl: SEEK, Paused (%x %x %x) LastEnd (%x %x %x)\n",
3554: deviceExtension->PausedM,
3555: deviceExtension->PausedS,
3556: deviceExtension->PausedF,
3557: deviceExtension->LastEndM,
3558: deviceExtension->LastEndS,
3559: deviceExtension->LastEndF ));
3560:
3561: } else {
3562:
3563: CdDump(( 3,
3564: "CdAudioDenonDeviceControl: SEEK failed (0x%08lX)\n",
3565: status ));
3566:
3567: //
3568: // The Denon drive returns STATUS_INVALD_DEVICE_REQUEST
3569: // when we ask to play an invalid address, so we need
3570: // to map to STATUS_NONEXISTENT_SECTOR in order to be
3571: // consistent with the other drives.
3572: //
3573:
3574: if (status==STATUS_INVALID_DEVICE_REQUEST) {
3575:
3576: status = STATUS_NONEXISTENT_SECTOR;
3577: }
3578:
3579: }
3580: }
3581: break;
3582:
3583: case IOCTL_CDROM_PAUSE_AUDIO:
3584: {
3585: PUCHAR SubQPtr =
3586: ExAllocatePool( NonPagedPoolCacheAligned,
3587: 10
3588: );
3589:
3590: CdDump(( 3,
3591: "CdAudioDenonDeviceControl: IOCTL_CDROM_PAUSE_AUDIO received.\n"
3592: ));
3593:
3594: deviceExtension->PlayActive = FALSE;
3595:
3596: if (SubQPtr==NULL) {
3597:
3598: status = STATUS_INSUFFICIENT_RESOURCES;
3599: goto SetStatusAndReturn;
3600:
3601: }
3602:
3603: //
3604: // Enter pause (still ) mode
3605: //
3606:
3607: if (deviceExtension->Paused==CDAUDIO_PAUSED) {
3608:
3609: CdDump(( 3,
3610: "CdAudioDenonDeviceControl: PAUSE: Already Paused!\n"
3611: ));
3612:
3613: ExFreePool( SubQPtr );
3614: status = STATUS_SUCCESS;
3615: goto SetStatusAndReturn;
3616:
3617: }
3618:
3619: //
3620: // Since the Denon doesn't have a pause mode,
3621: // we'll just record the current position and
3622: // stop the drive.
3623: //
3624:
3625: srb.CdbLength = 6;
3626: srb.TimeOutValue = AUDIO_TIMEOUT;
3627: cdb->CDB6GENERIC.OperationCode = DENON_READ_SUB_Q_CHANNEL_CODE;
3628: cdb->CDB6GENERIC.CommandUniqueBytes[2] = 10; // Transfer Length
3629: status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
3630: &srb,
3631: SubQPtr,
3632: 10,
3633: FALSE
3634: );
3635: if (!NT_SUCCESS(status)) {
3636:
3637: CdDump(( 1,
3638: "CdAudioDenonDeviceControl: Pause, Read Q Channel failed (0x%lx)\n",
3639: status ));
3640: ExFreePool( SubQPtr );
3641: goto SetStatusAndReturn;
3642: }
3643:
3644: deviceExtension->PausedM = SubQPtr[7];
3645: deviceExtension->PausedS = SubQPtr[8];
3646: deviceExtension->PausedF = SubQPtr[9];
3647:
3648: RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
3649: srb.CdbLength = 6;
3650: srb.TimeOutValue = AUDIO_TIMEOUT;
3651: cdb->CDB6GENERIC.OperationCode = DENON_STOP_AUDIO_CODE;
3652: status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
3653: &srb,
3654: NULL,
3655: 0,
3656: FALSE
3657: );
3658: if (!NT_SUCCESS(status)) {
3659:
3660: CdDump(( 1,
3661: "CdAudioDenonDeviceControl: PAUSE, StopAudio failed! (0x%08lX)\n",
3662: status ));
3663: ExFreePool( SubQPtr );
3664: goto SetStatusAndReturn;
3665: }
3666:
3667: deviceExtension->Paused = CDAUDIO_PAUSED;
3668: deviceExtension->PausedM = SubQPtr[7];
3669: deviceExtension->PausedS = SubQPtr[8];
3670: deviceExtension->PausedF = SubQPtr[9];
3671:
3672: CdDump((3,
3673: "CdAudioDenonDeviceControl: PAUSE ==> Paused set to (%x %x %x)\n",
3674: deviceExtension->PausedM,
3675: deviceExtension->PausedS,
3676: deviceExtension->PausedF ));
3677:
3678: ExFreePool( SubQPtr );
3679: }
3680: break;
3681:
3682: case IOCTL_CDROM_RESUME_AUDIO:
3683:
3684: //
3685: // Resume cdrom
3686: //
3687:
3688: CdDump(( 3,
3689: "CdAudioDenonDeviceControl: IOCTL_CDROM_RESUME_AUDIO received.\n"
3690: ));
3691:
3692:
3693: //
3694: // Since the Denon doesn't have a resume IOCTL,
3695: // we'll just start playing (if paused) from the
3696: // last recored paused position to the last recorded
3697: // "end of play" position.
3698: //
3699:
3700: if (deviceExtension->Paused==CDAUDIO_NOT_PAUSED) {
3701:
3702: status = STATUS_UNSUCCESSFUL;
3703: goto SetStatusAndReturn;
3704:
3705: }
3706:
3707:
3708:
3709: //
3710: // Fill in cdb for this operation
3711: //
3712:
3713: srb.CdbLength = 10;
3714: srb.TimeOutValue = AUDIO_TIMEOUT;
3715: cdb->CDB10.OperationCode = DENON_PLAY_AUDIO_EXTENDED_CODE;
3716: cdb->CDB10.LogicalBlockByte0 = deviceExtension->PausedM;
3717: cdb->CDB10.LogicalBlockByte1 = deviceExtension->PausedS;
3718: cdb->CDB10.LogicalBlockByte2 = deviceExtension->PausedF;
3719: cdb->CDB10.LogicalBlockByte3 = deviceExtension->LastEndM;
3720: cdb->CDB10.Reserved2 = deviceExtension->LastEndS;
3721: cdb->CDB10.TransferBlocksMsb = deviceExtension->LastEndF;
3722: status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
3723: &srb,
3724: NULL,
3725: 0,
3726: FALSE
3727: );
3728:
3729: if (NT_SUCCESS(status)) {
3730:
3731: deviceExtension->Paused = CDAUDIO_NOT_PAUSED;
3732:
3733: } else {
3734:
3735: CdDump(( 1,
3736: "CdAudioDenonDeviceControl: RESUME (%x %x %x) - (%x %x %x) failed (0x%08lX)\n",
3737: deviceExtension->PausedM,
3738: deviceExtension->PausedS,
3739: deviceExtension->PausedF,
3740: deviceExtension->LastEndM,
3741: deviceExtension->LastEndS,
3742: deviceExtension->LastEndF,
3743: status ));
3744:
3745: }
3746: break;
3747:
3748: case IOCTL_CDROM_READ_Q_CHANNEL:
3749: {
3750: PSUB_Q_CURRENT_POSITION userPtr =
3751: Irp->AssociatedIrp.SystemBuffer;
3752: PUCHAR SubQPtr =
3753: ExAllocatePool( NonPagedPoolCacheAligned,
3754: sizeof(SUB_Q_CHANNEL_DATA)
3755: );
3756:
3757: CdDump(( 5,
3758: "CdAudioDenonDeviceControl: IOCTL_CDROM_READ_Q_CHANNEL received.\n"
3759: ));
3760:
3761: if (SubQPtr==NULL) {
3762:
3763: CdDump(( 1,
3764: "CdAudioDenonDeviceControl: READ_Q_CHANNEL, SubQPtr==NULL!\n"
3765: ));
3766:
3767: RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
3768: status = STATUS_INSUFFICIENT_RESOURCES;
3769: goto SetStatusAndReturn;
3770:
3771: }
3772:
3773: if ( ((PCDROM_SUB_Q_DATA_FORMAT)userPtr)->Format!=
3774: IOCTL_CDROM_CURRENT_POSITION) {
3775:
3776: CdDump(( 1,
3777: "CdAudioDenonDeviceControl: READ_Q_CHANNEL, illegal Format (%d)\n",
3778: ((PCDROM_SUB_Q_DATA_FORMAT)userPtr)->Format
3779: ));
3780:
3781: ExFreePool( SubQPtr );
3782: RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
3783: status = STATUS_UNSUCCESSFUL;
3784: goto SetStatusAndReturn;
3785: }
3786:
3787: //
3788: // Read audio play status
3789: //
3790:
3791: srb.CdbLength = 6;
3792: srb.TimeOutValue = AUDIO_TIMEOUT;
3793: cdb->CDB6GENERIC.OperationCode = DENON_READ_SUB_Q_CHANNEL_CODE;
3794: cdb->CDB6GENERIC.CommandUniqueBytes[2] = 10; // Transfer Length
3795: status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
3796: &srb,
3797: SubQPtr,
3798: 10,
3799: FALSE
3800: );
3801: if (NT_SUCCESS(status)) {
3802:
3803: userPtr->Header.Reserved = 0;
3804:
3805: if (deviceExtension->Paused==CDAUDIO_PAUSED) {
3806:
3807: deviceExtension->PlayActive = FALSE;
3808: userPtr->Header.AudioStatus = AUDIO_STATUS_PAUSED;
3809:
3810: } else {
3811:
3812: if (SubQPtr[0]==0x01)
3813: userPtr->Header.AudioStatus = AUDIO_STATUS_IN_PROGRESS;
3814: else if (SubQPtr[0]==0x00){
3815: userPtr->Header.AudioStatus = AUDIO_STATUS_PLAY_COMPLETE;
3816: deviceExtension->PlayActive = FALSE;
3817:
3818: } else {
3819: deviceExtension->PlayActive = FALSE;
3820: }
3821:
3822: }
3823:
3824: userPtr->Header.DataLength[0] = 0;
3825: userPtr->Header.DataLength[0] = 12;
3826:
3827: userPtr->FormatCode = 0x01;
3828: userPtr->Control = SubQPtr[1];
3829: userPtr->ADR = 0;
3830: userPtr->TrackNumber = BCD_TO_DEC(SubQPtr[2]);
3831: userPtr->IndexNumber = BCD_TO_DEC(SubQPtr[3]);
3832: userPtr->AbsoluteAddress[0] = 0;
3833: userPtr->AbsoluteAddress[1] = BCD_TO_DEC((SubQPtr[7]));
3834: userPtr->AbsoluteAddress[2] = BCD_TO_DEC((SubQPtr[8]));
3835: userPtr->AbsoluteAddress[3] = BCD_TO_DEC((SubQPtr[9]));
3836: userPtr->TrackRelativeAddress[0] = 0;
3837: userPtr->TrackRelativeAddress[1] = BCD_TO_DEC((SubQPtr[4]));
3838: userPtr->TrackRelativeAddress[2] = BCD_TO_DEC((SubQPtr[5]));
3839: userPtr->TrackRelativeAddress[3] = BCD_TO_DEC((SubQPtr[6]));
3840: Irp->IoStatus.Information = 16;
3841:
3842: } else {
3843:
3844: RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
3845: CdDump(( 1,
3846: "CdAudioDenonDeviceControl: READ_Q_CHANNEL failed (0x%08lX)\n",
3847: status
3848: ));
3849:
3850:
3851: }
3852:
3853: ExFreePool( SubQPtr );
3854: }
3855: break;
3856:
3857: case IOCTL_CDROM_EJECT_MEDIA:
3858:
3859: //
3860: // Build cdb to eject cartridge
3861: //
3862:
3863: CdDump(( 3,
3864: "CdAudioDenonDeviceControl: IOCTL_CDROM_EJECT_MEDIA received.\n"
3865: ));
3866:
3867: deviceExtension->PlayActive = FALSE;
3868:
3869: srb.CdbLength = 6;
3870: srb.TimeOutValue = AUDIO_TIMEOUT;
3871: cdb->CDB6GENERIC.OperationCode = DENON_EJECT_CODE;
3872: status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
3873: &srb,
3874: NULL,
3875: 0,
3876: FALSE
3877: );
3878: break;
3879:
3880: case IOCTL_CDROM_GET_CONTROL:
3881: case IOCTL_CDROM_GET_VOLUME:
3882: case IOCTL_CDROM_SET_VOLUME:
3883: CdDump(( 3, "CdAudioDenonDeviceControl: Not Supported yet.\n" ));
3884: status = STATUS_INVALID_DEVICE_REQUEST;
3885: break;
3886:
3887: case IOCTL_CDROM_CHECK_VERIFY:
3888:
3889: //
3890: // Update the play active flag.
3891: //
3892:
3893: CdAudioIsPlayActive(DeviceObject);
3894:
3895: default:
3896:
3897: CdDump((5,"CdAudioDenonDeviceControl: Unsupported device IOCTL\n"));
3898: return CdAudioSendToNextDriver( DeviceObject, Irp );
3899: break;
3900:
3901: } // end switch( IOCTL )
3902:
3903: SetStatusAndReturn:
3904: //
3905: // set status code and return
3906: //
3907:
3908: if (status == STATUS_VERIFY_REQUIRED) {
3909:
3910: //
3911: // If the status is verified required and the this request
3912: // should bypass verify required then retry the request.
3913: //
3914:
3915: if (currentIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME) {
3916:
3917: status = STATUS_IO_DEVICE_ERROR;
3918: goto DenonRestart;
3919:
3920: }
3921:
3922:
3923: IoSetHardErrorOrVerifyDevice( Irp,
3924: deviceExtension->TargetDeviceObject
3925: );
3926:
3927: Irp->IoStatus.Information = 0;
3928: }
3929:
3930: Irp->IoStatus.Status = status;
3931: IoCompleteRequest(Irp, IO_NO_INCREMENT);
3932: return status;
3933:
3934: }
3935:
3936: NTSTATUS
3937: CdAudioHitatchiSendPauseCommand(
3938: IN PDEVICE_OBJECT DeviceObject
3939: )
3940:
3941: /*++
3942:
3943: Routine Description:
3944:
3945: This routine sends a PAUSE cdb to the Hitatchi drive. The Hitatchi
3946: drive returns a "busy" condition whenever a play audio command is in
3947: progress...so we need to bump the drive out of audio play to issue
3948: a new command. This routine is in place for this purpose.
3949:
3950: Arguments:
3951:
3952: DeviceObject
3953: Irp
3954:
3955: Return Value:
3956:
3957: NTSTATUS
3958:
3959: --*/
3960:
3961: {
3962: PCD_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
3963: SCSI_REQUEST_BLOCK srb;
3964: PCDB12 cdb = (PCDB12)srb.Cdb;
3965: NTSTATUS status;
3966: PUCHAR PausePos;
3967:
3968: //
3969: // Allocate buffer for pause data
3970: //
3971:
3972: PausePos = (PUCHAR)ExAllocatePool( NonPagedPoolCacheAligned, 3 );
3973:
3974: if (PausePos==NULL) {
3975:
3976: return(STATUS_INSUFFICIENT_RESOURCES);
3977:
3978: }
3979:
3980: RtlZeroMemory( PausePos, 3 );
3981:
3982: //
3983: // Clear out cdb
3984: //
3985:
3986: RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
3987:
3988: //
3989: // Clear audio play command so that next command will be issued
3990: //
3991:
3992: srb.CdbLength = 12;
3993: srb.TimeOutValue = AUDIO_TIMEOUT;
3994: cdb->PAUSE_AUDIO.OperationCode = HITATCHI_PAUSE_AUDIO_CODE;
3995: status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
3996: &srb,
3997: PausePos,
3998: 3,
3999: FALSE
4000: );
4001:
4002: ExFreePool( PausePos );
4003:
4004: return status;
4005: }
4006:
4007: NTSTATUS
4008: CdAudioHitatchiDeviceControl(
4009: IN PDEVICE_OBJECT DeviceObject,
4010: IN PIRP Irp
4011: )
4012:
4013: /*++
4014:
4015: Routine Description:
4016:
4017: This routine is called by CdAudioDeviceControl to handle
4018: audio IOCTLs sent to Hitatchi cdrom drives.
4019:
4020: Arguments:
4021:
4022: DeviceObject
4023: Irp
4024:
4025: Return Value:
4026:
4027: NTSTATUS
4028:
4029: --*/
4030:
4031: {
4032: PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
4033: PCD_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
4034: PCDROM_TOC cdaudioDataOut = Irp->AssociatedIrp.SystemBuffer;
4035: SCSI_REQUEST_BLOCK srb;
4036: PCDB12 cdb = (PCDB12)srb.Cdb;
4037: NTSTATUS status;
4038: ULONG i,bytesTransfered;
4039: PUCHAR Toc;
4040:
4041: HitatchiRestart:
4042:
4043: //
4044: // Clear out cdb
4045: //
4046:
4047: RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
4048:
4049: //
4050: // What IOCTL do we need to execute?
4051: //
4052:
4053: switch (currentIrpStack->Parameters.DeviceIoControl.IoControlCode) {
4054:
4055: case IOCTL_CDROM_READ_TOC:
4056: CdDump(( 3,
4057: "CdAudioHitatchiDeviceControl: IOCTL_CDROM_READ_TOC received.\n"
4058: ));
4059:
4060: //
4061: // If the cd is playing music then reject this request.
4062: //
4063:
4064: if (CdAudioIsPlayActive(DeviceObject)) {
4065: status = STATUS_DEVICE_BUSY;
4066: break;
4067: }
4068:
4069: //
4070: // Allocate storage to hold TOC from disc
4071: //
4072:
4073: Toc = (PUCHAR)ExAllocatePool( NonPagedPoolCacheAligned,
4074: CDROM_TOC_SIZE
4075: );
4076:
4077: if (Toc==NULL) {
4078:
4079: status = STATUS_INSUFFICIENT_RESOURCES;
4080: goto SetStatusAndReturn;
4081:
4082: }
4083:
4084: //
4085: // Set up defaults
4086: //
4087:
4088: RtlZeroMemory( Toc, CDROM_TOC_SIZE );
4089: srb.CdbLength = 12;
4090:
4091: //
4092: // Fill in CDB
4093: //
4094:
4095: cdb->READ_DISC_INFO.OperationCode = HITATCHI_READ_TOC_CODE;
4096: cdb->READ_DISC_INFO.AllocationLength[0] = CDROM_TOC_SIZE >> 8;
4097: cdb->READ_DISC_INFO.AllocationLength[1] = CDROM_TOC_SIZE & 0xFF;
4098: srb.TimeOutValue = AUDIO_TIMEOUT;
4099: status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
4100: &srb,
4101: Toc,
4102: CDROM_TOC_SIZE,
4103: FALSE
4104: );
4105:
4106: if (!NT_SUCCESS(status) && (status!=STATUS_DATA_OVERRUN)) {
4107:
4108: CdDump(( 1,
4109: "CdAudioHitatchiDeviceControl: READ_TOC error (0x%08lX)\n",
4110: status ));
4111:
4112:
4113: if (SRB_STATUS(srb.SrbStatus)!=SRB_STATUS_DATA_OVERRUN) {
4114:
4115: CdDump(( 1, "CdAudioHitatchiDeviceControl: SRB ERROR (0x%lX)\n",
4116: srb.SrbStatus ));
4117: ExFreePool( Toc );
4118: goto SetStatusAndReturn;
4119: }
4120:
4121: } else
4122:
4123: status = STATUS_SUCCESS;
4124:
4125: //
4126: // Translate data into our format
4127: //
4128:
4129: bytesTransfered =
4130: currentIrpStack->Parameters.Read.Length > sizeof(CDROM_TOC) ?
4131: sizeof(CDROM_TOC) : currentIrpStack->Parameters.Read.Length;
4132: Irp->IoStatus.Information = bytesTransfered;
4133: cdaudioDataOut->Length[0] = bytesTransfered >> 8;
4134: cdaudioDataOut->Length[1] = (bytesTransfered & 0xFF);
4135: cdaudioDataOut->FirstTrack = Toc[2];
4136: cdaudioDataOut->LastTrack = Toc[3];
4137:
4138: for( i=0;
4139: i<=( (ULONG)cdaudioDataOut->LastTrack -
4140: (ULONG)cdaudioDataOut->FirstTrack );
4141: i++
4142: ) {
4143:
4144: //
4145: // Grab Information for each track
4146: //
4147:
4148: cdaudioDataOut->TrackData[i].Reserved = 0;
4149: cdaudioDataOut->TrackData[i].Control =
4150: ((Toc[(i*4)+8] & 0x0F) << 4) | (Toc[(i*4)+8] >> 4);
4151: cdaudioDataOut->TrackData[i].TrackNumber =
4152: (i + cdaudioDataOut->FirstTrack);
4153:
4154: cdaudioDataOut->TrackData[i].Reserved1 = 0;
4155: cdaudioDataOut->TrackData[i].Address[0] = 0;
4156: cdaudioDataOut->TrackData[i].Address[1] = Toc[(i*4)+9];
4157: cdaudioDataOut->TrackData[i].Address[2] = Toc[(i*4)+10];
4158: cdaudioDataOut->TrackData[i].Address[3] = Toc[(i*4)+11];
4159:
4160: }
4161:
4162: //
4163: // Fake "lead out track" info
4164: //
4165:
4166: cdaudioDataOut->TrackData[i].Reserved = 0;
4167: cdaudioDataOut->TrackData[i].Control = 0x10;
4168: cdaudioDataOut->TrackData[i].TrackNumber = 0xaa;
4169: cdaudioDataOut->TrackData[i].Reserved1 = 0;
4170: cdaudioDataOut->TrackData[i].Address[0] = 0;
4171: cdaudioDataOut->TrackData[i].Address[1] = Toc[5];
4172: cdaudioDataOut->TrackData[i].Address[2] = Toc[6];
4173: cdaudioDataOut->TrackData[i].Address[3] = Toc[7];
4174:
4175: //
4176: // Clear out device extension data
4177: //
4178:
4179: deviceExtension->Paused = CDAUDIO_NOT_PAUSED;
4180: deviceExtension->PausedM = 0;
4181: deviceExtension->PausedS = 0;
4182: deviceExtension->PausedF = 0;
4183: deviceExtension->LastEndM = 0;
4184: deviceExtension->LastEndS = 0;
4185: deviceExtension->LastEndF = 0;
4186:
4187: //
4188: // Free storage now that we've stored it elsewhere
4189: //
4190:
4191: ExFreePool( Toc );
4192: break;
4193:
4194: case IOCTL_CDROM_STOP_AUDIO:
4195:
4196: deviceExtension->PlayActive = FALSE;
4197:
4198: //
4199: // Kill any current play operation
4200: //
4201:
4202: CdAudioHitatchiSendPauseCommand( DeviceObject );
4203:
4204: //
4205: // Same as scsi-2 spec, so just send to default driver
4206: //
4207:
4208: deviceExtension->Paused = CDAUDIO_NOT_PAUSED;
4209: deviceExtension->PausedM = 0;
4210: deviceExtension->PausedS = 0;
4211: deviceExtension->PausedF = 0;
4212: deviceExtension->LastEndM = 0;
4213: deviceExtension->LastEndS = 0;
4214: deviceExtension->LastEndF = 0;
4215:
4216: return CdAudioSendToNextDriver( DeviceObject, Irp );
4217: break;
4218:
4219: case IOCTL_CDROM_PLAY_AUDIO_MSF:
4220: {
4221:
4222: PCDROM_PLAY_AUDIO_MSF inputBuffer =
4223: Irp->AssociatedIrp.SystemBuffer;
4224:
4225: CdDump(( 3,
4226: "CdAudioHitatchiDeviceControl: IOCTL_CDROM_PLAY_AUDIO_MSF received.\n"
4227: ));
4228:
4229: //
4230: // Kill any current play operation
4231: //
4232:
4233: CdAudioHitatchiSendPauseCommand( DeviceObject );
4234:
4235: //
4236: // Fill in CDB for PLAY operation
4237: //
4238:
4239: srb.CdbLength = 12;
4240: srb.TimeOutValue = AUDIO_TIMEOUT;
4241: cdb->PLAY_AUDIO.OperationCode = HITATCHI_PLAY_AUDIO_MSF_CODE;
4242: cdb->PLAY_AUDIO.Immediate = 1;
4243: cdb->PLAY_AUDIO.StartingM = inputBuffer->StartingM;
4244: cdb->PLAY_AUDIO.StartingS = inputBuffer->StartingS;
4245: cdb->PLAY_AUDIO.StartingF = inputBuffer->StartingF;
4246: cdb->PLAY_AUDIO.EndingM = inputBuffer->EndingM;
4247: cdb->PLAY_AUDIO.EndingS = inputBuffer->EndingS;
4248: cdb->PLAY_AUDIO.EndingF = inputBuffer->EndingF;
4249: status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
4250: &srb,
4251: NULL,
4252: 0,
4253: FALSE
4254: );
4255:
4256: if (NT_SUCCESS(status)) {
4257:
4258: //
4259: // Indicate the play actition is active.
4260: //
4261:
4262: deviceExtension->PlayActive = TRUE;
4263:
4264: deviceExtension->Paused = CDAUDIO_NOT_PAUSED;
4265:
4266:
4267: //
4268: // Set last play ending address for next pause command
4269: //
4270:
4271: deviceExtension->PausedM = inputBuffer->StartingM;
4272: deviceExtension->PausedS = inputBuffer->StartingS;
4273: deviceExtension->PausedF = inputBuffer->StartingF;
4274: deviceExtension->LastEndM = inputBuffer->EndingM;
4275: deviceExtension->LastEndS = inputBuffer->EndingS;
4276: deviceExtension->LastEndF = inputBuffer->EndingF;
4277:
4278: } else {
4279:
4280: CdDump(( 3,
4281: "CdAudioHitatchiDeviceControl: PLAY failed (0x%08lX)\n",
4282: status ));
4283: }
4284:
4285: }
4286: break;
4287:
4288: case IOCTL_CDROM_SEEK_AUDIO_MSF:
4289: {
4290:
4291: PCDROM_SEEK_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
4292:
4293: CdDump(( 3,
4294: "CdAudioHitatchiDeviceControl: IOCTL_CDROM_SEEK_AUDIO_MSF received.\n"
4295: ));
4296:
4297: //
4298: // Kill any current play operation
4299: //
4300:
4301: CdAudioHitatchiSendPauseCommand( DeviceObject );
4302:
4303: //
4304: // seek to MSF and enter pause (still) mode.
4305: //
4306:
4307: //
4308: // Fill in CDB for PLAY operation
4309: //
4310:
4311: srb.CdbLength = 12;
4312: srb.TimeOutValue = AUDIO_TIMEOUT;
4313: cdb->PLAY_AUDIO.OperationCode = HITATCHI_PLAY_AUDIO_MSF_CODE;
4314: cdb->PLAY_AUDIO.Immediate = 1;
4315: cdb->PLAY_AUDIO.StartingM = inputBuffer->M;
4316: cdb->PLAY_AUDIO.StartingS = inputBuffer->S;
4317: cdb->PLAY_AUDIO.StartingF = inputBuffer->F;
4318: cdb->PLAY_AUDIO.EndingM = inputBuffer->M;
4319: cdb->PLAY_AUDIO.EndingS = inputBuffer->S;
4320: cdb->PLAY_AUDIO.EndingF = inputBuffer->F;
4321:
4322: status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
4323: &srb,
4324: NULL,
4325: 0,
4326: FALSE
4327: );
4328: if (NT_SUCCESS(status)) {
4329:
4330: deviceExtension->PausedM = inputBuffer->M;
4331: deviceExtension->PausedS = inputBuffer->S;
4332: deviceExtension->PausedF = inputBuffer->F;
4333: deviceExtension->LastEndM = inputBuffer->M;
4334: deviceExtension->LastEndS = inputBuffer->S;
4335: deviceExtension->LastEndF = inputBuffer->F;
4336:
4337: } else {
4338:
4339: CdDump(( 3,
4340: "CdAudioHitatchiDeviceControl: SEEK failed (0x%08lX)\n",
4341: status ));
4342: }
4343:
4344: }
4345: break;
4346:
4347: case IOCTL_CDROM_PAUSE_AUDIO:
4348: {
4349:
4350: PUCHAR PausePos = ExAllocatePool( NonPagedPoolCacheAligned, 3 );
4351: if (PausePos==NULL) {
4352:
4353: status = STATUS_INSUFFICIENT_RESOURCES;
4354: goto SetStatusAndReturn;
4355:
4356: }
4357:
4358: deviceExtension->PlayActive = FALSE;
4359:
4360: RtlZeroMemory( PausePos, 3 );
4361:
4362: CdDump(( 3,
4363: "CdAudioHitatchiDeviceControl: IOCTL_CDROM_PAUSE_AUDIO received.\n"
4364: ));
4365:
4366: //
4367: // Enter pause (still ) mode
4368: //
4369:
4370: srb.CdbLength = 12;
4371: srb.TimeOutValue = AUDIO_TIMEOUT;
4372: cdb->PAUSE_AUDIO.OperationCode = HITATCHI_PAUSE_AUDIO_CODE;
4373: status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
4374: &srb,
4375: PausePos,
4376: 3,
4377: FALSE
4378: );
4379:
4380: deviceExtension->Paused = CDAUDIO_PAUSED;
4381: deviceExtension->PausedM = PausePos[0];
4382: deviceExtension->PausedS = PausePos[1];
4383: deviceExtension->PausedF = PausePos[2];
4384:
4385: ExFreePool( PausePos );
4386: }
4387: break;
4388:
4389: case IOCTL_CDROM_RESUME_AUDIO:
4390:
4391: CdDump(( 3,
4392: "CdAudioHitatchiDeviceControl: IOCTL_CDROM_RESUME_AUDIO received.\n"
4393: ));
4394:
4395: //
4396: // Kill any current play operation
4397: //
4398:
4399: CdAudioHitatchiSendPauseCommand( DeviceObject );
4400:
4401: //
4402: // Resume play
4403: //
4404:
4405: //
4406: // Fill in CDB for PLAY operation
4407: //
4408:
4409: srb.CdbLength = 12;
4410: srb.TimeOutValue = AUDIO_TIMEOUT;
4411: cdb->PLAY_AUDIO.OperationCode = HITATCHI_PLAY_AUDIO_MSF_CODE;
4412: cdb->PLAY_AUDIO.Immediate = 1;
4413: cdb->PLAY_AUDIO.StartingM = deviceExtension->PausedM;
4414: cdb->PLAY_AUDIO.StartingS = deviceExtension->PausedS;
4415: cdb->PLAY_AUDIO.StartingF = deviceExtension->PausedF;
4416: cdb->PLAY_AUDIO.EndingM = deviceExtension->LastEndM;
4417: cdb->PLAY_AUDIO.EndingS = deviceExtension->LastEndS;
4418: cdb->PLAY_AUDIO.EndingF = deviceExtension->LastEndF;
4419: status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
4420: &srb,
4421: NULL,
4422: 0,
4423: FALSE
4424: );
4425:
4426: if (NT_SUCCESS(status)) {
4427:
4428: deviceExtension->Paused = CDAUDIO_NOT_PAUSED;
4429:
4430: }
4431:
4432: break;
4433:
4434: case IOCTL_CDROM_READ_Q_CHANNEL:
4435: {
4436:
4437: PSUB_Q_CURRENT_POSITION userPtr =
4438: Irp->AssociatedIrp.SystemBuffer;
4439: PUCHAR SubQPtr =
4440: ExAllocatePool( NonPagedPoolCacheAligned,
4441: sizeof(SUB_Q_CHANNEL_DATA)
4442: );
4443:
4444: CdDump(( 5,
4445: "CdAudioHitatchiDeviceControl: IOCTL_CDROM_READ_Q_CHANNEL received.\n"
4446: ));
4447:
4448: if (SubQPtr==NULL) {
4449:
4450: CdDump(( 1,
4451: "CdAudioHitatchiDeviceControl: READ_Q_CHANNEL, SubQPtr==NULL!\n"
4452: ));
4453:
4454: status = STATUS_INSUFFICIENT_RESOURCES;
4455: RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
4456: goto SetStatusAndReturn;
4457:
4458: }
4459:
4460: if ( ((PCDROM_SUB_Q_DATA_FORMAT)userPtr)->Format!=
4461: IOCTL_CDROM_CURRENT_POSITION) {
4462:
4463: CdDump(( 1,
4464: "CdAudioHitatchiDeviceControl: READ_Q_CHANNEL, illegal Format (%d)\n",
4465: ((PCDROM_SUB_Q_DATA_FORMAT)userPtr)->Format
4466: ));
4467:
4468: ExFreePool( SubQPtr );
4469: status = STATUS_UNSUCCESSFUL;
4470: RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
4471: goto SetStatusAndReturn;
4472: }
4473:
4474: //
4475: // Set up to read Q Channel
4476: //
4477:
4478: srb.CdbLength = 12;
4479: srb.TimeOutValue = AUDIO_TIMEOUT;
4480: cdb->AUDIO_STATUS.OperationCode = HITATCHI_READ_SUB_Q_CHANNEL_CODE;
4481: status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
4482: &srb,
4483: SubQPtr,
4484: sizeof(SUB_Q_CHANNEL_DATA),
4485: FALSE
4486: );
4487: if ((NT_SUCCESS(status)) || (status==STATUS_DATA_OVERRUN)) {
4488:
4489: userPtr->Header.Reserved = 0;
4490: if (deviceExtension->Paused == CDAUDIO_PAUSED) {
4491:
4492: deviceExtension->PlayActive = FALSE;
4493: userPtr->Header.AudioStatus = AUDIO_STATUS_PAUSED;
4494: } else {
4495: if (SubQPtr[0]==0x01)
4496: userPtr->Header.AudioStatus = AUDIO_STATUS_IN_PROGRESS;
4497: else if (SubQPtr[0]==0x00){
4498: userPtr->Header.AudioStatus = AUDIO_STATUS_PLAY_COMPLETE;
4499: deviceExtension->PlayActive = FALSE;
4500:
4501: } else {
4502: deviceExtension->PlayActive = FALSE;
4503: }
4504: }
4505: userPtr->Header.DataLength[0] = 0;
4506: userPtr->Header.DataLength[0] = 12;
4507:
4508: userPtr->FormatCode = 0x01;
4509: userPtr->Control = ((SubQPtr[1] & 0xF0) >> 4);
4510: userPtr->ADR = SubQPtr[1] & 0x0F;
4511: userPtr->TrackNumber = SubQPtr[2];
4512: userPtr->IndexNumber = SubQPtr[3];
4513: userPtr->AbsoluteAddress[0] = 0;
4514: userPtr->AbsoluteAddress[1] = SubQPtr[8];
4515: userPtr->AbsoluteAddress[2] = SubQPtr[9];
4516: userPtr->AbsoluteAddress[3] = SubQPtr[10];
4517: userPtr->TrackRelativeAddress[0] = 0;
4518: userPtr->TrackRelativeAddress[1] = SubQPtr[4];
4519: userPtr->TrackRelativeAddress[2] = SubQPtr[5];
4520: userPtr->TrackRelativeAddress[3] = SubQPtr[6];
4521: Irp->IoStatus.Information = 16;
4522: status = STATUS_SUCCESS;
4523:
4524: } else {
4525:
4526: RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
4527: CdDump(( 1,
4528: "CdAudioHitatchiDeviceControl: READ_Q_CHANNEL failed (0x%08lX)\n",
4529: status
4530: ));
4531:
4532: }
4533:
4534: ExFreePool( SubQPtr );
4535:
4536: }
4537: break;
4538:
4539: case IOCTL_CDROM_EJECT_MEDIA:
4540: {
4541:
4542: PUCHAR EjectStatus = ExAllocatePool( NonPagedPoolCacheAligned, 1 );
4543:
4544: if (EjectStatus==NULL) {
4545:
4546: status = STATUS_INSUFFICIENT_RESOURCES;
4547: goto SetStatusAndReturn;
4548:
4549: }
4550:
4551: deviceExtension->PlayActive = FALSE;
4552:
4553: CdDump(( 3,
4554: "CdAudioHitatchiDeviceControl: IOCTL_CDROM_EJECT_MEDIA received.\n"
4555: ));
4556:
4557: //
4558: // Set up to EJECT disc
4559: //
4560:
4561: srb.CdbLength = 12;
4562: srb.TimeOutValue = AUDIO_TIMEOUT;
4563: cdb->EJECT.OperationCode = HITATCHI_EJECT_CODE;
4564: cdb->EJECT.Eject = 1; // Set Eject flag
4565: status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
4566: &srb,
4567: EjectStatus,
4568: 1,
4569: FALSE
4570: );
4571: if (NT_SUCCESS(status)) {
4572:
4573: deviceExtension->Paused = CDAUDIO_NOT_PAUSED;
4574: deviceExtension->PausedM = 0;
4575: deviceExtension->PausedS = 0;
4576: deviceExtension->PausedF = 0;
4577: deviceExtension->LastEndM = 0;
4578: deviceExtension->LastEndS = 0;
4579: deviceExtension->LastEndF = 0;
4580:
4581: }
4582:
4583: ExFreePool( EjectStatus );
4584: }
4585: break;
4586:
4587: case IOCTL_CDROM_GET_CONTROL:
4588: case IOCTL_CDROM_GET_VOLUME:
4589: case IOCTL_CDROM_SET_VOLUME:
4590:
4591: CdDump(( 3, "CdAudioHitatchieviceControl: Not Supported yet.\n" ));
4592: status = STATUS_INVALID_DEVICE_REQUEST;
4593: break;
4594:
4595: case IOCTL_CDROM_CHECK_VERIFY:
4596:
4597: //
4598: // Update the play active flag.
4599: //
4600:
4601: CdAudioIsPlayActive(DeviceObject);
4602:
4603: default:
4604:
4605: CdDump((5,"CdAudioHitatchiDeviceControl: Unsupported device IOCTL\n"));
4606: return CdAudioSendToNextDriver( DeviceObject, Irp );
4607: break;
4608:
4609: } // end switch( IOCTL )
4610:
4611: SetStatusAndReturn:
4612:
4613: //
4614: // set status code and return
4615: //
4616:
4617: if (status == STATUS_VERIFY_REQUIRED) {
4618:
4619: //
4620: // If the status is verified required and the this request
4621: // should bypass verify required then retry the request.
4622: //
4623:
4624: if (currentIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME) {
4625:
4626: status = STATUS_IO_DEVICE_ERROR;
4627: goto HitatchiRestart;
4628:
4629: }
4630:
4631:
4632: IoSetHardErrorOrVerifyDevice( Irp,
4633: deviceExtension->TargetDeviceObject
4634: );
4635:
4636: Irp->IoStatus.Information = 0;
4637: }
4638:
4639: Irp->IoStatus.Status = status;
4640: IoCompleteRequest(Irp, IO_NO_INCREMENT);
4641: return status;
4642:
4643: }
4644:
4645: NTSTATUS
4646: CdAudio535DeviceControl(
4647: PDEVICE_OBJECT DeviceObject,
4648: PIRP Irp
4649: )
4650:
4651: /*++
4652:
4653: Routine Description:
4654:
4655: This routine is called by CdAudioDeviceControl to handle
4656: audio IOCTLs sent to Chinon CDS-535 cdrom drive.
4657:
4658: Arguments:
4659:
4660: DeviceObject
4661: Irp
4662:
4663: Return Value:
4664:
4665: NTSTATUS
4666:
4667: --*/
4668:
4669: {
4670: PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
4671: PCD_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
4672: PCDROM_TOC cdaudioDataOut = Irp->AssociatedIrp.SystemBuffer;
4673: SCSI_REQUEST_BLOCK srb;
4674: PREAD_CAPACITY_DATA lastSession;
4675: PCDB cdb = (PCDB)srb.Cdb;
4676: NTSTATUS status;
4677: ULONG i,bytesTransfered;
4678: PUCHAR Toc;
4679: ULONG retry;
4680: ULONG destblock;
4681:
4682:
4683: //
4684: // Clear out cdb
4685: //
4686:
4687: RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
4688:
4689: //
4690: // What IOCTL do we need to execute?
4691: //
4692:
4693: switch (currentIrpStack->Parameters.DeviceIoControl.IoControlCode) {
4694:
4695: case IOCTL_CDROM_GET_LAST_SESSION:
4696:
4697: //
4698: // If the cd is playing music then reject this request.
4699: //
4700:
4701: if (CdAudioIsPlayActive(DeviceObject)) {
4702: status = STATUS_DEVICE_BUSY;
4703: break;
4704: }
4705:
4706: if (currentIrpStack->Parameters.Read.Length <
4707: FIELD_OFFSET(CDROM_TOC, TrackData[1])) {
4708: status = STATUS_INFO_LENGTH_MISMATCH;
4709: break;
4710:
4711: }
4712:
4713: // Allocate storage to hold lastSession from disc
4714: //
4715:
4716: lastSession = ExAllocatePool( NonPagedPoolCacheAligned,
4717: sizeof(READ_CAPACITY_DATA)
4718: );
4719:
4720: if (lastSession==NULL) {
4721:
4722: status = STATUS_INSUFFICIENT_RESOURCES;
4723: goto SetStatusAndReturn;
4724:
4725: }
4726:
4727: //
4728: // Set up defaults
4729: //
4730:
4731: RtlZeroMemory( lastSession, sizeof(READ_CAPACITY_DATA));
4732: srb.CdbLength = 10;
4733:
4734: //
4735: // Fill in CDB
4736: //
4737:
4738: cdb->CDB10.OperationCode = CDS535_GET_LAST_SESSION;
4739: srb.TimeOutValue = AUDIO_TIMEOUT;
4740: status = ScsiClassSendSrbSynchronous(
4741: deviceExtension->DeviceObject,
4742: &srb,
4743: lastSession,
4744: sizeof(READ_CAPACITY_DATA),
4745: FALSE
4746: );
4747:
4748: if (!NT_SUCCESS(status)) {
4749:
4750: CdDump(( 1,
4751: "CdAudio535DeviceControl: READ_TOC error (0x%08lX)\n",
4752: status ));
4753:
4754:
4755: ExFreePool( lastSession );
4756: goto SetStatusAndReturn;
4757:
4758: } else {
4759:
4760: status = STATUS_SUCCESS;
4761: }
4762:
4763: //
4764: // Translate data into our format.
4765: //
4766:
4767: bytesTransfered = FIELD_OFFSET(CDROM_TOC, TrackData[1]);
4768: Irp->IoStatus.Information = bytesTransfered;
4769:
4770: RtlZeroMemory(cdaudioDataOut, bytesTransfered);
4771:
4772: cdaudioDataOut->Length[0] = bytesTransfered >> 8;
4773: cdaudioDataOut->Length[1] = (bytesTransfered & 0xFF);
4774:
4775: //
4776: // Determine if this is a multisession cd.
4777: //
4778:
4779: if (lastSession->LogicalBlockAddress == 0) {
4780:
4781: //
4782: // This is a single session disk. Just return.
4783: //
4784:
4785: ExFreePool(lastSession);
4786: break;
4787: }
4788:
4789: //
4790: // Fake the session information.
4791: //
4792:
4793: cdaudioDataOut->FirstTrack = 1;
4794: cdaudioDataOut->LastTrack = 2;
4795:
4796: CdDump(( 4,
4797: "CdAudio535DeviceControl: Tracks %d - %d, (0x%lX bytes)\n",
4798: cdaudioDataOut->FirstTrack,
4799: cdaudioDataOut->LastTrack,
4800: bytesTransfered
4801: ));
4802:
4803:
4804: //
4805: // Grab Information for the last session.
4806: //
4807:
4808: *((ULONG *)&cdaudioDataOut->TrackData[0].Address[0]) =
4809: lastSession->LogicalBlockAddress;
4810:
4811: //
4812: // Free storage now that we've stored it elsewhere
4813: //
4814:
4815: ExFreePool( lastSession );
4816: break;
4817:
4818:
4819: case IOCTL_CDROM_READ_TOC:
4820: CdDump(( 3,
4821: "CdAudio535DeviceControl: IOCTL_CDROM_READ_TOC received.\n"
4822: ));
4823:
4824:
4825: //
4826: // If the cd is playing music then reject this request.
4827: //
4828:
4829: if (CdAudioIsPlayActive(DeviceObject)) {
4830: status = STATUS_DEVICE_BUSY;
4831: break;
4832: }
4833:
4834: //
4835: // Allocate storage to hold TOC from disc
4836: //
4837:
4838: Toc = (PUCHAR)ExAllocatePool( NonPagedPoolCacheAligned,
4839: CDROM_TOC_SIZE
4840: );
4841:
4842: if (Toc==NULL) {
4843:
4844: status = STATUS_INSUFFICIENT_RESOURCES;
4845: goto SetStatusAndReturn;
4846:
4847: }
4848:
4849: //
4850: // Set up defaults
4851: //
4852:
4853: RtlZeroMemory( Toc, CDROM_TOC_SIZE );
4854:
4855: //
4856: // Fill in cdb for this operation
4857: //
4858:
4859: cdb->CDB10.OperationCode = CDS535_READ_TOC_CODE;
4860: cdb->CDB10.Reserved1 = 1; // MSF mode
4861: cdb->CDB10.TransferBlocksMsb = (CDROM_TOC_SIZE >> 8);
4862: cdb->CDB10.TransferBlocksLsb = (CDROM_TOC_SIZE & 0xFF);
4863: srb.TimeOutValue = AUDIO_TIMEOUT;
4864: srb.CdbLength = 10;
4865: status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
4866: &srb,
4867: Toc,
4868: CDROM_TOC_SIZE,
4869: FALSE
4870: );
4871:
4872: if (!NT_SUCCESS(status) && (status!=STATUS_DATA_OVERRUN)) {
4873:
4874: CdDump(( 1,
4875: "CdAudio535DeviceControl: READ_TOC error (0x%08lX)\n",
4876: status ));
4877:
4878: if (SRB_STATUS(srb.SrbStatus)!=SRB_STATUS_DATA_OVERRUN) {
4879:
4880: CdDump(( 1, "CdAudio535DeviceControl: SRB ERROR (0x%lX)\n",
4881: srb.SrbStatus ));
4882: ExFreePool( Toc );
4883: goto SetStatusAndReturn;
4884: }
4885:
4886: } else {
4887:
4888: status = STATUS_SUCCESS;
4889: }
4890:
4891: //
4892: // Translate data into SCSI-II format
4893: // (track numbers, except 0xAA, must be converted from BCD)
4894:
4895: bytesTransfered =
4896: currentIrpStack->Parameters.Read.Length > sizeof(CDROM_TOC) ?
4897: sizeof(CDROM_TOC) : currentIrpStack->Parameters.Read.Length;
4898: Irp->IoStatus.Information = bytesTransfered;
4899:
4900: cdaudioDataOut->Length[0] = Toc[0];
4901: cdaudioDataOut->Length[1] = Toc[1];
4902: cdaudioDataOut->FirstTrack = BCD_TO_DEC(Toc[2]);
4903: cdaudioDataOut->LastTrack = BCD_TO_DEC(Toc[3]);
4904:
4905: for( i=0;
4906: i<=( (ULONG)cdaudioDataOut->LastTrack -
4907: (ULONG)cdaudioDataOut->FirstTrack );
4908: i++
4909: ) {
4910:
4911: //
4912: // Grab Information for each track
4913: //
4914:
4915: cdaudioDataOut->TrackData[i].Reserved = 0;
4916: cdaudioDataOut->TrackData[i].Control = Toc[(i*8)+4+1];
4917: cdaudioDataOut->TrackData[i].TrackNumber = BCD_TO_DEC(Toc[(i*8)+4+2]);
4918: cdaudioDataOut->TrackData[i].Reserved1 = 0;
4919: cdaudioDataOut->TrackData[i].Address[0] = 0;
4920: cdaudioDataOut->TrackData[i].Address[1] = Toc[(i*8)+4+5];
4921: cdaudioDataOut->TrackData[i].Address[2] = Toc[(i*8)+4+6];
4922: cdaudioDataOut->TrackData[i].Address[3] = Toc[(i*8)+4+7];
4923:
4924: }
4925:
4926: //
4927: // Copy "lead out track" info
4928: //
4929:
4930: cdaudioDataOut->TrackData[i].Reserved = 0;
4931: cdaudioDataOut->TrackData[i].Control = Toc[(i*8)+4+1];
4932: cdaudioDataOut->TrackData[i].TrackNumber = Toc[(i*8)+4+2]; /* leave as 0xAA */
4933: cdaudioDataOut->TrackData[i].Reserved1 = 0;
4934: cdaudioDataOut->TrackData[i].Address[0] = 0;
4935: cdaudioDataOut->TrackData[i].Address[1] = Toc[(i*8)+4+5];
4936: cdaudioDataOut->TrackData[i].Address[2] = Toc[(i*8)+4+6];
4937: cdaudioDataOut->TrackData[i].Address[3] = Toc[(i*8)+4+7];
4938:
4939: //
4940: // Free storage now that we've stored it elsewhere
4941: //
4942:
4943: ExFreePool( Toc );
4944: break;
4945:
4946: case IOCTL_CDROM_READ_Q_CHANNEL:
4947: {
4948: PSUB_Q_CURRENT_POSITION userPtr =
4949: Irp->AssociatedIrp.SystemBuffer;
4950: PUCHAR SubQPtr =
4951: ExAllocatePool( NonPagedPoolCacheAligned,
4952: sizeof(SUB_Q_CURRENT_POSITION)
4953: );
4954:
4955: CdDump(( 5,
4956: "CdAudio535DeviceControl: IOCTL_CDROM_READ_Q_CHANNEL received.\n"
4957: ));
4958:
4959: if (SubQPtr==NULL) {
4960:
4961: CdDump(( 1,
4962: "CdAudio535DeviceControl: READ_Q_CHANNEL, SubQPtr==NULL!\n"
4963: ));
4964:
4965: RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
4966: status = STATUS_INSUFFICIENT_RESOURCES;
4967: goto SetStatusAndReturn;
4968:
4969: }
4970:
4971: if ( ((PCDROM_SUB_Q_DATA_FORMAT)userPtr)->Format!=
4972: IOCTL_CDROM_CURRENT_POSITION) {
4973:
4974: CdDump(( 1,
4975: "CdAudio535DeviceControl: READ_Q_CHANNEL, illegal Format (%d)\n",
4976: ((PCDROM_SUB_Q_DATA_FORMAT)userPtr)->Format
4977: ));
4978:
4979: ExFreePool( SubQPtr );
4980: RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
4981: status = STATUS_UNSUCCESSFUL;
4982: goto SetStatusAndReturn;
4983: }
4984:
4985: //
4986: // Get Current Position
4987: //
4988:
4989: srb.CdbLength = 10;
4990: srb.TimeOutValue = AUDIO_TIMEOUT;
4991: cdb->SUBCHANNEL.OperationCode = CDS535_READ_SUB_Q_CHANNEL_CODE;
4992: cdb->SUBCHANNEL.Msf = 1;
4993: cdb->SUBCHANNEL.SubQ = 1;
4994: cdb->SUBCHANNEL.Format = 1;
4995: cdb->SUBCHANNEL.AllocationLength[1] = sizeof(SUB_Q_CURRENT_POSITION);
4996: status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
4997: &srb,
4998: SubQPtr,
4999: sizeof(SUB_Q_CURRENT_POSITION),
5000: FALSE
5001: );
5002:
5003: //
5004: // Copy current position, converting track and index from BCD
5005: //
5006:
5007: if (NT_SUCCESS(status)) {
5008: if(SubQPtr[1] == 0x11) deviceExtension->PlayActive = TRUE;
5009: else deviceExtension->PlayActive = FALSE;
5010:
5011: userPtr->Header.Reserved = 0;
5012: userPtr->Header.AudioStatus = SubQPtr[1];
5013: userPtr->Header.DataLength[0] = 0;
5014: userPtr->Header.DataLength[1] = 12;
5015: userPtr->FormatCode = 0x01;
5016: userPtr->Control = SubQPtr[5];
5017: userPtr->ADR = 0;
5018: userPtr->TrackNumber = BCD_TO_DEC(SubQPtr[6]);
5019: userPtr->IndexNumber = BCD_TO_DEC(SubQPtr[7]);
5020: userPtr->AbsoluteAddress[0] = 0;
5021: userPtr->AbsoluteAddress[1] = SubQPtr[9];
5022: userPtr->AbsoluteAddress[2] = SubQPtr[10];
5023: userPtr->AbsoluteAddress[3] = SubQPtr[11];
5024: userPtr->TrackRelativeAddress[0] = 0;
5025: userPtr->TrackRelativeAddress[1] = SubQPtr[13];
5026: userPtr->TrackRelativeAddress[2] = SubQPtr[14];
5027: userPtr->TrackRelativeAddress[3] = SubQPtr[15];
5028: Irp->IoStatus.Information = 16;
5029: } else {
5030: RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
5031: CdDump(( 1,
5032: "CdAudio535DeviceControl: READ_Q_CHANNEL failed (0x%08lX)\n",
5033: status
5034: ));
5035: }
5036:
5037: ExFreePool( SubQPtr );
5038: }
5039: break;
5040:
5041: case IOCTL_CDROM_PLAY_AUDIO_MSF:
5042:
5043: {
5044: PCDROM_PLAY_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
5045:
5046: //
5047: // Play Audio MSF
5048: //
5049:
5050: DebugPrint((2,"ScsiCdRomDeviceControl: Play audio MSF\n"));
5051:
5052: if (currentIrpStack->Parameters.DeviceIoControl.InputBufferLength <
5053: sizeof(CDROM_PLAY_AUDIO_MSF)) {
5054:
5055: //
5056: // Indicate unsuccessful status.
5057: //
5058:
5059: status = STATUS_BUFFER_TOO_SMALL;
5060: break;
5061: }
5062:
5063: if (inputBuffer->StartingM == inputBuffer->EndingM &&
5064: inputBuffer->StartingS == inputBuffer->EndingS &&
5065: inputBuffer->StartingF == inputBuffer->EndingF) {
5066:
5067: cdb->PAUSE_RESUME.OperationCode = SCSIOP_PAUSE_RESUME;
5068: cdb->PAUSE_RESUME.Action = CDB_AUDIO_PAUSE;
5069:
5070: } else {
5071: cdb->PLAY_AUDIO_MSF.OperationCode = SCSIOP_PLAY_AUDIO_MSF;
5072:
5073: cdb->PLAY_AUDIO_MSF.StartingM = inputBuffer->StartingM;
5074: cdb->PLAY_AUDIO_MSF.StartingS = inputBuffer->StartingS;
5075: cdb->PLAY_AUDIO_MSF.StartingF = inputBuffer->StartingF;
5076:
5077: cdb->PLAY_AUDIO_MSF.EndingM = inputBuffer->EndingM;
5078: cdb->PLAY_AUDIO_MSF.EndingS = inputBuffer->EndingS;
5079: cdb->PLAY_AUDIO_MSF.EndingF = inputBuffer->EndingF;
5080:
5081: }
5082:
5083: srb.CdbLength = 10;
5084:
5085: //
5086: // Set timeout value.
5087: //
5088:
5089: srb.TimeOutValue = AUDIO_TIMEOUT;
5090:
5091: status = ScsiClassSendSrbSynchronous(DeviceObject,
5092: &srb,
5093: NULL,
5094: 0,
5095: FALSE);
5096:
5097: if (NT_SUCCESS(status) &&
5098: cdb->PLAY_AUDIO_MSF.OperationCode == SCSIOP_PLAY_AUDIO_MSF) {
5099: deviceExtension->PlayActive = TRUE;
5100: }
5101: }
5102:
5103: break;
5104:
5105: case IOCTL_CDROM_SEEK_AUDIO_MSF:
5106: {
5107:
5108: PCDROM_SEEK_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
5109:
5110: CdDump(( 3,
5111: "CdAudio535DeviceControl: IOCTL_CDROM_SEEK_AUDIO_MSF received.\n"
5112: ));
5113:
5114: //
5115: // Use the data seek command to move the pickup
5116: // BUGBUG: blithely assumes logical block size == 2048 bytes
5117: //
5118:
5119: destblock = ((((ULONG)(inputBuffer->M) * 60)
5120: + (ULONG)(inputBuffer->S)) * 75)
5121: + (ULONG)(inputBuffer->F)
5122: - 150;
5123:
5124: srb.CdbLength = 10;
5125: srb.TimeOutValue = AUDIO_TIMEOUT;
5126: cdb->SEEK.OperationCode = SCSIOP_SEEK;
5127: cdb->SEEK.LogicalBlockAddress[0] = (destblock >> 24) & 0xFF;
5128: cdb->SEEK.LogicalBlockAddress[1] = (destblock >> 16) & 0xFF;
5129: cdb->SEEK.LogicalBlockAddress[2] = (destblock >> 8) & 0xFF;
5130: cdb->SEEK.LogicalBlockAddress[3] = destblock & 0xFF;
5131: status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
5132: &srb,
5133: NULL,
5134: 0,
5135: FALSE
5136: );
5137:
5138: if (!NT_SUCCESS(status)) {
5139:
5140: CdDump(( 3,
5141: "CdAudio535DeviceControl: SEEK failed (0x%08lX)\n",
5142: status ));
5143:
5144: }
5145: }
5146: break;
5147:
5148: case IOCTL_CDROM_EJECT_MEDIA:
5149:
5150: //
5151: // Build cdb to eject cartridge
5152: //
5153:
5154: CdDump(( 3,
5155: "CdAudio535DeviceControl: IOCTL_CDROM_EJECT_MEDIA received.\n"
5156: ));
5157:
5158: deviceExtension->PlayActive = FALSE;
5159:
5160: srb.CdbLength = 10;
5161: srb.TimeOutValue = AUDIO_TIMEOUT;
5162: cdb->CDB10.OperationCode = CDS535_EJECT_CODE;
5163: status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
5164: &srb,
5165: NULL,
5166: 0,
5167: FALSE
5168: );
5169: break;
5170:
5171: case IOCTL_CDROM_GET_CONTROL:
5172: case IOCTL_CDROM_GET_VOLUME:
5173: case IOCTL_CDROM_SET_VOLUME:
5174: CdDump(( 3, "CdAudio535DeviceControl: Not Supported yet.\n" ));
5175: status = STATUS_INVALID_DEVICE_REQUEST;
5176: break;
5177:
5178: case IOCTL_CDROM_CHECK_VERIFY:
5179:
5180: //
5181: // Update the play active flag.
5182: //
5183:
5184: CdAudioIsPlayActive(DeviceObject);
5185:
5186: default:
5187:
5188: CdDump((5,"ChCdAudio535DeviceControl: Unsupported device IOCTL\n"));
5189: return CdAudioSendToNextDriver( DeviceObject, Irp );
5190: break;
5191:
5192: } // end switch( IOCTL )
5193:
5194: SetStatusAndReturn:
5195: //
5196: // set status code and return
5197: //
5198:
5199: if (status == STATUS_VERIFY_REQUIRED) {
5200:
5201: IoSetHardErrorOrVerifyDevice( Irp,
5202: deviceExtension->TargetDeviceObject
5203: );
5204:
5205: Irp->IoStatus.Information = 0;
5206: }
5207:
5208: Irp->IoStatus.Status = status;
5209: IoCompleteRequest(Irp, IO_NO_INCREMENT);
5210: return status;
5211:
5212: }
5213:
5214:
5215: NTSTATUS
5216: CdAudio435DeviceControl(
5217: PDEVICE_OBJECT DeviceObject,
5218: PIRP Irp
5219: )
5220:
5221: /*++
5222:
5223: Routine Description:
5224:
5225: This routine is called by CdAudioDeviceControl to handle
5226: audio IOCTLs sent to Chinon CDS-435 cdrom drive.
5227:
5228: Arguments:
5229:
5230: DeviceObject
5231: Irp
5232:
5233: Return Value:
5234:
5235: NTSTATUS
5236:
5237: --*/
5238:
5239: {
5240: PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
5241: PCD_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
5242: PCDROM_TOC cdaudioDataOut = Irp->AssociatedIrp.SystemBuffer;
5243: SCSI_REQUEST_BLOCK srb;
5244: PCDB cdb = (PCDB)srb.Cdb;
5245: NTSTATUS status;
5246: ULONG i,bytesTransfered;
5247: PUCHAR Toc;
5248:
5249: //
5250: // Clear out cdb
5251: //
5252:
5253: RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
5254:
5255: //
5256: // What IOCTL do we need to execute?
5257: //
5258:
5259: switch (currentIrpStack->Parameters.DeviceIoControl.IoControlCode) {
5260:
5261: case IOCTL_CDROM_READ_TOC:
5262: CdDump(( 3,
5263: "CdAudio435DeviceControl: IOCTL_CDROM_READ_TOC received.\n"
5264: ));
5265:
5266:
5267: //
5268: // If the cd is playing music then reject this request.
5269: //
5270:
5271: if (CdAudioIsPlayActive(DeviceObject)) {
5272: status = STATUS_DEVICE_BUSY;
5273: break;
5274: }
5275:
5276: //
5277: // Allocate storage to hold TOC from disc
5278: //
5279:
5280: Toc = (PUCHAR)ExAllocatePool( NonPagedPoolCacheAligned,
5281: CDROM_TOC_SIZE
5282: );
5283:
5284: if (Toc==NULL) {
5285:
5286: status = STATUS_INSUFFICIENT_RESOURCES;
5287: goto SetStatusAndReturn;
5288:
5289: }
5290:
5291: //
5292: // Set up defaults
5293: //
5294:
5295: RtlZeroMemory( Toc, CDROM_TOC_SIZE );
5296:
5297: //
5298: // Fill in cdb for this operation
5299: //
5300:
5301: cdb->READ_TOC.OperationCode = CDS435_READ_TOC_CODE;
5302: cdb->READ_TOC.Msf = 1;
5303: cdb->READ_TOC.AllocationLength[0] = (CDROM_TOC_SIZE >> 8);
5304: cdb->READ_TOC.AllocationLength[1] = (CDROM_TOC_SIZE & 0xFF);
5305: srb.TimeOutValue = AUDIO_TIMEOUT;
5306: srb.CdbLength = 10;
5307: status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
5308: &srb,
5309: Toc,
5310: CDROM_TOC_SIZE,
5311: FALSE
5312: );
5313:
5314: if (!NT_SUCCESS(status) && (status!=STATUS_DATA_OVERRUN)) {
5315:
5316: CdDump(( 1,
5317: "CdAudio435DeviceControl: READ_TOC error (0x%08lX)\n",
5318: status ));
5319:
5320: if (SRB_STATUS(srb.SrbStatus)!=SRB_STATUS_DATA_OVERRUN) {
5321:
5322: CdDump(( 1, "CdAudio435DeviceControl: SRB ERROR (0x%lX)\n",
5323: srb.SrbStatus ));
5324: ExFreePool( Toc );
5325: goto SetStatusAndReturn;
5326: }
5327:
5328: } else {
5329:
5330: status = STATUS_SUCCESS;
5331: }
5332:
5333: //
5334: // Translate data into SCSI-II format
5335: // (track numbers, except 0xAA, must be converted from BCD)
5336:
5337: bytesTransfered =
5338: currentIrpStack->Parameters.Read.Length > sizeof(CDROM_TOC) ?
5339: sizeof(CDROM_TOC) : currentIrpStack->Parameters.Read.Length;
5340: Irp->IoStatus.Information = bytesTransfered;
5341:
5342: cdaudioDataOut->Length[0] = Toc[0];
5343: cdaudioDataOut->Length[1] = Toc[1];
5344: cdaudioDataOut->FirstTrack = BCD_TO_DEC(Toc[2]);
5345: cdaudioDataOut->LastTrack = BCD_TO_DEC(Toc[3]);
5346:
5347: for( i=0;
5348: i<=( (ULONG)cdaudioDataOut->LastTrack -
5349: (ULONG)cdaudioDataOut->FirstTrack );
5350: i++
5351: ) {
5352:
5353: //
5354: // Grab Information for each track
5355: //
5356:
5357: cdaudioDataOut->TrackData[i].Reserved = 0;
5358: cdaudioDataOut->TrackData[i].Control = Toc[(i*8)+4+1];
5359: cdaudioDataOut->TrackData[i].TrackNumber = BCD_TO_DEC(Toc[(i*8)+4+2]);
5360: cdaudioDataOut->TrackData[i].Reserved1 = 0;
5361: cdaudioDataOut->TrackData[i].Address[0] = 0;
5362: cdaudioDataOut->TrackData[i].Address[1] = Toc[(i*8)+4+5];
5363: cdaudioDataOut->TrackData[i].Address[2] = Toc[(i*8)+4+6];
5364: cdaudioDataOut->TrackData[i].Address[3] = Toc[(i*8)+4+7];
5365:
5366: }
5367:
5368: //
5369: // Copy "lead out track" info
5370: //
5371:
5372: cdaudioDataOut->TrackData[i].Reserved = 0;
5373: cdaudioDataOut->TrackData[i].Control = Toc[(i*8)+4+1];
5374: cdaudioDataOut->TrackData[i].TrackNumber = Toc[(i*8)+4+2]; /* leave as 0xAA */
5375: cdaudioDataOut->TrackData[i].Reserved1 = 0;
5376: cdaudioDataOut->TrackData[i].Address[0] = 0;
5377: cdaudioDataOut->TrackData[i].Address[1] = Toc[(i*8)+4+5];
5378: cdaudioDataOut->TrackData[i].Address[2] = Toc[(i*8)+4+6];
5379: cdaudioDataOut->TrackData[i].Address[3] = Toc[(i*8)+4+7];
5380:
5381: //
5382: // Clear out deviceExtension data
5383: //
5384:
5385: deviceExtension->Paused = CDAUDIO_NOT_PAUSED;
5386: deviceExtension->PausedM = 0;
5387: deviceExtension->PausedS = 0;
5388: deviceExtension->PausedF = 0;
5389: deviceExtension->LastEndM = 0;
5390: deviceExtension->LastEndS = 0;
5391: deviceExtension->LastEndF = 0;
5392:
5393: //
5394: // Free storage now that we've stored it elsewhere
5395: //
5396:
5397: ExFreePool( Toc );
5398: break;
5399:
5400: case IOCTL_CDROM_PLAY_AUDIO_MSF:
5401: case IOCTL_CDROM_STOP_AUDIO:
5402: {
5403:
5404: PCDROM_PLAY_AUDIO_MSF inputBuffer =
5405: Irp->AssociatedIrp.SystemBuffer;
5406:
5407: srb.CdbLength = 10;
5408: srb.TimeOutValue = AUDIO_TIMEOUT;
5409: cdb->CDB10.OperationCode = CDS435_STOP_AUDIO_CODE;
5410: status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
5411: &srb,
5412: NULL,
5413: 0,
5414: FALSE
5415: );
5416:
5417: if (NT_SUCCESS(status)) {
5418:
5419: deviceExtension->PlayActive = FALSE;
5420:
5421: deviceExtension->Paused = CDAUDIO_NOT_PAUSED;
5422: deviceExtension->PausedM = 0;
5423: deviceExtension->PausedS = 0;
5424: deviceExtension->PausedF = 0;
5425: deviceExtension->LastEndM = 0;
5426: deviceExtension->LastEndS = 0;
5427: deviceExtension->LastEndF = 0;
5428:
5429: } else {
5430:
5431: CdDump(( 3,
5432: "CdAudio435DeviceControl: STOP failed (0x%08lX)\n",
5433: status ));
5434:
5435: }
5436:
5437:
5438: if (currentIrpStack->Parameters.DeviceIoControl.IoControlCode ==
5439: IOCTL_CDROM_STOP_AUDIO
5440: ) {
5441:
5442: CdDump(( 3,
5443: "CdAudio435DeviceControl: IOCTL_CDROM_STOP_AUDIO received.\n"
5444: ));
5445:
5446: goto SetStatusAndReturn;
5447:
5448: }
5449:
5450: CdDump(( 3,
5451: "CdAudio435DeviceControl: IOCTL_CDROM_PLAY_AUDIO_MSF received.\n"
5452: ));
5453:
5454: //
5455: // Fill in cdb for this operation
5456: //
5457:
5458: srb.CdbLength = 10;
5459: srb.TimeOutValue = AUDIO_TIMEOUT;
5460: cdb->PLAY_AUDIO_MSF.OperationCode = CDS435_PLAY_AUDIO_EXTENDED_CODE;
5461: cdb->PLAY_AUDIO_MSF.StartingM = inputBuffer->StartingM;
5462: cdb->PLAY_AUDIO_MSF.StartingS = inputBuffer->StartingS;
5463: cdb->PLAY_AUDIO_MSF.StartingF = inputBuffer->StartingF;
5464: cdb->PLAY_AUDIO_MSF.EndingM = inputBuffer->EndingM;
5465: cdb->PLAY_AUDIO_MSF.EndingS = inputBuffer->EndingS;
5466: cdb->PLAY_AUDIO_MSF.EndingF = inputBuffer->EndingF;
5467: status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
5468: &srb,
5469: NULL,
5470: 0,
5471: FALSE
5472: );
5473:
5474: if (NT_SUCCESS(status)) {
5475:
5476: deviceExtension->PlayActive = TRUE;
5477:
5478: deviceExtension->Paused = CDAUDIO_NOT_PAUSED;
5479:
5480: //
5481: // Set last play ending address for next pause command
5482: //
5483:
5484: deviceExtension->LastEndM = inputBuffer->EndingM;
5485: deviceExtension->LastEndS = inputBuffer->EndingS;
5486: deviceExtension->LastEndF = inputBuffer->EndingF;
5487: CdDump(( 3,
5488: "CdAudio435DeviceControl: PLAY ==> BcdLastEnd set to (%x %x %x)\n",
5489: deviceExtension->LastEndM,
5490: deviceExtension->LastEndS,
5491: deviceExtension->LastEndF ));
5492:
5493: } else {
5494:
5495: CdDump(( 3,
5496: "CdAudio435DeviceControl: PLAY failed (0x%08lX)\n",
5497: status ));
5498:
5499: }
5500: }
5501: break;
5502:
5503: case IOCTL_CDROM_SEEK_AUDIO_MSF:
5504: {
5505:
5506: PCDROM_SEEK_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
5507:
5508: CdDump(( 3,
5509: "CdAudio435DeviceControl: IOCTL_CDROM_SEEK_AUDIO_MSF received.\n"
5510: ));
5511:
5512: //
5513: // Fill in cdb for this operation
5514: //
5515:
5516: srb.CdbLength = 10;
5517: srb.TimeOutValue = AUDIO_TIMEOUT;
5518: cdb->CDB10.OperationCode = CDS435_PLAY_AUDIO_EXTENDED_CODE;
5519: cdb->PLAY_AUDIO_MSF.StartingM = inputBuffer->M;
5520: cdb->PLAY_AUDIO_MSF.StartingS = inputBuffer->S;
5521: cdb->PLAY_AUDIO_MSF.StartingF = inputBuffer->F;
5522: cdb->PLAY_AUDIO_MSF.EndingM = inputBuffer->M;
5523: cdb->PLAY_AUDIO_MSF.EndingS = inputBuffer->S;
5524: cdb->PLAY_AUDIO_MSF.EndingF = inputBuffer->F;
5525: status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
5526: &srb,
5527: NULL,
5528: 0,
5529: FALSE
5530: );
5531:
5532: if (NT_SUCCESS(status)) {
5533:
5534: deviceExtension->Paused = CDAUDIO_PAUSED;
5535: deviceExtension->PausedM = inputBuffer->M;
5536: deviceExtension->PausedS = inputBuffer->S;
5537: deviceExtension->PausedF = inputBuffer->F;
5538: deviceExtension->LastEndM = inputBuffer->M;
5539: deviceExtension->LastEndS = inputBuffer->S;
5540: deviceExtension->LastEndF = inputBuffer->F;
5541: CdDump(( 3,
5542: "CdAudio435DeviceControl: SEEK, Paused (%x %x %x) LastEnd (%x %x %x)\n",
5543: deviceExtension->PausedM,
5544: deviceExtension->PausedS,
5545: deviceExtension->PausedF,
5546: deviceExtension->LastEndM,
5547: deviceExtension->LastEndS,
5548: deviceExtension->LastEndF ));
5549:
5550: } else {
5551:
5552: CdDump(( 3,
5553: "CdAudio435DeviceControl: SEEK failed (0x%08lX)\n",
5554: status ));
5555:
5556: //
5557: // The CDS-435 drive returns STATUS_INVALID_DEVICE_REQUEST
5558: // when we ask to play an invalid address, so we need
5559: // to map to STATUS_NONEXISTENT_SECTOR in order to be
5560: // consistent with the other drives.
5561: //
5562:
5563: if (status==STATUS_INVALID_DEVICE_REQUEST) {
5564:
5565: status = STATUS_NONEXISTENT_SECTOR;
5566: }
5567:
5568: }
5569: }
5570: break;
5571:
5572: case IOCTL_CDROM_PAUSE_AUDIO:
5573: {
5574: PUCHAR SubQPtr =
5575: ExAllocatePool( NonPagedPoolCacheAligned,
5576: sizeof(SUB_Q_CHANNEL_DATA)
5577: );
5578:
5579: CdDump(( 3,
5580: "CdAudio435DeviceControl: IOCTL_CDROM_PAUSE_AUDIO received.\n"
5581: ));
5582:
5583: if (SubQPtr==NULL) {
5584:
5585: status = STATUS_INSUFFICIENT_RESOURCES;
5586: goto SetStatusAndReturn;
5587:
5588: }
5589:
5590: //
5591: // Enter pause (still ) mode
5592: //
5593:
5594: if (deviceExtension->Paused==CDAUDIO_PAUSED) {
5595:
5596: CdDump(( 3,
5597: "CdAudio435DeviceControl: PAUSE: Already Paused!\n"
5598: ));
5599:
5600: ExFreePool( SubQPtr );
5601: status = STATUS_SUCCESS;
5602: goto SetStatusAndReturn;
5603:
5604: }
5605:
5606: //
5607: // Since the CDS-435 doesn't have a pause mode,
5608: // we'll just record the current position and
5609: // stop the drive.
5610: //
5611:
5612: srb.CdbLength = 10;
5613: srb.TimeOutValue = AUDIO_TIMEOUT;
5614: cdb->SUBCHANNEL.OperationCode = CDS435_READ_SUB_Q_CHANNEL_CODE;
5615: cdb->SUBCHANNEL.Msf = 1;
5616: cdb->SUBCHANNEL.SubQ = 1;
5617: cdb->SUBCHANNEL.AllocationLength[1] = sizeof(SUB_Q_CHANNEL_DATA);
5618: status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
5619: &srb,
5620: SubQPtr,
5621: sizeof(SUB_Q_CHANNEL_DATA),
5622: FALSE
5623: );
5624: if (!NT_SUCCESS(status)) {
5625:
5626: CdDump(( 1,
5627: "CdAudio435DeviceControl: Pause, Read Q Channel failed (0x%lx)\n",
5628: status ));
5629: ExFreePool( SubQPtr );
5630: goto SetStatusAndReturn;
5631: }
5632:
5633: deviceExtension->PausedM = SubQPtr[9];
5634: deviceExtension->PausedS = SubQPtr[10];
5635: deviceExtension->PausedF = SubQPtr[11];
5636:
5637: //
5638: // now stop audio
5639: //
5640: RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
5641: srb.CdbLength = 10;
5642: srb.TimeOutValue = AUDIO_TIMEOUT;
5643: cdb->CDB10.OperationCode = CDS435_STOP_AUDIO_CODE;
5644: status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
5645: &srb,
5646: NULL,
5647: 0,
5648: FALSE
5649: );
5650: if (!NT_SUCCESS(status)) {
5651:
5652: CdDump(( 1,
5653: "CdAudio435DeviceControl: PAUSE, StopAudio failed! (0x%08lX)\n",
5654: status ));
5655: ExFreePool( SubQPtr );
5656: goto SetStatusAndReturn;
5657: }
5658:
5659: deviceExtension->PlayActive = FALSE;
5660:
5661: deviceExtension->Paused = CDAUDIO_PAUSED;
5662: deviceExtension->PausedM = SubQPtr[9];
5663: deviceExtension->PausedS = SubQPtr[10];
5664: deviceExtension->PausedF = SubQPtr[11];
5665:
5666: CdDump((3,
5667: "CdAudio435DeviceControl: PAUSE ==> Paused set to (%x %x %x)\n",
5668: deviceExtension->PausedM,
5669: deviceExtension->PausedS,
5670: deviceExtension->PausedF ));
5671:
5672: ExFreePool( SubQPtr );
5673: }
5674: break;
5675:
5676: case IOCTL_CDROM_RESUME_AUDIO:
5677:
5678: //
5679: // Resume cdrom
5680: //
5681:
5682: CdDump(( 3,
5683: "CdAudio435DeviceControl: IOCTL_CDROM_RESUME_AUDIO received.\n"
5684: ));
5685:
5686:
5687: //
5688: // Since the CDS-435 doesn't have a resume IOCTL,
5689: // we'll just start playing (if paused) from the
5690: // last recored paused position to the last recorded
5691: // "end of play" position.
5692: //
5693:
5694: if (deviceExtension->Paused==CDAUDIO_NOT_PAUSED) {
5695:
5696: status = STATUS_UNSUCCESSFUL;
5697: goto SetStatusAndReturn;
5698:
5699: }
5700:
5701: //
5702: // Fill in cdb for this operation
5703: //
5704:
5705: srb.CdbLength = 10;
5706: srb.TimeOutValue = AUDIO_TIMEOUT;
5707: cdb->PLAY_AUDIO_MSF.OperationCode = CDS435_PLAY_AUDIO_EXTENDED_CODE;
5708: cdb->PLAY_AUDIO_MSF.StartingM = deviceExtension->PausedM;
5709: cdb->PLAY_AUDIO_MSF.StartingS = deviceExtension->PausedS;
5710: cdb->PLAY_AUDIO_MSF.StartingF = deviceExtension->PausedF;
5711: cdb->PLAY_AUDIO_MSF.EndingM = deviceExtension->LastEndM;
5712: cdb->PLAY_AUDIO_MSF.EndingS = deviceExtension->LastEndS;
5713: cdb->PLAY_AUDIO_MSF.EndingF = deviceExtension->LastEndF;
5714: status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
5715: &srb,
5716: NULL,
5717: 0,
5718: FALSE
5719: );
5720:
5721: if (NT_SUCCESS(status)) {
5722:
5723: deviceExtension->PlayActive = TRUE;
5724:
5725: deviceExtension->Paused = CDAUDIO_NOT_PAUSED;
5726:
5727: } else {
5728:
5729: CdDump(( 1,
5730: "CdAudio435DeviceControl: RESUME (%x %x %x) - (%x %x %x) failed (0x%08lX)\n",
5731: deviceExtension->PausedM,
5732: deviceExtension->PausedS,
5733: deviceExtension->PausedF,
5734: deviceExtension->LastEndM,
5735: deviceExtension->LastEndS,
5736: deviceExtension->LastEndF,
5737: status ));
5738:
5739: }
5740: break;
5741:
5742: case IOCTL_CDROM_READ_Q_CHANNEL:
5743: {
5744: PSUB_Q_CURRENT_POSITION userPtr =
5745: Irp->AssociatedIrp.SystemBuffer;
5746: PUCHAR SubQPtr =
5747: ExAllocatePool( NonPagedPoolCacheAligned,
5748: sizeof(SUB_Q_CHANNEL_DATA)
5749: );
5750:
5751: CdDump(( 5,
5752: "CdAudio435DeviceControl: IOCTL_CDROM_READ_Q_CHANNEL received.\n"
5753: ));
5754:
5755: if (SubQPtr==NULL) {
5756:
5757: CdDump(( 1,
5758: "CdAudio435DeviceControl: READ_Q_CHANNEL, SubQPtr==NULL!\n"
5759: ));
5760:
5761: RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
5762: status = STATUS_INSUFFICIENT_RESOURCES;
5763: goto SetStatusAndReturn;
5764:
5765: }
5766:
5767: if ( ((PCDROM_SUB_Q_DATA_FORMAT)userPtr)->Format!=
5768: IOCTL_CDROM_CURRENT_POSITION) {
5769:
5770: CdDump(( 1,
5771: "CdAudio435DeviceControl: READ_Q_CHANNEL, illegal Format (%d)\n",
5772: ((PCDROM_SUB_Q_DATA_FORMAT)userPtr)->Format
5773: ));
5774:
5775: ExFreePool( SubQPtr );
5776: RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
5777: status = STATUS_UNSUCCESSFUL;
5778: goto SetStatusAndReturn;
5779: }
5780:
5781: //
5782: // Read audio play status
5783: //
5784:
5785: srb.CdbLength = 10;
5786: srb.TimeOutValue = AUDIO_TIMEOUT;
5787: cdb->SUBCHANNEL.OperationCode = CDS435_READ_SUB_Q_CHANNEL_CODE;
5788: cdb->SUBCHANNEL.Msf = 1;
5789: cdb->SUBCHANNEL.SubQ = 1;
5790: cdb->SUBCHANNEL.AllocationLength[1] = sizeof(SUB_Q_CHANNEL_DATA);
5791: status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
5792: &srb,
5793: SubQPtr,
5794: sizeof(SUB_Q_CHANNEL_DATA),
5795: FALSE
5796: );
5797: if (NT_SUCCESS(status)) {
5798:
5799: userPtr->Header.Reserved = 0;
5800:
5801: if (deviceExtension->Paused==CDAUDIO_PAUSED) {
5802:
5803: deviceExtension->PlayActive = FALSE;
5804: userPtr->Header.AudioStatus = AUDIO_STATUS_PAUSED;
5805:
5806: } else {
5807:
5808: if (SubQPtr[1] == 0x11) {
5809:
5810: deviceExtension->PlayActive = TRUE;
5811: userPtr->Header.AudioStatus = AUDIO_STATUS_IN_PROGRESS;
5812:
5813: } else {
5814:
5815: deviceExtension->PlayActive = FALSE;
5816: userPtr->Header.AudioStatus = AUDIO_STATUS_PLAY_COMPLETE;
5817:
5818: }
5819: }
5820:
5821: userPtr->Header.DataLength[0] = 0;
5822: userPtr->Header.DataLength[1] = 12;
5823:
5824: userPtr->FormatCode = 0x01;
5825: userPtr->Control = SubQPtr[5];
5826: userPtr->ADR = 0;
5827: userPtr->TrackNumber = BCD_TO_DEC(SubQPtr[6]);
5828: userPtr->IndexNumber = BCD_TO_DEC(SubQPtr[7]);
5829: userPtr->AbsoluteAddress[0] = 0;
5830: userPtr->AbsoluteAddress[1] = SubQPtr[9];
5831: userPtr->AbsoluteAddress[2] = SubQPtr[10];
5832: userPtr->AbsoluteAddress[3] = SubQPtr[11];
5833: userPtr->TrackRelativeAddress[0] = 0;
5834: userPtr->TrackRelativeAddress[1] = SubQPtr[13];
5835: userPtr->TrackRelativeAddress[2] = SubQPtr[14];
5836: userPtr->TrackRelativeAddress[3] = SubQPtr[15];
5837: Irp->IoStatus.Information = 16;
5838:
5839: } else {
5840:
5841: RtlZeroMemory( userPtr, sizeof(SUB_Q_CURRENT_POSITION) );
5842: CdDump(( 1,
5843: "CdAudio435DeviceControl: READ_Q_CHANNEL failed (0x%08lX)\n",
5844: status
5845: ));
5846:
5847:
5848: }
5849:
5850: ExFreePool( SubQPtr );
5851: }
5852: break;
5853:
5854: case IOCTL_CDROM_EJECT_MEDIA:
5855:
5856: //
5857: // Build cdb to eject cartridge
5858: //
5859:
5860: CdDump(( 3,
5861: "CdAudio435DeviceControl: IOCTL_CDROM_EJECT_MEDIA received.\n"
5862: ));
5863:
5864: srb.CdbLength = 10;
5865: srb.TimeOutValue = AUDIO_TIMEOUT;
5866: cdb->CDB10.OperationCode = CDS435_EJECT_CODE;
5867: status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
5868: &srb,
5869: NULL,
5870: 0,
5871: FALSE
5872: );
5873:
5874: deviceExtension->Paused = CDAUDIO_NOT_PAUSED;
5875: deviceExtension->PausedM = 0;
5876: deviceExtension->PausedS = 0;
5877: deviceExtension->PausedF = 0;
5878: deviceExtension->LastEndM = 0;
5879: deviceExtension->LastEndS = 0;
5880: deviceExtension->LastEndF = 0;
5881:
5882: break;
5883:
5884: case IOCTL_CDROM_GET_CONTROL:
5885: case IOCTL_CDROM_GET_VOLUME:
5886: case IOCTL_CDROM_SET_VOLUME:
5887: CdDump(( 3, "CdAudio435DeviceControl: Not Supported yet.\n" ));
5888: status = STATUS_INVALID_DEVICE_REQUEST;
5889: break;
5890:
5891: case IOCTL_CDROM_CHECK_VERIFY:
5892: //
5893: // Update the play active flag.
5894: //
5895:
5896: CdAudioIsPlayActive(DeviceObject);
5897:
5898: //
5899: // This normally uses the Test_Unit_Ready (TUR) command. The
5900: // CDS-435/431 respond to the TUR command with a status byte
5901: // of 0x08 to indicate that an audio play is in progress. That
5902: // looks like SCSISTAT_BUSY, so it ends up getting retried.
5903: // There are a couple of solutions:
5904: // a) install a class error handler that watches for
5905: // Status == STATUS_DEVICE_NOT_READY
5906: // and/or Srb->ScsiStatus = SCSISTAT_BUSY
5907: // and converts it to Status = STATUS_SUCCESS,
5908: // Srb->ScsiStatus = SCSISTAT_GOOD
5909: // This is considerably more general than really necessary,
5910: // since only the TUR command behaves this way.
5911: // b) use another command, like ReadSubQ to get the drive's status
5912: // (we don't need to transfer any data, i.e. allocation length
5913: // = 0)
5914: //
5915:
5916: CdDump(( 3, "CdAudio435DeviceControl: IOCTL_CDROM_CHECK_VERIFY received.\n"
5917: ));
5918:
5919: //
5920: // Read audio play status
5921: //
5922:
5923: srb.CdbLength = 10;
5924: srb.TimeOutValue = AUDIO_TIMEOUT;
5925: cdb->SUBCHANNEL.OperationCode = CDS435_READ_SUB_Q_CHANNEL_CODE;
5926: cdb->SUBCHANNEL.Msf = 1;
5927: cdb->SUBCHANNEL.SubQ = 1;
5928: status = ScsiClassSendSrbSynchronous( deviceExtension->DeviceObject,
5929: &srb,
5930: NULL,
5931: 0,
5932: FALSE
5933: );
5934: break;
5935:
5936: default:
5937:
5938: CdDump((5,"CdAudio435DeviceControl: Unsupported device IOCTL\n"));
5939: return CdAudioSendToNextDriver( DeviceObject, Irp );
5940: break;
5941:
5942: } // end switch( IOCTL )
5943:
5944: SetStatusAndReturn:
5945: //
5946: // set status code and return
5947: //
5948:
5949: if (status == STATUS_VERIFY_REQUIRED) {
5950:
5951: IoSetHardErrorOrVerifyDevice( Irp,
5952: deviceExtension->TargetDeviceObject
5953: );
5954:
5955: Irp->IoStatus.Information = 0;
5956: }
5957:
5958: Irp->IoStatus.Status = status;
5959: IoCompleteRequest(Irp, IO_NO_INCREMENT);
5960: return status;
5961:
5962: }
5963:
5964: #if DBG
5965: VOID
5966: CdAudioDebugPrint(
5967: ULONG DebugPrintLevel,
5968: PCCHAR DebugMessage,
5969: ...
5970: )
5971:
5972: /*++
5973:
5974: Routine Description:
5975:
5976: Debug print for CdAudio driver
5977:
5978: Arguments:
5979:
5980: Debug print level between 0 and 3, with 3 being the most verbose.
5981:
5982: Return Value:
5983:
5984: None
5985:
5986: --*/
5987:
5988: {
5989: va_list ap;
5990:
5991: va_start( ap, DebugMessage );
5992:
5993: if (DebugPrintLevel <= CdAudioDebug) {
5994:
5995: char buffer[128];
5996:
5997: vsprintf(buffer, DebugMessage, ap);
5998: DbgPrint(buffer);
5999: }
6000:
6001: va_end(ap);
6002:
6003: } // end CdAudioDebugPrint
6004:
6005: #endif // DBG
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.