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

📄 colibri.cpp

📁 完整的基于Conxant平台的USB电视棒的WIN驱动程序。
💻 CPP
字号:
/*+++ *******************************************************************\ 
* 
*  Copyright and Disclaimer: 
*  
*     --------------------------------------------------------------- 
*     This software is provided "AS IS" without warranty of any kind, 
*     either expressed or implied, including but not limited to the 
*     implied warranties of noninfringement, merchantability and/or 
*     fitness for a particular purpose.
*     --------------------------------------------------------------- 
*   
*     Copyright (c) 2008 Conexant Systems, Inc. 
*     All rights reserved. 
*
\******************************************************************* ---*/ 
#include "colibri.h"
#include "miscfuncs.h"
#include "debug.h"

Colibri::Colibri(DriverI2C* p_i2c, void* p_DIF):
_p_i2c(p_i2c)
{
    KeInitializeMutex(&_mutex, 0);
    _p_DIF = (DirectIF *)p_DIF;
}
Colibri::~Colibri()
{

}

VOID Colibri::lock()
{
    KeWaitForSingleObject(&_mutex, Executive, KernelMode, FALSE, NULL );
}

/////////////////////////////////////////////////////////////////////////////////////////
VOID Colibri::unlock()
{
    KeReleaseMutex(&_mutex, FALSE);
}

VOID Colibri::initialize()
{    
    initSuperBlock();
    initChannels();    
}

VOID Colibri::SetupAFEforLowIF()
{   
    RegMaskWrite(8, ADC_STATUS2_CH3, 0, 0, 1); // clear the stab flag latch
    RegMaskWrite(8, ADC_PWRDN_CLAMP_CH2, 4, 6, 0x7); //pwr down ch2

    // config colibri to lo-if mode
    // FIXME: ntf_mode = 2'b00 by default. But set 0x1 would reduce the diff IF input by half, 
    //        for low-if agc defect
    RegMaskWrite(8, ADC_NTF_PRECLMP_EN_CH3, 0, 1, 0x0); // ntf_mode = 2'b0
    RegMaskWrite(8, ADC_INPUT_CH3, 1, 2, 0x1); // input_mode = 2'b1
    RegMaskWrite(8, ADC_FB_FRCRST_CH3, 2, 2, 0x1); // fb_mode = 1'b1
    RegMaskWrite(8, ADC_DCSERVO_DEM_CH3, 0, 1, 0x3); // clk_inv = dem_off = 1'b1
    RegMaskWrite(8, ADC_CTRL_DAC1_CH3, 2, 2, 0x1); // ctrl_dac1 = 1'b1
    RegMaskWrite(8, ADC_CTRL_DAC23_CH3 , 0, 2, 0x6); // ctrl_dac2 = 3'b6
    RegMaskWrite(8, ADC_CTRL_DAC23_CH3, 4, 6, 0x4); // ctrl_dac3 = 3'b4
    RegMaskWrite(8, ADC_PWRDN_CLAMP_CH3, 5, 5, 0x1); // pd_buffer = 1'b1

}

VOID Colibri::SetupAFEforBaseband()
{   
    BYTE c_value = 0;
    readByte(ADC_PWRDN_CLAMP_CH2, &c_value);
    c_value &= (~(0x50));
    writeByte(ADC_PWRDN_CLAMP_CH2, c_value);
}

VOID Colibri::SetupAFEforHiIF()
{
    //todo:ask Alsor for Hi-IF settings
}

VOID Colibri::initializeAudioInputTunerTv()
{
    RegMaskWrite(8, ADC_INPUT_CH1, 4, 5, 0x3);
    RegMaskWrite(8, ADC_INPUT_CH3, 4, 5, 0x1);
    RegMaskWrite(8, ADC_PWRDN_CLAMP_CH2, 4, 6, 0x7); //pwr down ch2
}

NTSTATUS Colibri::RegMaskWrite(BYTE size, WORD register_address,BYTE bit_start,BYTE bit_end, DWORD value)
{

    if (bit_start>(size-1) || bit_end>(size-1))
    {
        return STATUS_UNSUCCESSFUL;
    }

    CHAR tmp[4] = {0,};
    NTSTATUS status = STATUS_SUCCESS;
    if (size==8)
    {
        status = readByte(register_address, (PBYTE)tmp);
    }
    else
    {
        status = readDword(register_address, (PDWORD)tmp);
    }

    if (!NT_SUCCESS(status))
    {
        return status;
    }

    DWORD mask = 1<<bit_end;
    for (int i=bit_end; i>bit_start&&i>0; i--)
    {
        mask = mask + (1<<(i-1));
    }

    value <<= bit_start;

    if (size==8)
    {
        (*(PBYTE)tmp) = (*(PBYTE)tmp) & ((BYTE)~mask);
        (*(PBYTE)tmp) = (*(PBYTE)tmp) | ((BYTE)value);
        status = writeByte(register_address, (*(PBYTE)tmp));
    }
    else
    {
        (*(PDWORD)tmp) = (*(PDWORD)tmp) & ((DWORD)~mask);
        (*(PDWORD)tmp) = (*(PDWORD)tmp) | ((DWORD)value);
        status = writeDword(register_address, (*(PDWORD)tmp));
    }

    return status;
}

/////////////////////////////////////////////////////////////////////////////////////////
NTSTATUS Colibri::readByte(WORD register_address, PBYTE p_value)
{
    lock();

    NTSTATUS status = readByteNoLock(register_address, p_value);

    unlock();

    return status;
}

/////////////////////////////////////////////////////////////////////////////////////////
NTSTATUS Colibri::writeByte(WORD register_address, BYTE value)
{
    lock();

    NTSTATUS status = writeByteNoLock(register_address, value);

    unlock();

    return status;
}

/////////////////////////////////////////////////////////////////////////////////////////
NTSTATUS Colibri::readByteNoLock(WORD register_address, PBYTE p_value)
{
    BYTE addr[2] = {0,0};
    addr[0] = (BYTE) register_address;
    addr[1] =  (register_address >> 8) & 0xff;

    BOOLEAN status =  _p_i2c->read(
                        Colibri_DEVICE_ADDRESS>>1,
                        2,
                        &addr[0],
                        1,
                        p_value);

    if (status==TRUE)
    {
        return STATUS_SUCCESS;
    }
    else
    {
        return STATUS_UNSUCCESSFUL;
    }
}

/////////////////////////////////////////////////////////////////////////////////////////
NTSTATUS Colibri::writeByteNoLock(WORD register_address, BYTE value)
{
    BYTE buffer[2];
    
    buffer[0] = (register_address) & 0xff;
    buffer[1] = (register_address>>8) & 0xff;
    
    BOOLEAN status = _p_i2c->write(
                    Colibri_DEVICE_ADDRESS>>1,
                    2,
                    buffer,
                    1,
                    &value);

    if (status==TRUE)
    {
        return STATUS_SUCCESS;
    }
    else
    {
        return STATUS_UNSUCCESSFUL;
    }
}

/////////////////////////////////////////////////////////////////////////////////////////
NTSTATUS Colibri::writeDword(WORD register_address, DWORD value)
{
    BYTE buffer[2];
    BYTE v[4];
    
    buffer[0] = (BYTE) (register_address );
    buffer[1] = (BYTE) (register_address>>8);
    v[0] = (BYTE) (value);
    v[1] = (BYTE) (value >> 8);
    v[2] = (BYTE) (value >> 16);
    v[3] = (BYTE) (value >> 24);

    lock();

    BOOLEAN status =  _p_i2c->write(
                            Colibri_DEVICE_ADDRESS>>1,
                            2,
                            buffer,
                            4,
                            v);

    unlock();

    if (status==TRUE)
    {
        return STATUS_SUCCESS;
    }
    else
    {
        return STATUS_UNSUCCESSFUL;
    }
}


NTSTATUS Colibri::readDword(WORD register_address, PDWORD p_value)
{
    BYTE addr[2] = {0,0};
    addr[0] = (BYTE) register_address ;
    addr[1] =  (register_address>> 8 )& 0xff;
    
    lock();
    
    BOOLEAN status = _p_i2c->read(
                            Colibri_DEVICE_ADDRESS>>1,
                            2,
                            &addr[0],
                            4,
                            (PBYTE)p_value);

    unlock();

    if (status==TRUE)
    {
        return STATUS_SUCCESS;
    }
    else
    {
        return STATUS_UNSUCCESSFUL;
    }

}

/*
	we have 3 channel
	channel 1 ----- pin 1  to pin4(in reg is 1-4)
	channel 2 ----- pin 5  to pin8(in reg is 5-8)
	channel 3 ----- pin 9 to pin 12(in reg is 9-11)
*/
VOID Colibri::setInputMux(DWORD input_mux)
{
    BYTE ch1_setting = (BYTE)input_mux;
    BYTE ch2_setting = (BYTE)(input_mux >> 8);
    BYTE ch3_setting = (BYTE)(input_mux >> 16);

    WORD ch1 = 0;
    WORD ch2 = 0;
    WORD ch3 = 0;

    BYTE value = 0;	

    if(ch1_setting != 0)
    {
        readByte(ADC_INPUT_CH1, &value);
        value &= (!INPUT_SEL_MASK);
        value |= (ch1_setting-1)<<4;
        writeByte(ADC_INPUT_CH1, value);
    }

    if(ch2_setting != 0) 
    {
        readByte(ADC_INPUT_CH2, &value);
        value &= (!INPUT_SEL_MASK);
        value |= (ch2_setting-1)<<4;
        writeByte(ADC_INPUT_CH2, value);
    }

    //For ch3_setting, the value to put in the register is 7 less than the input number
    if(ch3_setting != 0) 
    {
        readByte(ADC_INPUT_CH3, &value);
        value &= (!INPUT_SEL_MASK);
        value |= (ch3_setting-1)<<4;
        writeByte(ADC_INPUT_CH3, value);
    }
}

// Function name   : Colibri::static_setColibriForLowIF
// Description     : Sets up colibri for Low IF mode, BW center Freq = 12.5MHz
//                   channel 3 differential mode.
// Return type     : void 
// Argument        : void *p_Colibri
// Argument        : DWORD if_freq
// Argument        : BOOL spectral_invert
// Argument        : ULONG mode
void Colibri::static_setColibriForLowIF(void *p_Colibri, DWORD if_freq, BOOL spectral_invert, ULONG mode)
{
    ASSERT(p_Colibri);

    DirectIF * p_DIF;

    DWORD colibri_carrier_offset = 0;

    Colibri * pColibri = (Colibri *)p_Colibri;

    if(pColibri)
    {
        p_DIF = pColibri->getDIF();
        
        //Set colibri for low IF
        pColibri->SetMode(Colibri::AFE_MODE_LOW_IF);//SetupAFEforLowIF();        

        // Set C2HH for low IF operation.
        p_DIF->ConfigureC2HHforLowIF(mode);
        
        // Get colibri offsets.
        colibri_carrier_offset = pColibri->GetColibriCarrierOffset(mode);

        // Set the band Pass filter for DIF
        p_DIF->setDIFbandpass( (if_freq+colibri_carrier_offset) , spectral_invert, mode);
    }
}

// Function name   : Colibri::GetColibriCarrierOffset
// Description     : Return the frequency shift that the IF gets after 
//                   passing though colibri. For NTSC the IF changes from 5.35 to 10.18
//                   or 10.6(video carrier center freq)                       
// Return type     : DWORD 
DWORD Colibri::GetColibriCarrierOffset(ULONG mode)
{
    DWORD colibri_carrier_offset = 0;    

    if(mode == KSPROPERTY_TUNER_MODE_FM_RADIO)
    {   
        colibri_carrier_offset = 1100000;
    }
    else
    {   
        //get offset for KSPROPERTY_TUNER_MODE_TV
        DWORD video_standard = KS_AnalogVideo_NTSC_M;
        video_standard = _p_DIF->getStandard();
        
        switch(video_standard)
        {
        case KS_AnalogVideo_PAL_B:   
        case KS_AnalogVideo_PAL_G:
             colibri_carrier_offset = 2700000;  //2.70MHz       
             break;
        
        case KS_AnalogVideo_PAL_D:  
        case KS_AnalogVideo_PAL_I:
        case KS_AnalogVideo_SECAM_L:
        case KS_AnalogVideo_SECAM_L1:
            colibri_carrier_offset = 2100000;  //2.70MHz
        break;
        
        default:
        case KS_AnalogVideo_NTSC_M:   
        case KS_AnalogVideo_NTSC_M_J:        
             colibri_carrier_offset = 4832000;  //4.83MHz         
             break;    
    }
    }

    return colibri_carrier_offset;
}

VOID Colibri::initSuperBlock()
{
    // super block initialize
    writeByte( SUP_BLK_TUNE1,  0x42); // 0x00
    writeByte( SUP_BLK_TUNE2,  0x12); // 0x01
    writeByte( SUP_BLK_PLL2,   0x0f); // 0x05
    // enable pll
    writeByte( SUP_BLK_PWRDN,   0x18); // 0x08
    // start tuning filter
    writeByte( SUP_BLK_TUNE3,   0x40); // 0x02
    sleep(5);
    // exit tuning
    writeByte( SUP_BLK_TUNE3,   0x00); // 0x02
}

VOID Colibri::initChannels()
{
    // power up all 3 channels, clear pd_buffer
    writeByte( ADC_PWRDN_CLAMP_CH1,   0x00);  // 0x23
    writeByte( ADC_PWRDN_CLAMP_CH2,   0x00);
    writeByte( ADC_PWRDN_CLAMP_CH3,   0x00);
    // Enable quantizer calibration
    writeByte( ADC_COM_QUANT,       0x02); // 0x0B

    // channel initialize
    // force modulator (fb) reset
    writeByte( ADC_FB_FRCRST_CH1,   0x17); // 0x27
    writeByte( ADC_FB_FRCRST_CH2,   0x17);
    writeByte( ADC_FB_FRCRST_CH3,   0x17);

    // start quantilizer calibration
    writeByte( ADC_CAL_ATEST_CH1,   0x10); // 0x22
    writeByte( ADC_CAL_ATEST_CH2,   0x10);
    writeByte( ADC_CAL_ATEST_CH3,   0x10);
    sleep(5);

    // exit modulator (fb) reset
    writeByte( ADC_FB_FRCRST_CH1,   0x07); // 0x27
    writeByte( ADC_FB_FRCRST_CH2,   0x07);
    writeByte( ADC_FB_FRCRST_CH3,   0x07);

    // enable the pre_clamp in each channel for single-ended input
    writeByte( ADC_NTF_PRECLMP_EN_CH1,   0xf0); // 0x29
    writeByte( ADC_NTF_PRECLMP_EN_CH2,   0xf0);
    writeByte( ADC_NTF_PRECLMP_EN_CH3,   0xf0);

    // use diode instead of resistor, so set term_en to 0, res_en to 0
    RegMaskWrite(8, ADC_QGAIN_RES_TRM_CH1, 3, 7, 0x00); // 0x2A
    RegMaskWrite(8, ADC_QGAIN_RES_TRM_CH2, 3, 7, 0x00);
    RegMaskWrite(8, ADC_QGAIN_RES_TRM_CH3, 3, 7, 0x00);

    //dynamic element matching off
    writeByte( ADC_DCSERVO_DEM_CH1,   0x03); // 0x26
    writeByte( ADC_DCSERVO_DEM_CH2,   0x03);
    writeByte( ADC_DCSERVO_DEM_CH3,   0x03);
}

VOID Colibri::powerUp()
{
    //todo:finsih this
    initialize();
}

VOID Colibri::powerDown()
{
    //todo:finsih this
}

VOID Colibri::SetMode(AFE_MODE mode)
{
    switch(mode)
    {
    case AFE_MODE_LOW_IF:
        SetupAFEforLowIF();
        break;            
    case 
        AFE_MODE_BASEBAND:
        SetupAFEforBaseband();
        break;
    case 
        AFE_MODE_HI_IF:
        SetupAFEforHiIF();
        break;
    }

}

⌨️ 快捷键说明

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