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

📄 merlin.cpp

📁 完整的基于Conxant平台的USB电视棒的WIN驱动程序。
💻 CPP
📖 第 1 页 / 共 2 页
字号:


/////////////////////////////////////////////////////////////////////////////////////////
//Merlin::uploadFirmware
//
// This function is dependant on the Merlin firmware file being present as
// \\Windows\system32\drivers\MerlinD.rom
//
// The firmware file consists of the following structures:
// 2 byte address
// 4 byte data length
// data (data length bytes)
//
// We read from the file until there are no more structures.
//
NTSTATUS Merlin::uploadFirmware()
{
    HANDLE file_handle;
    NTSTATUS status = openFirmwareFile(&file_handle);

    if(NT_SUCCESS(status))
    {
        status = _p_registers->writeAudioFirmware(file_handle,_p_device->getRevID());
        ZwClose(file_handle);

//        // Uncomment the following lines if you want to verify firmware after upload
//        // verify every byte just for Debuging.
//        status = openFirmwareFile(&file_handle);
//        
//        if(NT_SUCCESS(status))
//        {
//            _p_registers->verifyAudioFirmware(file_handle);
//            ZwClose(file_handle);
//        }
//        else
//        {
//            DbgLogError(("Audio firmware file open failed for verify\n"));
//        }

    }
    else
    {
        DbgLogError(("Audio firmware file open failed for upload\n"));
    }


    return status;
}

VOID Merlin::initialize()
{
    NTSTATUS status = uploadFirmware();
    DbgLog(("Completed Merlin Firmware upload, status = %x\n", status));

    //////////////////
    //Initialize a few other registers necessary for audio functioning.

    _p_registers->lock();

    _p_registers->writeDword(I2S_IN_CTL, 0x000000A0);

    //Audio output control 1 is set to Sony mode
    //Audio output control 2 is set to 1 for master mode
    _p_registers->writeDword(I2S_OUT_CTL, 0x000001A0);

    _p_registers->writeDword(STD_DET_CTL, 0x000000F6);

    setAudioInput(_current_audio_input);

    //we can simply verify the FW version to tell whether FW is successfully downloaded.
    GetVersion();

    _p_registers->unlock();
}


/////////////////////////////////////////////////////////////////////////////////////////
VOID Merlin::setTVAudioMode(DWORD new_mode)
{
    _p_registers->lock();

    BYTE control_register;
    _p_registers->readByte(STD_DET_CTL_PREF_MODE, &control_register);
    control_register &= 0xF0;

    //If the user selected stereo, select it
    if(new_mode & KS_TVAUDIO_MODE_STEREO)
    {
        _tv_audio_preferred_mode = PREF_MODE_STEREO;
    }
    else
    {
        //If the user selected language B, select it
        if(new_mode & KS_TVAUDIO_MODE_LANG_B)
        {
            _tv_audio_preferred_mode = PREF_MODE_MONO_LANGB;
        }
        else if(new_mode & KS_TVAUDIO_MODE_LANG_C)
        {
            //Read the detected modes
            DWORD mode_detect_status;
            _p_registers->readDword(STD_DET_STATUS, &mode_detect_status);
            mode_detect_status &= 0xFF;

            if(mode_detect_status & DETECT_TRI)
            {
                _tv_audio_preferred_mode = PREF_MODE_MONO_LANGC;
            }
            else
            {
                _tv_audio_preferred_mode = PREF_MODE_DUAL_LANG_AB;
            }
        }
        else //Language A
        {
            //Make sure there is a selected language (to be checked when getting the current mode)
            _tv_audio_preferred_mode = PREF_MODE_MONO_LANGA;
        }
    }

    control_register |= _tv_audio_preferred_mode;
    _p_registers->writeByte(STD_DET_CTL_PREF_MODE, control_register);

    _p_registers->unlock();
}

/////////////////////////////////////////////////////////////////////////////////////////
DWORD Merlin::getCurrentMode()
{
    if(!((_current_audio_input == AUDIO_INPUT_TUNER_TV) || (_current_audio_input == AUDIO_INPUT_MUTE)))
    {
        return KS_TVAUDIO_MODE_STEREO | KS_TVAUDIO_MODE_LANG_A;
    }

    //Read the detected modes
    DWORD mode_detect_status;
    _p_registers->readDword(STD_DET_STATUS, &mode_detect_status);
    mode_detect_status &= 0xFF;

    DWORD current_mode;
    current_mode = KS_TVAUDIO_MODE_MONO | KS_TVAUDIO_MODE_LANG_A;

    switch(_tv_audio_preferred_mode)
    {
    case PREF_MODE_STEREO:
        if (mode_detect_status & DETECT_STEREO)
            current_mode = KS_TVAUDIO_MODE_STEREO | KS_TVAUDIO_MODE_LANG_A;
        break;
    case PREF_MODE_MONO_LANGB:
        if ((mode_detect_status & DETECT_DUAL) ||
            (mode_detect_status & DETECT_SAP) ||
            (mode_detect_status & DETECT_TRI))
            current_mode = KS_TVAUDIO_MODE_MONO | KS_TVAUDIO_MODE_LANG_B;
        else if (mode_detect_status & DETECT_STEREO)
            current_mode = KS_TVAUDIO_MODE_STEREO | KS_TVAUDIO_MODE_LANG_A;
        break;
    case PREF_MODE_MONO_LANGC:
        if (mode_detect_status & DETECT_TRI)
            current_mode = KS_TVAUDIO_MODE_MONO | KS_TVAUDIO_MODE_LANG_C;
        else if (mode_detect_status & DETECT_STEREO)
            current_mode = KS_TVAUDIO_MODE_STEREO | KS_TVAUDIO_MODE_LANG_A;
        break;
    case PREF_MODE_DUAL_LANG_AB:
        if ((mode_detect_status & DETECT_DUAL) ||
            (mode_detect_status & DETECT_SAP) ||
            (mode_detect_status & DETECT_TRI))
            current_mode = KS_TVAUDIO_MODE_MONO | KS_TVAUDIO_MODE_LANG_C;
        else if (mode_detect_status & DETECT_STEREO)
            current_mode = KS_TVAUDIO_MODE_STEREO | KS_TVAUDIO_MODE_LANG_A;
        break;
    case PREF_MODE_MONO_LANGA:
        break;
    default:
        break;
    }

    return current_mode;
}

/////////////////////////////////////////////////////////////////////////////////////////
DWORD Merlin::getAvailableModes()
{
    if(!((_current_audio_input == AUDIO_INPUT_TUNER_TV) || (_current_audio_input == AUDIO_INPUT_MUTE)))
    {
        return KS_TVAUDIO_MODE_STEREO | KS_TVAUDIO_MODE_LANG_A;
    }

    //Read the detected modes
    DWORD mode_detect_status;
    _p_registers->readDword(STD_DET_STATUS, &mode_detect_status);

    DbgLogInfo(("Merlin::getAvailableModes : \n\t\t status_reg = %x \n\t\t status & 0xFF = %x, Audio Standard = %x \n",
            mode_detect_status, mode_detect_status & 0xFF, _audio_standard ));

    if(((mode_detect_status >> 8) & 0xFF) == DETECT_NO_SIGNAL)
    {
        return KS_TVAUDIO_MODE_MONO | KS_TVAUDIO_MODE_LANG_A;
    }

    mode_detect_status &= 0xFF;

    DWORD available_modes = KS_TVAUDIO_MODE_MONO | KS_TVAUDIO_MODE_LANG_A;
    if(mode_detect_status & DETECT_STEREO)
    {
        available_modes |= KS_TVAUDIO_MODE_STEREO;
    }

    if((mode_detect_status & DETECT_SAP) || (mode_detect_status & DETECT_DUAL))
    {
         if((_audio_standard == AUDIO_STANDARD_BTSC) ||
            (_audio_standard == AUDIO_STANDARD_EIAJ) ||
            (_audio_standard == AUDIO_STANDARD_A2_M) ||
            (_audio_standard == AUDIO_STANDARD_NICAM_BG) ||
            (_audio_standard == AUDIO_STANDARD_NICAM_DK) ||
            (_audio_standard == AUDIO_STANDARD_NICAM_L) ||
            (_audio_standard == AUDIO_STANDARD_NICAM_I))
         {
            available_modes |= (KS_TVAUDIO_MODE_LANG_B | KS_TVAUDIO_MODE_LANG_C);
         }
         else
         {
            available_modes |= KS_TVAUDIO_MODE_LANG_B;
         }
    }

    if(mode_detect_status & DETECT_TRI)
    {
        available_modes |= (KS_TVAUDIO_MODE_LANG_B | KS_TVAUDIO_MODE_LANG_C);
    }

    return available_modes;
}
///////////////////////////////////////////////////////////////////////////////////
//
//  Our default is AUDIO_INPUT_LINE. Since this getCapabilities is called only
//  once when the graph is opened, if we change the input to Tuner, we are not
//  able to send the new info back to MS.
//  So for now, return everything.
//  If an App wants to know the current avaliable modes, it will call the
//  getAvailableModes function which returns the proper modes as reported by Merlin.
//
///////////////////////////////////////////////////////////////////////////////////
DWORD Merlin::getCapabilities()
{
//    if((_current_audio_input == AUDIO_INPUT_TUNER_TV) || (_current_audio_input == AUDIO_INPUT_MUTE))
//    {
        return KS_TVAUDIO_MODE_LANG_A |
            KS_TVAUDIO_MODE_LANG_B |
            KS_TVAUDIO_MODE_LANG_C |
            KS_TVAUDIO_MODE_STEREO |
            KS_TVAUDIO_MODE_MONO;
//    }
//    else //Line in
//    {
//        return KS_TVAUDIO_MODE_LANG_A |
//            KS_TVAUDIO_MODE_STEREO;
//    }
}

VOID Merlin::powerUp()
{
    DbgLog(("Merlin::powerUp\n"));
    setAudioInput(_current_audio_input);
}

VOID Merlin::powerDown()
{   //[todo] finish this
    DbgLog(("Merlin::powerDown\n"));    
}
VOID Merlin::notifyPreChannelChange()
{
    DbgLog(("Merlin::notifyPreChannelChange\n"));

    _p_registers->stopAudioFirmware(FIRMWARE_STOP_REASON_CHANNEL_CHANGE);
}

VOID Merlin::notifyPostChannelChange()
{
    DbgLog(("Merlin::notifyPostChannelChange\n"));
    _p_registers->restartAudioFirmware(FIRMWARE_STOP_REASON_CHANNEL_CHANGE);
}

VOID Merlin::GetVersion()
{
    UCHAR aud_fw_ver[2];

    DWORD std_ctrl_reg;
    DWORD dl_control = 0;
    int MajRevHi,MajRevLo,MinRevlo;

    // First save the old state
    _p_registers->readDword(DL_CTL, &dl_control);
    //Enable the firmware
    _p_registers->writeDword(DL_CTL, FLD_START_8051 | FLD_DL_MAP);

    _p_registers->readDword(STD_DET_CTL, &std_ctrl_reg);

    //Write 0x00 on Audio Configuration register address
    //and read from particular addresses to get the audio
    //firmware Version & Build number.
    _p_registers->writeByte(STD_DET_CTL_AUD_CTL, 0x00);

    sleep(50); // wait for 50 ms

    //Polaris remove this REG
    _p_registers->readByte(AUD_VER_NUM, &aud_fw_ver[0]);
    _p_registers->readByte(AUD_BUILD_NUM, &aud_fw_ver[1]);  

    MajRevHi = aud_fw_ver[0]>>4;
    MajRevLo = aud_fw_ver[0]&0xF;
    MinRevlo = aud_fw_ver[1];

    _audio_fw_version = (((USHORT)aud_fw_ver[0]) & 0x00ff) | ((((USHORT)aud_fw_ver[1]) << 8) & 0xff00);

    _p_registers->writeDword(STD_DET_CTL, std_ctrl_reg);

    //restore the state.
    _p_registers->writeDword(DL_CTL, dl_control);

    DbgLog(("Merlin Firmware version = %d.%d.%d\n",MajRevHi, MajRevLo, MinRevlo));

}

BOOLEAN Merlin::isFMLocked()
{
    BOOLEAN result = false;    
    DWORD status_reg = 0;
    sleep(50);
    
    _p_registers->readDword(STD_DET_STATUS, &status_reg);

    DWORD fmLock = (status_reg >> 8) & 0xff;  
        
    DbgLogInfo(("Merlin::isFMLocked : status_reg = %x FM Lock = %x \n", status_reg, fmLock));

    if(DETECT_FM_LOCKED == fmLock)
    {
        result = true;
    }

    return result;
}

VOID Merlin::setupFM()
{
    //the following is just the normal FM Radio Merlin setup script
    //except that it is modified to accept 5.5 MHz instead of 10.7 MHz IF   
    DWORD temp;
    //autoconfig to FM Radio w/ 75 us preemphasis
     _p_registers->readDword(AUTOCONFIG_REG, &temp);
    temp &= 0xFFFFFFF0;
    temp |= 0x00000001;
    _p_registers->writeDword(AUTOCONFIG_REG, temp);

    //set ROT1 to de-rotate 5.5 MHz carrier
    //5.5/16.111616 * 2^16 = 0x5763
     _p_registers->readDword(ANALOG_DEMOD_CTL, &temp);
    temp &= 0x0000FFFF;
    temp |= 0x57630000;
    _p_registers->writeDword(ANALOG_DEMOD_CTL, temp);

    //turn off AFC, turn off DC notch filter
     _p_registers->readDword(FM_CTL, &temp);
    temp &= 0xFF3FFF3F;
    temp |= 0x00C000C0;
    _p_registers->writeDword(FM_CTL, temp);

    //setup dematrix for FM Radio Mono
     _p_registers->readDword(DEMATRIX_CTL, &temp);
    temp &= 0xFF00FFFF; 
    temp |= 0x00800000;
    _p_registers->writeDword(DEMATRIX_CTL, temp);

    //put the Merlin IF SRC into lowpass mode rather than highpass mode
    _p_registers->writeDword(IF_SRC_CTL, 0x000031C0); 
    
}

⌨️ 快捷键说明

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