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

📄 miniport.cpp

📁 winddk src目录下的WDM源码压缩!
💻 CPP
📖 第 1 页 / 共 5 页
字号:
            if (PropertyRequest->PropertyItem->Id == KSPROPERTY_AUDIO_VOLUMELEVEL)
            {
                ntStatus = BasicSupportHandler(PropertyRequest);
            }
        }   // (Verb & KSPROPERTY_TYPE_BASICSUPPORT) 
    }     // (Node == eFMVolumeNode)

    return ntStatus;
}

#pragma code_seg()
// convert from 16.16 dB to [0,63], set m_wSynthAttenR
void 
CMiniportMidiStreamFM::
SetFMAtten
(
    IN LONG channel, 
    IN LONG level
)
{
    KIRQL   oldIrql;
    if ((channel == CHAN_LEFT) || (channel == CHAN_MASTER))
    {
        m_SavedVolValue[CHAN_LEFT] = level;

        if (level > m_MaxVolValue)
            m_wSynthAttenL = 0;
        else if (level < m_MinVolValue)
            m_wSynthAttenL = 63;
        else
            m_wSynthAttenL = WORD(-level / (LONG)m_VolStepDelta);
    }
    if ((channel == CHAN_RIGHT) || (channel == CHAN_MASTER))
    {
        m_SavedVolValue[CHAN_RIGHT] = level;
    
        if (level > m_MaxVolValue)
            m_wSynthAttenR = 0;
        else if (level < m_MinVolValue)
            m_wSynthAttenR = 63;
        else
            m_wSynthAttenR = WORD(-level / (LONG)m_VolStepDelta);
    }
#ifdef USE_KDPRINT
    KdPrint(("'StreamFM::SetFMAtten: channel: 0x%X, level: 0x%X, m_wSynthAttenL: 0x%X, m_wSynthAttenR: 0x%X \n",
                                     channel,       level,       m_wSynthAttenL,       m_wSynthAttenR));
#else   //  USE_KDPRINT
    _DbgPrintF(DEBUGLVL_VERBOSE,("StreamFM::SetFMAtten: channel: 0x%X, level: 0x%X, m_wSynthAttenL: 0x%X, m_wSynthAttenR: 0x%X \n",
                                                        channel,       level,       m_wSynthAttenL,       m_wSynthAttenR));
#endif  //  USE_KDPRINT

    KeAcquireSpinLock(&m_Miniport->m_SpinLock,&oldIrql);
    Opl3_SetVolume(0xFF); //  0xFF means all channels
    KeReleaseSpinLock(&m_Miniport->m_SpinLock,oldIrql);
}

#pragma code_seg("PAGE")
/*****************************************************************************
 * PropertyHandler_CpuResources()
 *****************************************************************************
 * Processes a KSPROPERTY_AUDIO_CPU_RESOURCES request
 */
static
NTSTATUS PropertyHandler_CpuResources
(
    IN  PPCPROPERTY_REQUEST   PropertyRequest
)
{
    PAGED_CODE();

    ASSERT(PropertyRequest);

    _DbgPrintF(DEBUGLVL_VERBOSE,("PropertyHandler_CpuResources"));

    NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;

    // validate node
    if(PropertyRequest->Node == eFMVolumeNode)
    {
        if(PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
        {
            if(PropertyRequest->ValueSize >= sizeof(LONG))
            {
                *(PLONG(PropertyRequest->Value)) = KSAUDIO_CPU_RESOURCES_NOT_HOST_CPU;
                PropertyRequest->ValueSize = sizeof(LONG);
                ntStatus = STATUS_SUCCESS;
            } 
            else
            {
                _DbgPrintF(DEBUGLVL_VERBOSE,("PropertyHandler_CpuResources failed, buffer too small"));
                ntStatus = STATUS_BUFFER_TOO_SMALL;
            }
        }
    }
    return ntStatus;
}

#pragma code_seg()
// ==============================================================================
// SoundMidiSendFM
//  Writes out to the device.
//  Called from DPC code (Write->WriteMidiData->Opl3_NoteOn->Opl3_FMNote->here)
// ==============================================================================
void 
CMiniportMidiFM::
SoundMidiSendFM
(
IN    PUCHAR PortBase,
IN    ULONG Address,
IN    UCHAR Data
)
{
    ASSERT(Address < 0x200);
    ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);

    // these delays need to be 23us at least for old opl2 chips, even
    // though new chips can handle 1 us delays.

#ifdef USE_KDPRINT
    KdPrint(("'SoundMidiSendFM(%02x %02x) \n",Address,Data));
#else   //  USE_KDPRINT
    _DbgPrintF(DEBUGLVL_VERBOSE, ("%X\t%X", Address,Data));
#endif  //  USE_KDPRINT
    WRITE_PORT_UCHAR(PortBase + (Address < 0x100 ? 0 : 2), (UCHAR)Address);
    KeStallExecutionProcessor(23);

    WRITE_PORT_UCHAR(PortBase + (Address < 0x100 ? 1 : 3), Data);
    KeStallExecutionProcessor(23);

    m_SavedRegValues[Address] = Data;
}


#pragma code_seg()
// ==============================================================================
// Service()
// DPC-mode service call from the port.
// ==============================================================================
STDMETHODIMP_(void) 
CMiniportMidiFM::
Service
(   void
)
{
}

#pragma code_seg()
// ==============================================================================
// CMiniportMidiStreamFM::Read()
// Reads incoming MIDI data.
// ==============================================================================
STDMETHODIMP_(NTSTATUS)
CMiniportMidiStreamFM::
Read
(
    IN      PVOID   BufferAddress,
    IN      ULONG   Length,
    OUT     PULONG  BytesRead
)
{
    return STATUS_NOT_IMPLEMENTED;
}

#pragma code_seg()
// ==============================================================================
// CMiniportMidiStreamFM::Write()
// Writes outgoing MIDI data.  
// 
// N.B.!!!
// THIS DATA SINK ASSUMES THAT DATA COMES IN ONE MESSAGE AT A TIME!!!
// IF LENGTH IS MORE THAN THREE BYTES, SUCH AS SYSEX OR MULTIPLE MIDI 
// MESSAGES, ALL THE DATA IS DROPPED UNCEREMONIOUSLY ON THE FLOOR!!!
// ALSO DOES NOT PLAY WELL WITH RUNNING STATUS!!!
// 
// CLEARLY, THIS MINIPORT HAS SOME "ISSUES".
//
// ==============================================================================
STDMETHODIMP_(NTSTATUS)
CMiniportMidiStreamFM::
Write
(
    IN      PVOID   BufferAddress,  // pointer to Midi Data.
    IN      ULONG   Length,
    OUT     PULONG  BytesWritten
)
{
    ASSERT(BufferAddress);
    ASSERT(BytesWritten);

    _DbgPrintF(DEBUGLVL_VERBOSE, ("CMiniportMidiStreamFM::Write"));

    BYTE    statusByte = *(PBYTE)BufferAddress & 0xF0;
    *BytesWritten = Length;
    
    if (statusByte < 0x80)
    {
        _DbgPrintF(DEBUGLVL_TERSE, ("CMiniportMidiStreamFM::Write requires first byte to be status -- ignored"));
    }
    else if (statusByte == 0xF0)
    {
        _DbgPrintF(DEBUGLVL_VERBOSE, ("StreamFM::Write doesn't handle System messages -- ignored"));
    }
    else if (statusByte == 0xA0)
    {
        _DbgPrintF(DEBUGLVL_VERBOSE, ("StreamFM::Write doesn't handle Polyphonic key pressure/Aftertouch messages -- ignored"));
    }
    else if (statusByte == 0xD0)
    {
        _DbgPrintF(DEBUGLVL_VERBOSE, ("StreamFM::Write doesn't handle Channel pressure/Aftertouch messages -- ignored"));
    }
    else if (Length < 4)
    {
        WriteMidiData(*(DWORD *)BufferAddress);
    }
    else 
    {
        _DbgPrintF(DEBUGLVL_TERSE, ("StreamFM::Write doesn't handle Length > 3."));
    }   
    return STATUS_SUCCESS;
}

// ==============================================================================
// ==============================================================================
// Private Methods of CMiniportMidiFM
// ==============================================================================
// ==============================================================================


#pragma code_seg()
// =================================================================
// SoundMidiIsOpl3
// Checks if the midi synthesizer is Opl3 compatible or just adlib-compatible.
// returns:  TRUE if OPL3-compatible chip. FALSE otherwise.
//
// NOTE: This has been taken as is from the nt driver code.
// =================================================================
BOOL CMiniportMidiFM::
SoundMidiIsOpl3(void)
{
    ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);

    BOOL bIsOpl3 = FALSE;

    /*
     * theory: an opl3-compatible synthesizer chip looks
     * exactly like two separate 3812 synthesizers (for left and right
     * channels) until switched into opl3 mode. Then, the timer-control
     * register for the right half is replaced by a channel connection register
     * (among other changes).
     *
     * We can detect 3812 synthesizers by starting a timer and looking for
     * timer overflow. So if we find 3812s at both left and right addresses,
     * we then switch to opl3 mode and look again for the right-half. If we
     * still find it, then the switch failed and we have an old synthesizer
     * if the right half disappeared, we have a new opl3 synthesizer.
     *
     * NB we use either monaural base-level synthesis, or stereo opl3
     * synthesis. If we discover two 3812s (as on early SB Pro and
     * PAS), we ignore one of them.
     */

    /*
     * nice theory - but wrong. The timer on the right half of the
     * opl3 chip reports its status in the left-half status register.
     * There is no right-half status register on the opl3 chip.
     */


    /* ensure base mode */
    SoundMidiSendFM(m_PortBase, AD_NEW, 0x00);
    KeStallExecutionProcessor(20);

    /* look for right half of chip */
    if (SoundSynthPresent(m_PortBase + 2, m_PortBase))
    {
        /* yes - is this two separate chips or a new opl3 chip ? */
        /* switch to opl3 mode */
        SoundMidiSendFM(m_PortBase, AD_NEW, 0x01);
        KeStallExecutionProcessor(20);

        if (!SoundSynthPresent(m_PortBase + 2, m_PortBase))
        {
            _DbgPrintF(DEBUGLVL_VERBOSE, ("CMiniportMidiFM: In SoundMidiIsOpl3 right half disappeared"));
            /* right-half disappeared - so opl3 */
            bIsOpl3 = TRUE;
        }
    }

    if (!bIsOpl3)
    {
        /* reset to 3812 mode */
        SoundMidiSendFM(m_PortBase, AD_NEW, 0x00);
        KeStallExecutionProcessor(20);
    }

    _DbgPrintF(DEBUGLVL_VERBOSE, ("CMiniportMidiFM: In SoundMidiIsOpl3 returning bIsOpl3 = 0x%X", bIsOpl3));
    return(bIsOpl3);
}

#pragma code_seg()
// ==============================================================================
// SoundSynthPresent
//
// Detect the presence or absence of a 3812 (opl2/adlib-compatible) synthesizer
// at the given i/o address by starting the timer and looking for an
// overflow. Can be used to detect left and right synthesizers separately.
//
// Returns: True if a synthesiser is present at that address and false if not.
//
// NOTE: This and has been taken as is from the nt driver code.
// ==============================================================================
BOOL
CMiniportMidiFM::
SoundSynthPresent
(
IN PUCHAR   base,
IN PUCHAR inbase
)
{
    ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);

    UCHAR t1, t2;
    // check if the chip is present
    SoundMidiSendFM(base, 4, 0x60);             // mask T1 & T2
    SoundMidiSendFM(base, 4, 0x80);             // reset IRQ

    t1 = READ_PORT_UCHAR((PUCHAR)inbase);       // read status register

    SoundMidiSendFM(base, 2, 0xff);             // set timer - 1 latch
    SoundMidiSendFM(base, 4, 0x21);             // unmask & start T1

    // this timer should go off in 80 us. It sometimes
    // takes more than 100us, but will always have expired within
    // 200 us if it is ever going to.
    KeStallExecutionProcessor(200);

    t2 = READ_PORT_UCHAR((PUCHAR)inbase);       // read status register

    SoundMidiSendFM(base, 4, 0x60);
    SoundMidiSendFM(base, 4, 0x80);

    if (!((t1 & 0xE0) == 0) || !((t2 & 0xE0) == 0xC0))
    {
        _DbgPrintF(DEBUGLVL_VERBOSE, ("SoundSynthPresent: returning false"));
        return(FALSE);
    }
    _DbgPrintF(DEBUGLVL_VERBOSE, ("SoundSynthPresent: returning true"));
    return TRUE;
}


// ==============================================================================
// this array gives the offsets of the slots within an opl2
// chip. This is needed to set the attenuation for all slots to max,
// to ensure that the chip is silenced completely - switching off the
// voices alone will not do this.
// ==============================================================================
BYTE offsetSlot[] =
{
    0, 1, 2, 3, 4, 5,
    8, 9, 10, 11, 12, 13,
    16, 17, 18, 19, 20, 21
};

#pragma code_seg()
// =========================================================================
// WriteMidiData
//      Converts a MIDI atom into the corresponding FM transaction.
// =========================================================================
void
CMiniportMidiStreamFM::
WriteMidiData(DWORD dwData)
{
    BYTE    bMsgType,bChannel, bVelocity, bNote;
    WORD    wTemp;
    KIRQL   oldIrql;

    bMsgType = (BYTE) dwData & (BYTE)0xf0;
    bChannel = (BYTE) dwData & (BYTE)0x0f;
    bNote = (BYTE) ((WORD) dwData >> 8) & (BYTE)0x7f;
    bVelocity = (BYTE) (dwData >> 16) & (BYTE)0x7f;
    
#ifdef USE_KDPRINT
    KdPrint(("'StreamFM::WriteMidiData: (%x %x %x) \n",bMsgType+bChannel,bNote,bVelocity));
#else   //  USE_KDPRINT
    _DbgPrintF(DEBUGLVL_VERBOSE,("StreamFM::WriteMidiData: (%x %x %x) \n",bMsgType+bChannel,bNote,bVelocity));
#endif  //  USE_KDPRINT
    KeAcquireSpinLock(&m_Miniport->m_SpinLock,&oldIrql);
    switch (bMsgType)
    {
        case 0x90:      /* turn key on, or key off if volume == 0 */
            if (bVelocity)
            {
                if (bChannel == DRUMCHANNEL)
                {
                    Opl3_NoteOn((BYTE)(bNote + 128),bNote,bChannel,bVelocity,(short)m_iBend[bChannel]);
                }
                else
                {
                    Opl3_NoteOn((BYTE)m_bPatch[bChannel],bNote,bChannel,bVelocity,(short) m_iBend[bChannel]);

⌨️ 快捷键说明

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