📄 cdaudio.c
字号:
if (currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength <
((ULONG)FIELD_OFFSET(CDROM_TOC, TrackData[0]))
) {
status = STATUS_BUFFER_TOO_SMALL;
// we have transferred zero bytes
Irp->IoStatus.Information = 0;
break;
}
//
// Allocate storage to hold TOC from disc
//
Toc = (PUCHAR)ExAllocatePool( NonPagedPoolCacheAligned,
NEC_CDROM_TOC_SIZE
);
if ( Toc == NULL ) {
status = STATUS_INSUFFICIENT_RESOURCES;
Irp->IoStatus.Information = 0;
goto SetStatusAndReturn;
}
CdDump(( 4,
"NECDeviceControl => Toc = %p cdaudioDataOut = %p\n",
Toc, cdaudioDataOut
));
//
// Set up defaults
//
RtlZeroMemory( Toc, NEC_CDROM_TOC_SIZE );
srb.CdbLength = 10;
//
// Fill in CDB
//
cdb->NEC_READ_TOC.OperationCode = NEC_READ_TOC_CODE;
cdb->NEC_READ_TOC.Type = NEC_TRANSFER_WHOLE_TOC;
srb.TimeOutValue = AUDIO_TIMEOUT;
status = SendSrbSynchronous(
deviceExtension,
&srb,
Toc,
NEC_CDROM_TOC_SIZE
);
if (!NT_SUCCESS(status) && (status!=STATUS_DATA_OVERRUN)) {
CdDump(( 1,
"NECDeviceControl => READ_TOC error (%lx)\n",
status ));
if (status != STATUS_DATA_OVERRUN) {
CdDump(( 1, "NECDeviceControl => SRB ERROR (%lx)\n",
status ));
Irp->IoStatus.Information = 0;
ExFreePool( Toc );
goto SetStatusAndReturn;
}
} else {
status = STATUS_SUCCESS;
}
//
// Translate data into our format.
//
bytesTransfered =
currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength >
sizeof(CDROM_TOC) ?
sizeof(CDROM_TOC) :
currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
cdaudioDataOut->FirstTrack = BCD_TO_DEC(Toc[9]);
cdaudioDataOut->LastTrack = BCD_TO_DEC(Toc[19]);
CdDump(( 4,
"NECDeviceControl => Tracks %d - %d, (%x bytes)\n",
cdaudioDataOut->FirstTrack,
cdaudioDataOut->LastTrack,
bytesTransfered
));
//
// Return only N number of tracks, where N is the number of
// full tracks of info we can stuff into the user buffer
// if tracks from 1 to 2, that means there are two tracks,
// so let i go from 0 to 1 (two tracks of info)
//
{
//
// tracksToReturn == Number of real track info to return
// tracksInBuffer == How many fit into the user-supplied buffer
// tracksOnCd == Number of tracks on the CD (not including lead-out)
//
ULONG tracksToReturn;
ULONG tracksOnCd;
ULONG tracksInBuffer;
ULONG dataLength;
tracksOnCd = (cdaudioDataOut->LastTrack - cdaudioDataOut->FirstTrack) + 1;
dataLength = ((ULONG)FIELD_OFFSET(CDROM_TOC, TrackData[tracksOnCd])) - 2;
cdaudioDataOut->Length[0] = (UCHAR)(dataLength >> 8);
cdaudioDataOut->Length[1] = (UCHAR)(dataLength & 0xFF);
tracksInBuffer = currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength -
((ULONG)FIELD_OFFSET(CDROM_TOC, TrackData[0]));
tracksInBuffer /= sizeof(TRACK_DATA);
// take the lesser of the two
tracksToReturn = (tracksInBuffer < tracksOnCd) ?
tracksInBuffer :
tracksOnCd;
for( i=0; i < tracksToReturn; i++ ) {
//
// Grab Information for each track
//
cdaudioDataOut->TrackData[i].Reserved = 0;
cdaudioDataOut->TrackData[i].Control =
((Toc[(i*10)+32] & 0x0F) << 4) | (Toc[(i*10)+32] >> 4);
cdaudioDataOut->TrackData[i].TrackNumber =
(UCHAR)(i + cdaudioDataOut->FirstTrack);
cdaudioDataOut->TrackData[i].Reserved1 = 0;
cdaudioDataOut->TrackData[i].Address[0] = 0;
cdaudioDataOut->TrackData[i].Address[1] =
BCD_TO_DEC((Toc[(i*10)+39]));
cdaudioDataOut->TrackData[i].Address[2] =
BCD_TO_DEC((Toc[(i*10)+40]));
cdaudioDataOut->TrackData[i].Address[3] =
BCD_TO_DEC((Toc[(i*10)+41]));
CdDump(( 4,
"CdAudioNecDeviceControl: Track %d %d:%d:%d\n",
cdaudioDataOut->TrackData[i].TrackNumber,
cdaudioDataOut->TrackData[i].Address[1],
cdaudioDataOut->TrackData[i].Address[2],
cdaudioDataOut->TrackData[i].Address[3]
));
}
//
// Fake "lead out track" info
// Only if all tracks have been copied...
//
if ( tracksInBuffer > tracksOnCd ) {
cdaudioDataOut->TrackData[i].Reserved = 0;
cdaudioDataOut->TrackData[i].Control = 0x10;
cdaudioDataOut->TrackData[i].TrackNumber = 0xaa;
cdaudioDataOut->TrackData[i].Reserved1 = 0;
cdaudioDataOut->TrackData[i].Address[0] = 0;
cdaudioDataOut->TrackData[i].Address[1] = BCD_TO_DEC(Toc[29]);
cdaudioDataOut->TrackData[i].Address[2] = BCD_TO_DEC(Toc[30]);
cdaudioDataOut->TrackData[i].Address[3] = BCD_TO_DEC(Toc[31]);
CdDump(( 4,
"NECDeviceControl => Track %d %d:%d:%d\n",
cdaudioDataOut->TrackData[i].TrackNumber,
cdaudioDataOut->TrackData[i].Address[1],
cdaudioDataOut->TrackData[i].Address[2],
cdaudioDataOut->TrackData[i].Address[3]
));
i++;
}
Irp->IoStatus.Information = ((ULONG)FIELD_OFFSET(CDROM_TOC, TrackData[i]));
}
//
// Free storage now that we've stored it elsewhere
//
ExFreePool( Toc );
break;
case IOCTL_CDROM_STOP_AUDIO:
deviceExtension->PlayActive = FALSE;
//
// Same as scsi-2 spec, so just send to default driver
//
return CdAudioSendToNextDriver( DeviceObject, Irp );
break;
case IOCTL_CDROM_PLAY_AUDIO_MSF:
{
PCDROM_PLAY_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
CdDump(( 3,
"NECDeviceControl => IOCTL_CDROM_PLAY_AUDIO_MSF recv'd.\n"
));
if (currentIrpStack->Parameters.DeviceIoControl.InputBufferLength <
sizeof(CDROM_PLAY_AUDIO_MSF)
) {
status = STATUS_INFO_LENGTH_MISMATCH;
Irp->IoStatus.Information = 0;
break;
}
//
// First, seek to Starting MSF and enter play mode.
//
srb.CdbLength = 10;
srb.TimeOutValue = AUDIO_TIMEOUT;
cdb->NEC_PLAY_AUDIO.OperationCode = NEC_AUDIO_TRACK_SEARCH_CODE;
cdb->NEC_PLAY_AUDIO.PlayMode = NEC_ENTER_PLAY_MODE;
cdb->NEC_PLAY_AUDIO.Minute = DEC_TO_BCD(inputBuffer->StartingM);
cdb->NEC_PLAY_AUDIO.Second = DEC_TO_BCD(inputBuffer->StartingS);
cdb->NEC_PLAY_AUDIO.Frame = DEC_TO_BCD(inputBuffer->StartingF);
cdb->NEC_PLAY_AUDIO.Control = NEC_TYPE_ATIME;
CdDump(( 3,
"NECDeviceControl => play start MSF is BCD(%x:%x:%x)\n",
cdb->NEC_PLAY_AUDIO.Minute,
cdb->NEC_PLAY_AUDIO.Second,
cdb->NEC_PLAY_AUDIO.Frame
));
status = SendSrbSynchronous(deviceExtension,
&srb,
NULL,
0
);
if (NT_SUCCESS(status)) {
//
// Indicate the play actition is active.
//
deviceExtension->PlayActive = TRUE;
//
// Now, set the termination point for the play operation
//
RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
cdb->NEC_PLAY_AUDIO.OperationCode = NEC_PLAY_AUDIO_CODE;
cdb->NEC_PLAY_AUDIO.PlayMode = NEC_PLAY_STEREO;
cdb->NEC_PLAY_AUDIO.Minute = DEC_TO_BCD(inputBuffer->EndingM);
cdb->NEC_PLAY_AUDIO.Second = DEC_TO_BCD(inputBuffer->EndingS);
cdb->NEC_PLAY_AUDIO.Frame = DEC_TO_BCD(inputBuffer->EndingF);
cdb->NEC_PLAY_AUDIO.Control = NEC_TYPE_ATIME;
CdDump(( 3,
"NECDeviceControl => play end MSF is BCD(%x:%x:%x)\n",
cdb->NEC_PLAY_AUDIO.Minute,
cdb->NEC_PLAY_AUDIO.Second,
cdb->NEC_PLAY_AUDIO.Frame
));
status = SendSrbSynchronous(
deviceExtension,
&srb,
NULL,
0
);
}
}
break;
case IOCTL_CDROM_SEEK_AUDIO_MSF:
{
PCDROM_SEEK_AUDIO_MSF inputBuffer = Irp->AssociatedIrp.SystemBuffer;
CdDump(( 3,
"NECDeviceControl => IOCTL_CDROM_SEEK_AUDIO_MSF recv'd.\n"
));
//
// Must have allocated at least enough buffer space
// to store how many tracks are on the disc
//
if (currentIrpStack->Parameters.DeviceIoControl.InputBufferLength <
sizeof(CDROM_SEEK_AUDIO_MSF)
) {
status = STATUS_INFO_LENGTH_MISMATCH;
Irp->IoStatus.Information = 0;
break;
}
//
// seek to MSF and enter pause (still) mode.
//
srb.CdbLength = 10;
srb.TimeOutValue = AUDIO_TIMEOUT;
cdb->NEC_SEEK_AUDIO.OperationCode = NEC_AUDIO_TRACK_SEARCH_CODE;
cdb->NEC_SEEK_AUDIO.Minute = DEC_TO_BCD(inputBuffer->M);
cdb->NEC_SEEK_AUDIO.Second = DEC_TO_BCD(inputBuffer->S);
cdb->NEC_SEEK_AUDIO.Frame = DEC_TO_BCD(inputBuffer->F);
cdb->NEC_SEEK_AUDIO.Control = NEC_TYPE_ATIME;
CdDump(( 4,
"NECDeviceControl => seek MSF is %d:%d:%d\n",
cdb->NEC_SEEK_AUDIO.Minute,
cdb->NEC_SEEK_AUDIO.Second,
cdb->NEC_SEEK_AUDIO.Frame
));
status = SendSrbSynchronous(
deviceExtension,
&srb,
NULL,
0
);
}
break;
case IOCTL_CDROM_PAUSE_AUDIO:
CdDump(( 3,
"NECDeviceControl => IOCTL_CDROM_PAUSE_AUDIO recv'd.\n"
));
deviceExtension->PlayActive = FALSE;
//
// Enter pause (still ) mode
//
srb.CdbLength = 10;
srb.TimeOutValue = AUDIO_TIMEOUT;
cdb->NEC_PAUSE_AUDIO.OperationCode = NEC_STILL_CODE;
status = SendSrbSynchronous(
deviceExtension,
&srb,
NULL,
0
);
break;
case IOCTL_CDROM_RESUME_AUDIO:
CdDump(( 3,
"NECDeviceControl => IOCTL_CDROM_RESUME_AUDIO recv'd.\n"
));
//
// Resume play
//
srb.CdbLength = 10;
srb.TimeOutValue = AUDIO_TIMEOUT;
cdb->NEC_PLAY_AUDIO.OperationCode = NEC_PLAY_AUDIO_CODE;
cdb->NEC_PLAY_AUDIO.PlayMode = NEC_PLAY_STEREO;
cdb->NEC_PLAY_AUDIO.Control = NEC_TYPE_NO_CHANGE;
status = SendSrbSynchronous(
deviceExtension,
&srb,
NULL,
0
);
break;
case IOCTL_CDROM_READ_Q_CHANNEL:
{
PSUB_Q_CURRENT_POSITION userPtr =
Irp->AssociatedIrp.SystemBuffer;
PUCHAR SubQPtr =
ExAllocatePool( NonPagedPoolCacheAligned,
NEC_Q_CHANNEL_TRANSFER_SIZE
);
if (currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(SUB_Q_CURRENT_POSITION)
) {
status = STATUS_BUFFER_TOO_SMALL;
// we have transferred zero bytes
Irp->IoStatus.Information = 0;
if (SubQPtr) ExFreePool(SubQPtr);
break;
}
CdDump(( 5,
"NECDeviceControl => IOCTL_CDROM_READ_Q_CHANNEL recv'd.\n"
));
if (SubQPtr==NULL) {
CdDump(( 1,
"NECDeviceControl !! READ_Q_CHANNEL, SubQPtr==NULL!\n"
));
status = STATUS_INSUFFICIENT_RESOURCES;
Irp->IoStatus.Information = 0;
goto SetStatusAndReturn;
}
RtlZeroMemory( SubQPtr, NEC_Q_CHANNEL_TRANSFER_SIZE );
if ( ((PCDROM_SUB_Q_DATA_FORMAT)userPtr)->Format!=
IOCTL_CDROM_CURRENT_POSITION) {
CdDump((1,
"NECDeviceControl !! READ_Q_CHANNEL, illegal Format (%d)\n",
((PCDROM_SUB_Q_DATA_FORMAT)userPtr)->Format
));
ExFreePool( SubQPtr );
status = STATUS_UNSUCCESSFUL;
Irp->IoStatus.Information = 0;
goto SetStatusAndReturn;
}
NECSeek:
//
// Set up to read Q Channel
//
srb.CdbLength = 10;
srb.TimeOutValue = AUDIO_TIMEOUT;
cdb->NEC_READ_Q_CHANNEL.OperationCode = NEC_READ_SUB_Q_CHANNEL_CODE;
// Transfer Length
cdb->NEC_READ_Q_CHANNEL.TransferSize = NEC_Q_CHANNEL_TRANSFER_SIZE;
CdDump(( 4, "NECDeviceControl => cdb = %p srb = %p SubQPtr = %p\n",
cdb,
&srb,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -