⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cdaudio.c

📁 The CD Audio sample allows some non-SCSI2 CD ROMs to support audio operations by intercepting the re
💻 C
📖 第 1 页 / 共 5 页
字号:

/*++

Routine Description:

    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, Executive, 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;
        }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -