📄 cdaudio.c
字号:
This routine is called by the I/O subsystem for device controls.
Arguments:
DeviceObject
Irp
Return Value:
NTSTATUS
--*/
{
PCD_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
NTSTATUS status;
switch ( deviceExtension->Active ) {
case CDAUDIO_SEARCH_ACTIVE:
//
// This occurs while we have not finished StartDevice()
//
status = CdAudioSendToNextDriver( DeviceObject, Irp );
break;
case CDAUDIO_NOT_ACTIVE:
CdDump(( 3,
"DeviceControl => NOT ACTIVE for this drive.\n"
));
status = CdAudioSendToNextDriver( DeviceObject, Irp );
break;
case CDAUDIO_NEC:
status = CdAudioNECDeviceControl( DeviceObject, Irp );
break;
case CDAUDIO_PIONEER:
case CDAUDIO_PIONEER624:
status = CdAudioPioneerDeviceControl( DeviceObject, Irp );
break;
case CDAUDIO_DENON:
status = CdAudioDenonDeviceControl( DeviceObject, Irp );
break;
case CDAUDIO_FUJITSU:
case CDAUDIO_HITACHI:
status = CdAudioHitachiDeviceControl( DeviceObject, Irp );
break;
case CDAUDIO_CDS535:
status = CdAudio535DeviceControl( DeviceObject, Irp );
break;
case CDAUDIO_CDS435:
status = CdAudio435DeviceControl( DeviceObject, Irp );
break;
case CDAUDIO_ATAPI:
status = CdAudioAtapiDeviceControl( DeviceObject, Irp );
break;
case CDAUDIO_HPCDR:
status = CdAudioHPCdrDeviceControl( DeviceObject, Irp );
break;
default:
// LOGLOG
CdDump(( 0,
"DeviceControl !! Active==UNKNOWN %x\n",
deviceExtension->Active
));
ASSERT(FALSE);
deviceExtension->Active = CDAUDIO_NOT_ACTIVE;
status = CdAudioSendToNextDriver( DeviceObject, Irp );
}
return status;
}
NTSTATUS
CdAudioSendToNextDriver(
PDEVICE_OBJECT DeviceObject,
PIRP Irp
)
/*++
Routine Description:
This routine is sends the Irp to the next driver in line
when the Irp is not processed by this driver.
Arguments:
DeviceObject
Irp
Return Value:
NTSTATUS
--*/
{
PCD_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(deviceExtension->TargetDeviceObject, Irp);
}
BOOLEAN
CdAudioIsPlayActive(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
This routine determines if the cd is currently playing music.
Arguments:
DeviceObject - Device object to test.
Return Value:
TRUE if the device is playing music.
--*/
{
PCD_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PIRP irp;
IO_STATUS_BLOCK ioStatus;
KEVENT event;
NTSTATUS status;
PSUB_Q_CURRENT_POSITION currentBuffer;
BOOLEAN returnValue;
if (!deviceExtension->PlayActive) {
return(FALSE);
}
currentBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
sizeof(SUB_Q_CURRENT_POSITION));
if (currentBuffer == NULL) {
return(FALSE);
}
((PCDROM_SUB_Q_DATA_FORMAT) currentBuffer)->Format =
IOCTL_CDROM_CURRENT_POSITION;
((PCDROM_SUB_Q_DATA_FORMAT) currentBuffer)->Track = 0;
//
// Create notification event object to be used to signal the
// request completion.
//
KeInitializeEvent(&event, NotificationEvent, FALSE);
//
// Build the synchronous request to be sent to the port driver
// to perform the request.
//
irp = IoBuildDeviceIoControlRequest(IOCTL_CDROM_READ_Q_CHANNEL,
deviceExtension->DeviceObject,
currentBuffer,
sizeof(CDROM_SUB_Q_DATA_FORMAT),
currentBuffer,
sizeof(SUB_Q_CURRENT_POSITION),
FALSE,
&event,
&ioStatus);
if (irp == NULL) {
ExFreePool(currentBuffer);
return FALSE;
}
//
// Pass request to port driver and wait for request to complete.
//
status = IoCallDriver(deviceExtension->DeviceObject, irp);
if (status == STATUS_PENDING) {
KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
status = ioStatus.Status;
}
if (!NT_SUCCESS(status)) {
ExFreePool(currentBuffer);
return FALSE;
}
if (currentBuffer->Header.AudioStatus == AUDIO_STATUS_IN_PROGRESS) {
returnValue = TRUE;
} else {
returnValue = FALSE;
deviceExtension->PlayActive = FALSE;
}
ExFreePool(currentBuffer);
return(returnValue);
}
NTSTATUS
CdAudioNECDeviceControl(
PDEVICE_OBJECT DeviceObject,
PIRP Irp
)
/*++
Routine Description:
This routine is called by CdAudioDeviceControl to handle
audio IOCTLs sent to NEC cdrom drives.
Arguments:
DeviceObject
Irp
Return Value:
NTSTATUS
--*/
{
PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
PCD_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PCDROM_TOC cdaudioDataOut = Irp->AssociatedIrp.SystemBuffer;
SCSI_PASS_THROUGH srb;
PNEC_CDB cdb = (PNEC_CDB)srb.Cdb;
NTSTATUS status;
ULONG i,bytesTransfered;
PUCHAR Toc;
ULONG retryCount = 0;
ULONG address;
LARGE_INTEGER delay;
NECRestart:
//
// Clear out cdb
//
RtlZeroMemory( cdb, MAXIMUM_CDB_SIZE );
//
// What IOCTL do we need to execute?
//
switch (currentIrpStack->Parameters.DeviceIoControl.IoControlCode) {
case IOCTL_CDROM_GET_LAST_SESSION:
CdDump(( 2,
"NECDeviceControl => IOCTL_CDROM_GET_LAST_SESSION recv'd.\n"
));
//
// Ensure we have a large enough buffer?
//
if (currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength <
(ULONG)FIELD_OFFSET(CDROM_TOC, TrackData[1])) {
status = STATUS_BUFFER_TOO_SMALL;
// we have transferred zero bytes
Irp->IoStatus.Information = 0;
break;
}
//
// If the cd is playing music then reject this request.
//
if (CdAudioIsPlayActive(DeviceObject)) {
Irp->IoStatus.Information = 0;
status = STATUS_DEVICE_BUSY;
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;
}
//
// 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;
cdb->NEC_READ_TOC.TrackNumber = NEC_TOC_TYPE_SESSION;
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, status %lx\n",
status ));
ExFreePool( Toc );
Irp->IoStatus.Information = 0;
goto SetStatusAndReturn;
} else {
status = STATUS_SUCCESS;
}
//
// Translate data into our format.
//
bytesTransfered = FIELD_OFFSET(CDROM_TOC, TrackData[1]);
Irp->IoStatus.Information = bytesTransfered;
RtlZeroMemory(cdaudioDataOut, bytesTransfered);
cdaudioDataOut->Length[0] = (UCHAR)((bytesTransfered - 2) >> 8);
cdaudioDataOut->Length[1] = (UCHAR)((bytesTransfered - 2) & 0xFF);
//
// Determine if this is a multisession cd.
//
if (*((ULONG UNALIGNED *) &Toc[14]) == 0) {
//
// This is a single session disk. Just return.
//
ExFreePool(Toc);
break;
}
//
// Fake the session information.
//
cdaudioDataOut->FirstTrack = 1;
cdaudioDataOut->LastTrack = 2;
CdDump(( 4,
"NECDeviceControl => Tracks %d - %d, (%x bytes)\n",
cdaudioDataOut->FirstTrack,
cdaudioDataOut->LastTrack,
bytesTransfered
));
//
// Grab Information for the last session.
//
cdaudioDataOut->TrackData[0].Reserved = 0;
cdaudioDataOut->TrackData[0].Control =
((Toc[2] & 0x0F) << 4) | (Toc[2] >> 4);
cdaudioDataOut->TrackData[0].TrackNumber = 1;
cdaudioDataOut->TrackData[0].Reserved1 = 0;
//
// Convert the minutes, seconds and frames to an absolute block
// address. The formula comes from NEC.
//
address = (BCD_TO_DEC(Toc[15]) * 60 + BCD_TO_DEC(Toc[16])) * 75
+ BCD_TO_DEC(Toc[17]);
//
// Put the address in big-endian in the the user's TOC.
//
cdaudioDataOut->TrackData[0].Address[0] = (UCHAR) (address >> 24);
cdaudioDataOut->TrackData[0].Address[1] = (UCHAR) (address >> 16);
cdaudioDataOut->TrackData[0].Address[2] = (UCHAR) (address >> 8);
cdaudioDataOut->TrackData[0].Address[3] = (UCHAR) address;
//
// Free storage now that we've stored it elsewhere
//
ExFreePool( Toc );
break;
case IOCTL_CDROM_READ_TOC:
CdDump(( 2,
"NECDeviceControl => IOCTL_CDROM_READ_TOC recv'd.\n"
));
//
// If the cd is playing music then reject this request.
//
if (CdAudioIsPlayActive(DeviceObject)) {
status = STATUS_DEVICE_BUSY;
Irp->IoStatus.Information = 0;
break;
}
//
// Must have allocated at least enough buffer space
// to store how many tracks are on the disc
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -