From 871480933a1c28f8a9fed4c4d34d06c439a7a422 Mon Sep 17 00:00:00 2001 From: Srikant Patnaik Date: Sun, 11 Jan 2015 12:28:04 +0530 Subject: Moved, renamed, and deleted files The original directory structure was scattered and unorganized. Changes are basically to make it look like kernel structure. --- drivers/net/wireless/rda/Makefile | 3 + .../net/wireless/rda/rda_combo_power_ctrl/Makefile | 8 + .../rda/rda_combo_power_ctrl/rda_5990_power_ctrl.c | 1310 ++++++++++++ .../rda/rda_combo_power_ctrl/rda_5991_power_ctrl.c | 725 +++++++ .../rda_combo_power_ctrl/rda_5991e_power_ctrl.c | 796 +++++++ .../rda_combo_power_ctrl/rda_5991f_power_ctrl.c | 803 +++++++ .../wireless/rda/rda_combo_power_ctrl/rda_combo.h | 132 ++ .../rda_combo_power_ctrl/rda_combo_power_main.c | 1282 +++++++++++ drivers/net/wireless/rda/rda_fm/Makefile | 1 + drivers/net/wireless/rda/rda_fm/fm.h | 517 +++++ drivers/net/wireless/rda/rda_fm/fm_drv.c | 2257 ++++++++++++++++++++ drivers/net/wireless/rda/rda_wlan/Makefile | 17 + drivers/net/wireless/rda/rda_wlan/wlan_assoc.c | 228 ++ drivers/net/wireless/rda/rda_wlan/wlan_aver_rssi.c | 152 ++ drivers/net/wireless/rda/rda_wlan/wlan_aver_rssi.h | 25 + drivers/net/wireless/rda/rda_wlan/wlan_debugfs.c | 225 ++ drivers/net/wireless/rda/rda_wlan/wlan_defs.h | 168 ++ drivers/net/wireless/rda/rda_wlan/wlan_dev.h | 418 ++++ drivers/net/wireless/rda/rda_wlan/wlan_event.c | 227 ++ drivers/net/wireless/rda/rda_wlan/wlan_event.h | 33 + drivers/net/wireless/rda/rda_wlan/wlan_includes.h | 115 + drivers/net/wireless/rda/rda_wlan/wlan_init.c | 736 +++++++ drivers/net/wireless/rda/rda_wlan/wlan_module.c | 992 +++++++++ drivers/net/wireless/rda/rda_wlan/wlan_nvram.c | 209 ++ drivers/net/wireless/rda/rda_wlan/wlan_os.h | 145 ++ drivers/net/wireless/rda/rda_wlan/wlan_rxtx.c | 289 +++ drivers/net/wireless/rda/rda_wlan/wlan_scan.c | 429 ++++ drivers/net/wireless/rda/rda_wlan/wlan_sdio.c | 584 +++++ drivers/net/wireless/rda/rda_wlan/wlan_sdio.h | 42 + .../net/wireless/rda/rda_wlan/wlan_sdio_patch.c | 429 ++++ .../net/wireless/rda/rda_wlan/wlan_sdio_patch.h | 12 + .../net/wireless/rda/rda_wlan/wlan_sdio_patch_90.h | 1793 ++++++++++++++++ .../net/wireless/rda/rda_wlan/wlan_sdio_patch_91.h | 754 +++++++ .../wireless/rda/rda_wlan/wlan_sdio_patch_91e.h | 675 ++++++ .../wireless/rda/rda_wlan/wlan_sdio_patch_91f.h | 583 +++++ drivers/net/wireless/rda/rda_wlan/wlan_wext.c | 1870 ++++++++++++++++ drivers/net/wireless/rda/rda_wlan/wlan_wid.c | 1771 +++++++++++++++ drivers/net/wireless/rda/rda_wlan/wlan_wid.h | 344 +++ 38 files changed, 21099 insertions(+) create mode 100755 drivers/net/wireless/rda/Makefile create mode 100755 drivers/net/wireless/rda/rda_combo_power_ctrl/Makefile create mode 100755 drivers/net/wireless/rda/rda_combo_power_ctrl/rda_5990_power_ctrl.c create mode 100755 drivers/net/wireless/rda/rda_combo_power_ctrl/rda_5991_power_ctrl.c create mode 100755 drivers/net/wireless/rda/rda_combo_power_ctrl/rda_5991e_power_ctrl.c create mode 100755 drivers/net/wireless/rda/rda_combo_power_ctrl/rda_5991f_power_ctrl.c create mode 100755 drivers/net/wireless/rda/rda_combo_power_ctrl/rda_combo.h create mode 100755 drivers/net/wireless/rda/rda_combo_power_ctrl/rda_combo_power_main.c create mode 100755 drivers/net/wireless/rda/rda_fm/Makefile create mode 100755 drivers/net/wireless/rda/rda_fm/fm.h create mode 100755 drivers/net/wireless/rda/rda_fm/fm_drv.c create mode 100755 drivers/net/wireless/rda/rda_wlan/Makefile create mode 100755 drivers/net/wireless/rda/rda_wlan/wlan_assoc.c create mode 100755 drivers/net/wireless/rda/rda_wlan/wlan_aver_rssi.c create mode 100755 drivers/net/wireless/rda/rda_wlan/wlan_aver_rssi.h create mode 100755 drivers/net/wireless/rda/rda_wlan/wlan_debugfs.c create mode 100755 drivers/net/wireless/rda/rda_wlan/wlan_defs.h create mode 100755 drivers/net/wireless/rda/rda_wlan/wlan_dev.h create mode 100755 drivers/net/wireless/rda/rda_wlan/wlan_event.c create mode 100755 drivers/net/wireless/rda/rda_wlan/wlan_event.h create mode 100755 drivers/net/wireless/rda/rda_wlan/wlan_includes.h create mode 100755 drivers/net/wireless/rda/rda_wlan/wlan_init.c create mode 100755 drivers/net/wireless/rda/rda_wlan/wlan_module.c create mode 100755 drivers/net/wireless/rda/rda_wlan/wlan_nvram.c create mode 100755 drivers/net/wireless/rda/rda_wlan/wlan_os.h create mode 100755 drivers/net/wireless/rda/rda_wlan/wlan_rxtx.c create mode 100755 drivers/net/wireless/rda/rda_wlan/wlan_scan.c create mode 100755 drivers/net/wireless/rda/rda_wlan/wlan_sdio.c create mode 100755 drivers/net/wireless/rda/rda_wlan/wlan_sdio.h create mode 100755 drivers/net/wireless/rda/rda_wlan/wlan_sdio_patch.c create mode 100755 drivers/net/wireless/rda/rda_wlan/wlan_sdio_patch.h create mode 100755 drivers/net/wireless/rda/rda_wlan/wlan_sdio_patch_90.h create mode 100755 drivers/net/wireless/rda/rda_wlan/wlan_sdio_patch_91.h create mode 100755 drivers/net/wireless/rda/rda_wlan/wlan_sdio_patch_91e.h create mode 100755 drivers/net/wireless/rda/rda_wlan/wlan_sdio_patch_91f.h create mode 100755 drivers/net/wireless/rda/rda_wlan/wlan_wext.c create mode 100755 drivers/net/wireless/rda/rda_wlan/wlan_wid.c create mode 100755 drivers/net/wireless/rda/rda_wlan/wlan_wid.h (limited to 'drivers/net/wireless/rda') diff --git a/drivers/net/wireless/rda/Makefile b/drivers/net/wireless/rda/Makefile new file mode 100755 index 00000000..504f73f6 --- /dev/null +++ b/drivers/net/wireless/rda/Makefile @@ -0,0 +1,3 @@ +obj-m += rda_combo_power_ctrl/ +obj-m += rda_wlan/ +obj-m += rda_fm/ diff --git a/drivers/net/wireless/rda/rda_combo_power_ctrl/Makefile b/drivers/net/wireless/rda/rda_combo_power_ctrl/Makefile new file mode 100755 index 00000000..8ab7c892 --- /dev/null +++ b/drivers/net/wireless/rda/rda_combo_power_ctrl/Makefile @@ -0,0 +1,8 @@ +subdir-ccflags-y := -Werror +obj-m := rda_combo_power_ctrl.o +rda_combo_power_ctrl-objs := \ + rda_combo_power_main.o \ + rda_5990_power_ctrl.o \ + rda_5991_power_ctrl.o \ + rda_5991e_power_ctrl.o \ + rda_5991f_power_ctrl.o diff --git a/drivers/net/wireless/rda/rda_combo_power_ctrl/rda_5990_power_ctrl.c b/drivers/net/wireless/rda/rda_combo_power_ctrl/rda_5990_power_ctrl.c new file mode 100755 index 00000000..988579f8 --- /dev/null +++ b/drivers/net/wireless/rda/rda_combo_power_ctrl/rda_5990_power_ctrl.c @@ -0,0 +1,1310 @@ +#include "rda_combo.h" + +static u8 wifi_is_on = 0; + +static const u16 wifi_off_data[][2] = +{ + { 0x3F, 0x0001 }, //page up + { 0x31, 0x0B40 }, //power off wifi + { 0x3F, 0x0000 }, //page down +}; + +static const u16 wifi_en_data_90[][2] = +{ + //item:VerD_wf_on_2012_02_08 + {0x3f, 0x0001}, +#ifdef WLAN_USE_DCDC /*houzhen update Mar 15 2012 */ + {0x23, 0x8F21},//20111001 higher AVDD voltage to improve EVM to 0x8f21 download current -1db 0x8fA1>>0x8bA1 +#else + {0x23, 0x0FA1}, +#endif + {0x31, 0x0B40 }, //power off wifi +// {0x22, 0xD3C7},//for ver.c 20111109, txswitch + {0x24, 0x80C8},//freq_osc_in[1:0]00 0x80C8 >> 0x80CB + {0x27, 0x4925},//for ver.c20111109, txswitch + // {0x28, 0x80A1}, //BT_enable + {0x31, 0x8140},//enable wifi + {0x32, 0x0113},//set_ rdenout_ldooff_wf=0; rden4in_ldoon_wf=1 + {0x33, 0x0507},//stable time chenggangdeng + // {0x39, 0x0004}, //uart switch to wf + {0x3F, 0x0000}, //page down +}; + +static const u16 wifi_dc_cal_data[][2]= +{ + {0x3f, 0x0000}, + {0x30, 0x0248}, + {0x30, 0x0249}, + //{wait 200ms; } here +}; + +static const u16 wifi_dig_reset_data_90[][2]= +{ + {0x3F, 0x0001}, + {0x31, 0x8D40}, + {0x31, 0x8F40}, + {0x31, 0x8b40}, + {0x3F, 0x0000}, +}; + +static const u16 wifi_rf_init_data_90_verE[][2] = +{ + {0x3f, 0x0000}, + //{;;set_rf_swi},ch + {0x05, 0x8000}, + {0x06, 0x0101}, + {0x07, 0x0101}, + {0x08, 0x0101}, + {0x09, 0x3040}, + {0x0A, 0x002C},//aain_0 + {0x0D, 0x0507}, + {0x0E, 0x2300}, + {0x0F, 0x5689},// + //{;;//set_RF }, + {0x10, 0x0f78},//20110824 + {0x11, 0x0602}, + {0x13, 0x0652},//adc_tuning_bit[011] + {0x14, 0x8886}, + {0x15, 0x0910}, + {0x16, 0x049f}, +#ifdef WLAN_USE_CRYSTAL + {0x17, 0x0990}, + {0x18, 0x049F}, +#else + {0x17, 0x0910}, + {0x18, 0x249F}, +#endif + {0x19, 0x3C01}, + {0x1C, 0x0934}, + {0x1D, 0xFF00},//for ver.D20120119for temperature 70 degree + //{0x1F, 0x01F8},//for ver.c20111109 + //{0x1F, 0x0300},//for burst tx 涓嶉攣 + {0x20, 0x06E4}, + {0x21, 0x0ACF},//for ver.c20111109,dr dac reset,dr txflt reset + {0x22, 0x24DC}, +#ifdef WLAN_FOR_CTA + {0x23, 0x0BFF}, +#else + {0x23, 0x23FF}, +#endif + {0x24, 0x00FC}, + {0x26, 0x004F},//004F >> 005f premote pa + {0x27, 0x171D},///mdll*7 + {0x28, 0x031D},///mdll*7 +#ifdef WLAN_USE_CRYSTAL + {0x2A, 0x2860},//et0x2849-8.5p :yd 0x2861-7pf C1,C2=6.8p +#else + {0x2A, 0x7860}, +#endif + {0x2B, 0x0804},//bbpll,or ver.c20111116 + {0x32, 0x8a08}, + {0x33, 0x1D02},//liuyanan + //{;;//agc_gain}, +#if 1 + {0x36, 0x02f4}, //00F8;//gain_7 + {0x37, 0x01f4}, //0074;//aain_6 + {0x38, 0x21d4}, //0014;//gain_5 + {0x39, 0x25d4}, //0414;//aain_4 + {0x3A, 0x2584}, //1804;//gain_3 + {0x3B, 0x2dc4}, //1C04;//aain_2 + {0x3C, 0x2d04}, //1C02;//gain_1 + {0x3D, 0x2c02}, //3C01;//gain_0 +#else + {0x36, 0x01f8}, //00F8;//gain_7 + {0x37, 0x01f4}, //0074;//aain_6 + {0x38, 0x21d4}, //0014;//gain_5 + {0x39, 0x2073}, //0414;//aain_4 + {0x3A, 0x2473}, //1804;//gain_3 + {0x3B, 0x2dc7}, //1C04;//aain_2 + {0x3C, 0x2d07}, //1C02;//gain_1 + {0x3D, 0x2c04}, //3C01;//gain_0 +#endif + {0x33, 0x1502},//liuyanan + //{;;SET_channe},_to_11 + {0x1B, 0x0001},//set_channel + {0x30, 0x024D}, + {0x29, 0xD468}, + {0x29, 0x1468}, + {0x30, 0x0249}, + {0x3f, 0x0000}, +}; + +static const u16 wifi_rf_init_data_90_verD[][2] = +{ + {0x3f, 0x0000}, + //{;;set_rf_swi},ch + {0x05, 0x8000}, + {0x06, 0x0101}, + {0x07, 0x0101}, + {0x08, 0x0101}, + {0x09, 0x3040}, + {0x0A, 0x002C},//aain_0 + {0x0D, 0x0507}, + {0x0E, 0x2300},//2012_02_20 + {0x0F, 0x5689},// + //{;;//set_RF }, + {0x10, 0x0f78},//20110824 + {0x11, 0x0602}, + {0x13, 0x0652},//adc_tuning_bit[011] + {0x14, 0x8886}, + {0x15, 0x0910}, + {0x16, 0x049f}, +#ifdef WLAN_USE_CRYSTAL + {0x17, 0x0990}, + {0x18, 0x049F}, +#else + {0x17, 0x0910}, + {0x18, 0x249F}, +#endif + {0x19, 0x3C01},//sdm_vbit[3:0]=1111 + {0x1C, 0x0934}, + {0x1D, 0xFF00},//for ver.D20120119for temperature 70 degree 0xCE00 >> 0xFF00 + {0x1F, 0x0300},//div2_band_48g_dr=1;div2_band_48g_reg[8:0] + {0x20, 0x06E4}, + {0x21, 0x0ACF},//for ver.c20111109,dr dac reset,dr txflt reset + {0x22, 0x24DC}, +#ifdef WLAN_FOR_CTA + {0x23, 0x0BFF}, +#else + {0x23, 0x23FF}, +#endif + {0x24, 0x00FC}, + {0x26, 0x004F},//004F >> 005f premote pa + {0x27, 0x171D},///mdll*7 + {0x28, 0x031D},///mdll*7 +#ifdef WLAN_USE_CRYSTAL + {0x2A, 0x2860},//et0x2849-8.5p :yd 0x2861-7pf +#else + {0x2A, 0x7860}, +#endif + {0x2B, 0x0804},//bbpll,or ver.c20111116 + {0x32, 0x8a08}, + {0x33, 0x1D02},//liuyanan + //{;;//agc_gain}, +#if 1 + {0x36, 0x02f4}, //00F8;//gain_7 + {0x37, 0x01f4}, //0074;//aain_6 + {0x38, 0x21d4}, //0014;//gain_5 + {0x39, 0x25d4}, //0414;//aain_4 + {0x3A, 0x2584}, //1804;//gain_3 + {0x3B, 0x2dc4}, //1C04;//aain_2 + {0x3C, 0x2d04}, //1C02;//gain_1 + {0x3D, 0x2c02}, //3C01;//gain_0 +#else + {0x36, 0x01f8}, //00F8;//gain_7 + {0x37, 0x01f4}, //0074;//aain_6 + {0x38, 0x21d4}, //0014;//gain_5 + {0x39, 0x2073}, //0414;//aain_4 + {0x3A, 0x2473}, //1804;//gain_3 + {0x3B, 0x2dc7}, //1C04;//aain_2 + {0x3C, 0x2d07}, //1C02;//gain_1 + {0x3D, 0x2c04}, //3C01;//gain_0 +#endif + {0x33, 0x1502},//liuyanan + //{;;SET_channe},_to_11 + {0x1B, 0x0001},//set_channel + {0x30, 0x024D}, + {0x29, 0xD468}, + {0x29, 0x1468}, + {0x30, 0x0249}, + {0x3f, 0x0000}, +}; + +static const u16 wifi_tm_en_data_90[][2] = +{ + {0x3F,0x0001}, +#ifdef WLAN_USE_DCDC /*houzhen update Mar 15 2012 */ + {0x23, 0x8F21},//20111001 higher AVDD voltage to improve EVM to 0x8f21 download current -1db 0x8fA1>>0x8bA1 +#else + {0x23, 0x0FA1}, +#endif + {0x22,0xD3C7},//for ver.c 20111109, tx + {0x24, 0x80C8},//freq_osc_in[1:0]00 0x80C8 >> 0x80CB + {0x27,0x4925},//for ver.c20111109, txs + {0x28,0x80A1}, //BT_enable + {0x29,0x111F}, + {0x31,0x8140}, + {0x32,0x0113},//set_ rdenout_ldooff_wf + {0x39,0x0004},//uart switch to wf + {0x3f,0x0000}, +}; + +static const u16 wifi_tm_rf_init_data_90[][2] = +{ + {0x3f,0x0000}, + //set_rf_switch + {0x06,0x0101}, + {0x07,0x0101}, + {0x08,0x0101}, + {0x09,0x3040}, + {0x0A,0x002C},//aain_0 + {0x0D,0x0507}, + {0x0E,0x2300},//2012_02_20 + {0x0F,0x5689},// + //set_RF + {0x10,0x0f78},//20110824 + {0x11,0x0602}, + {0x13,0x0652},//adc_tuning_bit[011] + {0x14,0x8886}, + {0x15,0x0910}, + {0x16,0x049f}, +#ifdef WLAN_USE_CRYSTAL + {0x17,0x0990}, + {0x18,0x049F}, +#else + {0x17,0x0910}, + {0x18,0x249F}, +#endif + {0x19,0x3C01},//sdm_vbit[3:0]=1111 + {0x1C,0x0934}, + {0x1D,0xFF00},//for ver.D20120119for temperature 70 degree + {0x1F,0x0300},//div2_band_48g_dr=1;div2_band_48g_reg[8:0]1000000000 + {0x20,0x06E4}, + {0x21,0x0ACF},//for ver.c20111109,dr dac reset,dr txflt reset + {0x22,0x24DC}, +#ifdef WLAN_FOR_CTA + {0x23, 0x03FF}, +#else + {0x23, 0x0BFF}, +#endif + {0x24,0x00FC}, + {0x26,0x004F}, + {0x27,0x171D},///mdll*7 + {0x28,0x031D},///mdll*7 +#ifdef WLAN_USE_CRYSTAL + {0x2A,0x2860}, +#else + {0x2A,0x7860}, +#endif + {0x2B,0x0804},//bbpll,or ver.c20111116 + {0x32,0x8a08}, + {0x33,0x1D02},//liuyanan + //agc_gain +#if 1 + {0x36, 0x02f4}, //00F8;//gain_7 + {0x37, 0x01f4}, //0074;//aain_6 + {0x38, 0x21d4}, //0014;//gain_5 + {0x39, 0x25d4}, //0414;//aain_4 + {0x3A, 0x2584}, //1804;//gain_3 + {0x3B, 0x2dc4}, //1C04;//aain_2 + {0x3C, 0x2d04}, //1C02;//gain_1 + {0x3D, 0x2c02}, //3C01;//gain_0 +#else + {0x36, 0x01f8}, //00F8;//gain_7 + {0x37, 0x01f4}, //0074;//aain_6 + {0x38, 0x21d4}, //0014;//gain_5 + {0x39, 0x2073}, //0414;//aain_4 + {0x3A, 0x2473}, //1804;//gain_3 + {0x3B, 0x2dc7}, //1C04;//aain_2 + {0x3C, 0x2d07}, //1C02;//gain_1 + {0x3D, 0x2c04}, //3C01;//gain_0 +#endif + {0x30,0x0248}, + {0x30,0x0249}, + //wait 200ms; + {0x33,0x1502},//liuyanan + //SET_channel_to_11 + {0x1B,0x0001},//set_channel + {0x3f,0x0000}, +}; + + +/*houzhen update Mar 15 2012 + should be called when power up/down bt + */ +static int rda5990_wf_setup_A2_power(int enable) +{ + int ret; + u16 temp_data=0; + printk(KERN_INFO "***rda5990_wf_setup_A2_power start! \n"); + + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x3f, 0x0001); + if(ret) + goto err; + + if(enable){ + ret=i2c_read_1_addr_2_data(rda_wifi_rf_client,0x22,&temp_data); + if(ret) + goto err; + printk(KERN_INFO "***0xA2 readback value:0x%X \n", temp_data); + + temp_data |=0x0200; /*en reg4_pa bit*/ +#ifdef WLAN_USE_CRYSTAL + temp_data &= ~(1 << 14); //disable xen_out +#endif + ret=i2c_write_1_addr_2_data(rda_wifi_rf_client,0x22,temp_data); + if(ret) + goto err; + } + else{ + ret=i2c_read_1_addr_2_data(rda_wifi_rf_client,0x28,&temp_data); + if(ret) + goto err; + if(temp_data&0x8000){ // bt is on + goto out; + } + else{ + ret=i2c_read_1_addr_2_data(rda_wifi_rf_client,0x22,&temp_data); + if(ret) + goto err; + temp_data&=0xfdff; + + ret=i2c_write_1_addr_2_data(rda_wifi_rf_client,0x22,temp_data); + if(ret) + goto err; + } + } + +out: + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x3f, 0x0000); + if(ret) + goto err; + printk(KERN_INFO "***rda5990_wf_setup_A2_power succeed! \n"); + return 0; + +err: + printk(KERN_INFO "***rda5990_wf_setup_A2_power failed! \n"); + return -1; +} + + +int rda_5990_wifi_rf_init(void) +{ + int ret = 0; + + rda_combo_i2c_lock(); + + if( rda_wlan_version() == WLAN_VERSION_90_D){ + + ret = RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, wifi_rf_init_data_90_verD); + if(ret) + goto err; + } + else if(rda_wlan_version() == WLAN_VERSION_90_E){ + ret = RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, wifi_rf_init_data_90_verE); + if(ret) + goto err; + } + else{ + printk("unknown version of this chip\n"); + goto err; + } + + rda_combo_i2c_unlock(); + + printk(KERN_INFO "***rda_5990_wifi_rf_init_succceed \n"); + msleep(5); //5ms delay + return 0; +err: + rda_combo_i2c_unlock(); + printk(KERN_INFO "***rda_5990_wifi_rf_init failed! \n"); + return -1; +} + +int rda_5990_wifi_dc_cal(void) +{ + int ret = 0; + + rda_combo_i2c_lock(); + + ret = RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client ,wifi_dc_cal_data); + if(ret) + goto err; + + rda_combo_i2c_unlock(); + + printk(KERN_INFO "***rda_wifi_rf_dc_calsuccceed \n"); + msleep(50); //50ms delay + return 0; + +err: + rda_combo_i2c_unlock(); + + printk(KERN_INFO "***rda_wifi_rf_dc_calf_failed! \n"); + return -1; +} + +int rda_5990_wifi_en(void) +{ + int ret = 0; + enable_26m_regulator(CLOCK_WLAN); + enable_32k_rtc(CLOCK_WLAN); + enable_26m_rtc(CLOCK_WLAN); + + msleep(8); + + rda_combo_i2c_lock(); + + if(rda_wlan_version() == WLAN_VERSION_90_D || rda_wlan_version() == WLAN_VERSION_90_E){ + ret = RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, wifi_en_data_90); + if(ret) + goto err; + } + + ret=rda5990_wf_setup_A2_power(1); //en pa_reg for wf + if(ret) + goto err; + + rda_combo_i2c_unlock(); + + msleep(8); //8ms delay + + printk(KERN_INFO "***rda_5990_wifi_en_succceed \n"); + //in rda platform should close 26M after wifi power on success + disable_26m_rtc(CLOCK_WLAN); + return 0; +err: + rda_combo_i2c_unlock(); + disable_32k_rtc(CLOCK_WLAN); + disable_26m_rtc(CLOCK_WLAN); + disable_26m_regulator(CLOCK_WLAN); + printk(KERN_INFO "***rda_5990_wifi_en failed! \n"); + return -1; +} + +static int rda_5990_wifi_debug_en(int enable) +{ + int ret = 0; + u16 temp_data = 0; + + rda_combo_i2c_lock(); + + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x3f, 0x0001); + if (ret < 0) + goto err; + if (enable == 1){ + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x28, 0x80A1); + if (ret < 0) + goto err; + + ret = i2c_read_1_addr_2_data(rda_wifi_rf_client, 0x39, &temp_data); + if (ret < 0) + goto err; + + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x39, temp_data | (1 << 2)); + if (ret < 0) + goto err; + }else{ + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x28, 0x00A1); + if (ret < 0) + goto err; + + ret = i2c_read_1_addr_2_data(rda_wifi_rf_client, 0x39, &temp_data); + if (ret < 0) + goto err; + + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x39, temp_data & (~(1 << 2))); + if (ret < 0) + goto err; + } + + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x3f, 0x0000); + if (ret < 0) + goto err; +err: + rda_combo_i2c_unlock(); + return ret; +} + +int rda_5990_tm_wifi_en(void) +{ + int ret = 0; + enable_26m_regulator(CLOCK_WLAN); + enable_32k_rtc(CLOCK_WLAN); + enable_26m_rtc(CLOCK_WLAN); + msleep(5); + + if(rda_wlan_version() == WLAN_VERSION_90_D || rda_wlan_version() == WLAN_VERSION_90_E){ + + ret = RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, wifi_tm_en_data_90); + if(ret) + goto err; + } + + msleep(8); //8ms delay + printk(KERN_INFO "***rda_5990_tm_wifi_en succceed \n"); + disable_26m_rtc(CLOCK_WLAN); + return 0; +err: + disable_32k_rtc(CLOCK_WLAN); + disable_26m_rtc(CLOCK_WLAN); + printk(KERN_INFO "***rda_5990_tm_wifi_en failed! \n"); + return -1; +} + +int rda_5990_tm_wifi_rf_init(void) +{ + int ret = 0; + + if(rda_wlan_version() == WLAN_VERSION_90_D || rda_wlan_version() == WLAN_VERSION_90_E){ + ret = RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, wifi_tm_rf_init_data_90); + if(ret) + goto err; + }else + return -1; + + printk(KERN_INFO "***rda_5990_tm_wifi_rf_init \n"); + msleep(5); //5ms delay + return 0; + +err: + printk(KERN_INFO "***rda_5990_tm_wifi_rf_init failed! \n"); + return -1; +} +/*houzhen add 2012 04 09 + add to ensure wf dig powerup + */ + +int rda_5990_wifi_dig_reset(void) +{ + int ret = 0; + + msleep(8); //8ms delay + + rda_combo_i2c_lock(); + + ret = RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, wifi_dig_reset_data_90); + if(ret) + goto err; + + rda_combo_i2c_unlock(); + + msleep(8); //8ms delay + + printk(KERN_INFO "***rda_5990_wifi_dig_reset \n"); + return 0; +err: + rda_combo_i2c_unlock(); + + printk(KERN_INFO "***rda_5990_wifi_dig_reset failed! \n"); + return -1; +} + +int rda_5990_wifi_power_off(void) +{ + int ret = 0; + u16 temp=0x0000; + printk(KERN_INFO "rda_5990_wifi_power_off \n"); + + if(!rda_wifi_rf_client){ + printk(KERN_INFO "rda_5990_wifi_power_off failed on:i2c client \n"); + return -1; + } + + rda_combo_i2c_lock(); + + ret=rda5990_wf_setup_A2_power(0); //disable pa_reg for wf + if(ret) + goto err; + + if(rda_wlan_version() == WLAN_VERSION_90_D || rda_wlan_version() == WLAN_VERSION_90_E){ + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x3f, 0x0001); //page up + if(ret) + goto err; + + ret=i2c_read_1_addr_2_data(rda_wifi_rf_client,0x28,&temp); //poll bt status + if(ret) + goto err; + + if(temp&0x8000){ + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x3f, 0x0000); //page down + if(ret) + goto err; + + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x0f, 0x2223); // set antenna for bt + if(ret) + goto err; + + } + } + + ret = RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, wifi_off_data); + if(ret) + goto err; + + rda_combo_i2c_unlock(); + + wifi_is_on = 0; + disable_32k_rtc(CLOCK_WLAN); + disable_26m_rtc(CLOCK_WLAN); + disable_26m_regulator(CLOCK_WLAN); + printk(KERN_INFO "***rda_5990_wifi_power_off success!!! \n"); + return 0; + +err: + rda_combo_i2c_unlock(); + printk(KERN_INFO "***rda_5990_wifi_power_off failed! \n"); + return -1; + +} + +int rda_5990_wifi_power_on(void) +{ + int ret; + char retry = 3; + + if(!rda_wifi_rf_client){ + printk(KERN_INFO "rda_5990_wifi_power_on failed on:i2c client \n"); + return -1; + } + +_retry: + if(!rda_combo_wifi_in_test_mode()){ + ret = rda_5990_wifi_en(); + if(ret < 0) + goto err; + + ret = rda_5990_wifi_rf_init(); + if(ret < 0) + goto err; + + ret = rda_5990_wifi_dc_cal(); + if(ret < 0) + goto err; + + msleep(20); //20ms delay + ret=rda_5990_wifi_dig_reset(); //houzhen add to ensure wf power up safely + + if(ret < 0) + goto err; + msleep(20); //20ms delay + } + else{ + ret = rda_5990_tm_wifi_en(); + if(ret < 0) + goto err; + + ret = rda_5990_tm_wifi_rf_init(); + if(ret < 0) + goto err; + } + printk(KERN_INFO "rda_5990_wifi_power_on_succeed!! \n"); + wifi_is_on = 1; + return 0; + +err: + printk(KERN_INFO "rda_5990_wifi_power_on_failed retry:%d \n", retry); + if(retry -- > 0) { + rda_5990_wifi_power_off(); + goto _retry; + } + wifi_is_on = 0; + return -1; +} + +int rda_5990_fm_power_on(void) +{ + int ret = 0; + u16 temp = 0; + + if(!rda_wifi_rf_client){ + printk(KERN_INFO "rda_wifi_rf_client is NULL, rda_fm_power_on failed!\n"); + return -1; + } + + enable_32k_rtc(CLOCK_FM); + msleep(8); + rda_combo_i2c_lock(); + + if(rda_wlan_version() == WLAN_VERSION_90_D || rda_wlan_version() == WLAN_VERSION_90_E){ + + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x3f, 0x0001); // page down + if(ret < 0){ + printk(KERN_INFO "%s() write address(0x%02x) with value(0x%04x) failed! \n", __func__, 0x3f, 0x0001); + goto err; + } + + ret = i2c_read_1_addr_2_data(rda_wifi_rf_client, 0x22, &temp); //read 0xA2 + if(ret < 0){ + printk(KERN_INFO "%s() read from address(0x%02x) failed! \n", __func__, 0x22); + goto err; + } + temp = temp & (~(1 << 15)); //clear bit[15] + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x22, temp); //write back + if(ret < 0){ + printk(KERN_INFO "%s() write address(0x%02x) with value(0x%04x) failed! \n", __func__, 0x3f, 0x0001); + goto err; + } + } + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x3f, 0x0000); // page up + if(ret < 0){ + printk(KERN_INFO "%s() write address(0x%02x) with value(0x%04x) failed! \n", __func__, 0x3f, 0x0001); + goto err; + } + + rda_combo_i2c_unlock(); + return 0; + +err: + rda_combo_i2c_unlock(); + disable_32k_rtc(CLOCK_FM); + printk(KERN_INFO "***rda_fm_power_on failed! \n"); + return -1; +} + +int rda_5990_fm_power_off(void) +{ + int ret = 0; + u16 temp = 0; + + if(!rda_wifi_rf_client){ + printk(KERN_INFO "rda_wifi_rf_client is NULL, rda_fm_power_off failed!\n"); + return -1; + } + + rda_combo_i2c_lock(); + + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x3f, 0x0001); // page down + if(ret < 0){ + printk(KERN_INFO "%s() write address(0x%02x) with value(0x%04x) failed! \n", __func__, 0x3f, 0x0001); + goto err; + } + + if(rda_wlan_version() == WLAN_VERSION_90_D || rda_wlan_version() == WLAN_VERSION_90_E){ + ret = i2c_read_1_addr_2_data(rda_wifi_rf_client, 0x22, &temp); //read 0xA2 + if(ret < 0){ + printk(KERN_INFO "%s() read from address(0x%02x) failed! \n", __func__, 0x22); + goto err; + } + temp = temp | (1 << 15); //set bit[15] + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x22, temp); //write back + if(ret < 0){ + printk(KERN_INFO "%s() write address(0x%02x) with value(0x%04x) failed! \n", __func__, 0x3f, 0x0001); + goto err; + } + } + + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x3f, 0x0000); // page up + if(ret < 0){ + printk(KERN_INFO "%s() write address(0x%02x) with value(0x%04x) failed! \n", __func__, 0x3f, 0x0001); + goto err; + } + + rda_combo_i2c_unlock(); + disable_32k_rtc(CLOCK_FM); + return 0; +err: + rda_combo_i2c_unlock(); + printk(KERN_INFO "***rda_fm_power_off failed! \n"); + return -1; +} + + +static const u16 rda_5990_bt_off_data[][2] = +{ + {0x3f, 0x0001 }, //pageup + {0x28, 0x00A1 }, //power off bt + {0x3f, 0x0000 }, //pagedown +}; + +/*houzhen update 2012 03 06*/ +static const u16 rda_5990_bt_en_data[][2] = +{ + {0x3f, 0x0001 }, //pageup +#ifdef WLAN_USE_DCDC + {0x23, 0x8FA1}, // //20111001 higher AVDD voltage to improve EVM +#else + {0x23, 0x0FA1}, +#endif + {0x24, 0x80C8}, // ;//freq_osc_in[1:0]00 + {0x26, 0x47A5}, // reg_vbit_normal_bt[2:0] =111 + {0x27, 0x4925}, // //for ver.c20111109, txswitch + {0x29, 0x111F}, // // rden4in_ldoon_bt=1 + {0x32, 0x0111}, // set_ rdenout_ldooff_wf=0; + {0x39, 0x0000}, // //uart switch to bt + + {0x28, 0x80A1}, // bt en + {0x3f, 0x0000}, //pagedown +}; + +static const u16 rda_5990_bt_dc_cal[][2] = +{ + {0x3f, 0x0000 }, + {0x30, 0x0129 }, + {0x30, 0x012B }, + {0x3f, 0x0000 }, +}; + +static const u16 rda_5990_bt_set_rf_switch_data[][2] = +{ + {0x3f, 0x0000 }, + {0x0F, 0x2223 }, + {0x3f, 0x0000 }, +}; + +static const u16 RDA5990_bt_enable_clk_data[][2] = +{ + {0x3f, 0x0000 }, + {0x30, 0x0040 }, + {0x2a, 0x285d }, + {0x3f, 0x0000 }, +}; + +static const u16 RDA5990_bt_dig_reset_data[][2] = +{ + {0x3f, 0x0001 }, //pageup + {0x28, 0x86A1 }, + {0x28, 0x87A1 }, + {0x28, 0x85A1 }, + {0x3f, 0x0000 }, //pagedown +}; + +/*houzhen update 2012 03 06*/ +static const u16 rda_5990_bt_rf_data[][2] = +{ + {0x3f, 0x0000}, //pagedown + {0x01, 0x1FFF}, + {0x06, 0x07F7}, + {0x08, 0x29E7}, + {0x09, 0x0520}, + {0x0B, 0x03DF}, + {0x0C, 0x85E8}, + {0x0F, 0x0DBC}, + {0x12, 0x07F7}, + {0x13, 0x0327}, + {0x14, 0x0CCC}, + {0x15, 0x0526}, + {0x16, 0x8918}, + {0x18, 0x8800}, + {0x19, 0x10C8}, + {0x1A, 0x9078}, + {0x1B, 0x80E2}, + {0x1C, 0x361F}, + {0x1D, 0x4363}, + {0x1E, 0x303F}, + {0x23, 0x2222}, + {0x24, 0x359D}, + {0x27, 0x0011}, + {0x28, 0x124F}, + {0x39, 0xA5FC}, + {0x3f, 0x0001}, //page 1 + {0x00, 0x043F}, + {0x01, 0x467F}, + {0x02, 0x28FF}, + {0x03, 0x67FF}, + {0x04, 0x57FF}, + {0x05, 0x7BFF}, + {0x06, 0x3FFF}, + {0x07, 0x7FFF}, + {0x18, 0xF3F5}, + {0x19, 0xF3F5}, + {0x1A, 0xE7F3}, + {0x1B, 0xF1FF}, + {0x1C, 0xFFFF}, + {0x1D, 0xFFFF}, + {0x1E, 0xFFFF}, + {0x1F, 0xFFFF}, + // {0x22, 0xD3C7}, + // {0x23, 0x8fa1}, + // {0x24, 0x80c8}, + // {0x26, 0x47A5}, + // {0x27, 0x4925}, + // {0x28, 0x85a1}, + // {0x29, 0x111f}, + // {0x32, 0x0111}, + // {0x39, 0x0000}, + {0x3f, 0x0000}, //pagedown +}; + +/*houzhen update Mar 15 2012 + should be called when power up/down bt + */ +static int rda5990_bt_setup_A2_power(int enable) +{ + int ret; + u16 temp_data=0; + + ret = i2c_write_1_addr_2_data(rda_bt_rf_client, 0x3f, 0x0001); + if(ret) + goto err; + + if(enable){ + ret=i2c_read_1_addr_2_data(rda_bt_rf_client,0x22,&temp_data); + if(ret) + goto err; + printk(KERN_INFO "***0xA2 readback value:0x%X \n", temp_data); + + temp_data |=0x0200; /*en reg4_pa bit*/ + + ret=i2c_write_1_addr_2_data(rda_bt_rf_client,0x22,temp_data); + if(ret) + goto err; + } + else + { + ret=i2c_read_1_addr_2_data(rda_bt_rf_client,0x31,&temp_data); + if(ret) + goto err; + + if(temp_data&0x8000){ // wf is on + goto out; + } + else{ + ret=i2c_read_1_addr_2_data(rda_bt_rf_client,0x22,&temp_data); + if(ret) + goto err; + temp_data&=0xfdff; + + ret=i2c_write_1_addr_2_data(rda_bt_rf_client,0x22,temp_data); + if(ret) + goto err; + } + + } + +out: + ret = i2c_write_1_addr_2_data(rda_bt_rf_client, 0x3f, 0x0000); + if(ret) + goto err; + return 0; + +err: + printk(KERN_INFO "***rda5990_bt_setup_A2_power failed! \n"); + return -1; +} + +int rda_5990_bt_power_on(void) +{ + int ret = 0; + + printk(KERN_INFO "rda_bt_power_on \n"); + + if(!rda_bt_rf_client || !rda_bt_rf_client){ + printk(KERN_INFO "rda_bt_power_on failed on:i2c client \n"); + return -1; + } + enable_26m_regulator(CLOCK_BT); + enable_26m_rtc(CLOCK_BT); + enable_32k_rtc(CLOCK_BT); + msleep(8); + + rda_combo_i2c_lock(); + + if(rda_wlan_version() == WLAN_VERSION_90_D || rda_wlan_version() == WLAN_VERSION_90_E){ + ret = RDA_WRITE_DATA_TO_RF(rda_bt_rf_client, rda_5990_bt_en_data); + if(ret) + goto err; + } + + ret=rda5990_bt_setup_A2_power(1); + if(ret){ + printk(KERN_INFO "***rda5990_bt_setup_A2_power fail!!! \n"); + goto err; + } + + printk(KERN_INFO "***rda_bt_power_on success!!! \n"); + + rda_combo_i2c_unlock(); + /*houzhen update 2012 03 06*/ + msleep(10); //delay 10 ms after power on + disable_26m_rtc(CLOCK_BT); + return 0; + +err: + rda_combo_i2c_unlock(); + disable_26m_rtc(CLOCK_BT); + disable_32k_rtc(CLOCK_BT); + disable_26m_regulator(CLOCK_BT); + printk(KERN_INFO "***rda_bt_power_on failed! \n"); + return -1; + +} + +int rda_5990_bt_power_off(void) +{ + int ret = 0; + printk(KERN_INFO "rda_5990_bt_power_off \n"); + + if(!rda_bt_rf_client){ + printk(KERN_INFO "rda_5990_bt_power_off failed on:i2c client \n"); + return -1; + } + + rda_combo_i2c_lock(); + + if(rda_wlan_version() == WLAN_VERSION_90_D || rda_wlan_version() == WLAN_VERSION_90_E){ + ret = RDA_WRITE_DATA_TO_RF(rda_bt_rf_client ,rda_5990_bt_off_data); + if(ret) + goto err; + } + + msleep(10); //10ms + printk(KERN_INFO "***rda_5990_bt_power_off success!!! \n"); + + ret=rda5990_bt_setup_A2_power(0);//disable ldo_pa reg + if(ret) + goto err; + + rda_combo_i2c_unlock(); + disable_26m_rtc(CLOCK_BT); + disable_32k_rtc(CLOCK_BT); + disable_26m_regulator(CLOCK_BT); + return 0; + +err: + rda_combo_i2c_unlock(); + printk(KERN_INFO "***rda_5990_bt_power_off failed! \n"); + return -1; + +} + + +static int RDA5990_bt_rf_init(void) +{ + int ret = 0; + + if(!rda_bt_rf_client){ + printk(KERN_INFO "RDA5990_bt_rf_init on:i2c client \n"); + return -1; + } + + rda_combo_i2c_lock(); + + if(rda_wlan_version() == WLAN_VERSION_90_D || rda_wlan_version() == WLAN_VERSION_90_E){ + ret = RDA_WRITE_DATA_TO_RF(rda_bt_rf_client, rda_5990_bt_rf_data); + if(ret) + goto err; + } + + rda_combo_i2c_unlock(); + + printk(KERN_INFO "***RDA5990_bt_rf_init success!!! \n"); + msleep(5); //5ms + return 0; + +err: + rda_combo_i2c_unlock(); + printk(KERN_INFO "***RDA5990_bt_rf_init failed! \n"); + return -1; +} + +/*houzhen add 2012 04 09 + add to ensure bt dig powerup + */ +static int RDA5990_bt_dig_reset(void) +{ + int ret = 0; + + if(!rda_bt_rf_client){ + printk(KERN_INFO "RDA5990_bt_dig_reset on:i2c client \n"); + return -1; + } + + rda_combo_i2c_lock(); + + ret = RDA_WRITE_DATA_TO_RF(rda_bt_rf_client, RDA5990_bt_dig_reset_data); + if(ret) + goto err; + + rda_combo_i2c_unlock(); + + printk(KERN_INFO "***RDA5990_bt_dig_reset success!!! \n"); + msleep(5); //5ms + + return 0; + +err: + rda_combo_i2c_unlock(); + printk(KERN_INFO "***RDA5990_bt_dig_reset failed! \n"); + return -1; +} + + +static int RDA5990_bt_dc_cal(void) +{ + int ret = 0; + + if(!rda_bt_rf_client){ + printk(KERN_INFO "rda_bt_rf_client \n"); + return -1; + } + + rda_combo_i2c_lock(); + + if(rda_wlan_version() == WLAN_VERSION_90_D || rda_wlan_version() == WLAN_VERSION_90_E){ + ret = RDA_WRITE_DATA_TO_RF(rda_bt_rf_client, rda_5990_bt_dc_cal); + if(ret) + goto err; + } + + rda_combo_i2c_unlock(); + printk(KERN_INFO "***rda_bt_dc_cal success!!! \n"); + msleep(200); //200ms + + return 0; + +err: + rda_combo_i2c_unlock(); + printk(KERN_INFO "***rda_bt_dc_cal failed! \n"); + return -1; + +} + + +/*houzhen update Mar 15 2012 + bypass RDA5990_bt_set_rf_switch when wf is already on +*/ + +static int RDA5990_bt_set_rf_switch(void) +{ + int ret = 0; + u16 temp_data=0; + + if(!rda_bt_rf_client || !rda_wifi_rf_client){ + printk(KERN_INFO "RDA5990_bt_set_rf_switch failed on:i2c client \n"); + return -1; + } + + rda_combo_i2c_lock(); + + if(rda_wlan_version() == WLAN_VERSION_90_D || rda_wlan_version() == WLAN_VERSION_90_E){ + ret = i2c_write_1_addr_2_data(rda_bt_rf_client, 0x3f, 0x0001); + if(ret) + goto err; + + ret=i2c_read_1_addr_2_data(rda_bt_rf_client,0x31,&temp_data); + if(ret) + goto err; + + if(temp_data&0x8000) { // if wf is already on + printk(KERN_INFO "wf already en, bypass RDA5990_bt_set_rf_switch function \n"); + ret = i2c_write_1_addr_2_data(rda_bt_rf_client, 0x3f, 0x0000); + if(ret) + goto err; + + rda_combo_i2c_unlock(); + return 0; + } + + ret = RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, rda_5990_bt_set_rf_switch_data); + if(ret) + goto err; + } + + rda_combo_i2c_unlock(); + printk(KERN_INFO "***RDA5990_bt_set_rf_switch success!!! \n"); + msleep(50); //50ms + return 0; + +err: + rda_combo_i2c_unlock(); + printk(KERN_INFO "***RDA5990_bt_set_rf_switch failed! \n"); + return -1; + +} + + +/*houzhen update Mar 15 2012 + bypass RDA5990_bt_enable_clk when wf is already on + */ +static int RDA5990_bt_enable_clk(void) +{ + int ret = 0; + u16 temp_data=0; + + if(!rda_bt_rf_client){ + printk(KERN_INFO "RDA5990_bt_enable_clk failed on:i2c client \n"); + return -1; + } + + rda_combo_i2c_lock(); + ret = i2c_write_1_addr_2_data(rda_bt_rf_client, 0x3f, 0x0001); + if(ret) + goto err; + + ret=i2c_read_1_addr_2_data(rda_bt_rf_client,0x31,&temp_data); + + if(ret) + goto err; + + if(temp_data&0x8000){ // if wf is already on + printk(KERN_INFO "wf already en, bypass RDA5990_bt_enable_clk function \n"); + ret = i2c_write_1_addr_2_data(rda_bt_rf_client, 0x3f, 0x0000); + if(ret) + goto err; + rda_combo_i2c_unlock(); + return 0; + } + + + ret = RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, RDA5990_bt_enable_clk_data); + if(ret) + goto err; + + rda_combo_i2c_unlock(); + printk(KERN_INFO "***RDA5990_bt_enable_clk success!!! \n"); + msleep(50); //50ms + return 0; + +err: + rda_combo_i2c_unlock(); + printk(KERN_INFO "***RDA5990_bt_enable_clk failed! \n"); + return -1; +} + +long rda_5990_pw_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + int ret = 0; + + switch(cmd) + { + case RDA_WIFI_POWER_ON_IOCTL: + ret = rda_5990_wifi_power_on(); + break; + + case RDA_WIFI_POWER_OFF_IOCTL: + ret = rda_5990_wifi_power_off(); + break; + + case RDA_WIFI_DEBUG_MODE_IOCTL: + { + int enable = 0; + if(copy_from_user(&enable, (void*)arg, sizeof(int))) { + printk(KERN_ERR "copy_from_user enable failed!\n"); + return -EFAULT; + } + ret = rda_5990_wifi_debug_en(enable); + break; + } + + case RDA_BT_POWER_ON_IOCTL: + ret = rda_5990_bt_power_on(); + break; + + /* should call this function after bt_power_on*/ + case RDA_BT_EN_CLK: + ret = RDA5990_bt_enable_clk(); + break; + + case RDA_BT_RF_INIT_IOCTL: + ret = RDA5990_bt_rf_init(); + break; + + case RDA_BT_DC_CAL_IOCTL: + ret = RDA5990_bt_dc_cal(); + break; + + case RDA_BT_DC_DIG_RESET_IOCTL: + ret = RDA5990_bt_dig_reset(); + break; + + case RDA_BT_RF_SWITCH_IOCTL: + ret = RDA5990_bt_set_rf_switch(); + break; + + case RDA_BT_POWER_OFF_IOCTL: + ret = rda_5990_bt_power_off(); + break; + + default: + { + ret = -EFAULT; + printk(KERN_ERR "******rda_5990_pw_ioctl cmd[0x%02x]******.\n", cmd); + break; + } + } + + printk(KERN_INFO "rda_bt_pw_ioctl cmd=0x%02x \n", cmd); + return ret; +} + diff --git a/drivers/net/wireless/rda/rda_combo_power_ctrl/rda_5991_power_ctrl.c b/drivers/net/wireless/rda/rda_combo_power_ctrl/rda_5991_power_ctrl.c new file mode 100755 index 00000000..58d1fca4 --- /dev/null +++ b/drivers/net/wireless/rda/rda_combo_power_ctrl/rda_5991_power_ctrl.c @@ -0,0 +1,725 @@ +#include "rda_combo.h" + +#ifdef WLAN_USE_DCDC +static const u16 pmu_setting[][2] = { + {0x3F, 0x0001}, + {0x22, 0xA1F3}, //Pu_rf_dr=0;Nonov_delay_dig=11,Nonov_delay_ana=11 + {0x24, 0x8808}, //pu_dcdc_dr_ana=0;pu_ldo_dr_ana=0;AVDD=2.07V;sleep vol=0000;clk_mode_sel_dr_ana =0 + {0x26, 0x8255}, //sleep voltage=800mV;clk_mode_sel_dr_dig=0 + {0x23, 0xC200}, //Dcdc_en_ana=1 + {0x25, 0xC27F}, //Dcdc_en_dig=1;sleep_ldo_vout=111=1.1v + {0x37, 0x0B8A}, + {0x39, 0x1200}, //for dcdc;uart_bypass_en + {0x3F, 0x0000}, +}; +#else +static const u16 pmu_setting[][2] = { + {0x3F, 0x0001}, + {0x22, 0xA1F3}, //Pu_rf_dr=0;Nonov_delay_dig=11,Nonov_delay_ana=11 + {0x24, 0x8808}, //pu_dcdc_dr_ana=0;pu_ldo_dr_ana=0;AVDD=2.07V;sleep vol=0000;clk_mode_sel_dr_ana =0 + {0x26, 0x8255}, //sleep voltage=800mV;clk_mode_sel_dr_dig=0;pu_ldo_dr_dig=1;pu_ldo_reg_dig =1 + {0x23, 0x4200}, //Dcdc_en_ana=0 + {0x25, 0x427F}, //Dcdc_en_dig=0;sleep_ldo_vout=111=1.1v + {0x37, 0x0B8A}, + {0x39, 0x1200}, //for dcdc;uart_bypass_en + {0x3F, 0x0000}, +}; +#endif + +/*add according to hongjun's new config*/ +static const u16 soft_reset[][2] = { + {0x3F, 0x0000}, + {0x30, 0x8000}, + {0x30, 0x0000}, +}; + +static const u16 wf_en[][2] = { + {0x3F, 0x0001}, + {0x31, 0x8B40}, //;WIFI_en=1 + {0x3F, 0x0000}, +}; + +static const u16 wifi_disable[][2] = { + {0x3F, 0x0001}, + {0x31, 0x0B40}, //;WIFI_en=0 + {0x3F, 0x0000}, +}; + +static const u16 wf_rf_setting[][2] = { + {0x3F, 0x0000}, + {0x10, 0x9f33}, //wf_lna_bpf_en =1 + {0x11, 0xFF8A}, + {0x13, 0x5054}, + {0x14, 0x988C}, //wf_pll_regbit_presc[3:0]=1100,for temperatrue + {0x15, 0x596F}, + {0x16, 0x200B}, //wf_pll_r_bit[1:0] =01;wf_pll_r_bit[1:0]=00 + {0x19, 0x9C01}, //wf_pll_sinc_mode[2:0]=001 ,ver D + {0x1C, 0x06E4}, //wf_dac_cm_bit[1:0]=00,1.1V + {0x1D, 0x3A8C}, + {0x22, 0xFF4B}, //ver D + {0x23, 0xAA3C}, + {0x24, 0x88C4}, //wf_dac_cal_dr=1;ver D + {0x28, 0x1320}, + {0x2A, 0x0036}, + {0x2B, 0x41BB}, //wf_ovd_resbit_for_wf_tx[7:0]=FF;wf_pa_cap2_open_for_wf_tx=1 + {0x2D, 0xFF03}, //wf_pa_capbit_for_wf_tx[7:0]=3 + {0x2F, 0x00DE}, //wf_dsp_resetn_tx_dr=1;wf_dsp_resetn_tx_reg=1; ;;wf_dsp_resetn_rx_dr=1;wf_dsp_resetn_rx_reg=1; + {0x34, 0x3000}, //wf_dac_clk_inv[1:0]=11 + {0x39, 0x8000}, + {0x40, 0x7FFF}, //wf_tmx_gain,wf_pabias + {0x41, 0xFFFF}, //wf_pabias +}; + +static const u16 wf_agc_setting_for_dccal[][2] = { + {0x3F, 0x0000}, + {0x0F, 0x61F7}, //;//0F + {0x0E, 0x61F0}, // + {0x0D, 0x60F0}, // + {0x0C, 0x6070}, // + {0x0B, 0x6030}, // + {0x0A, 0x6010}, // + {0x09, 0x7033}, // + {0x08, 0x6830}, //;;//08 + {0x3F, 0x0001}, + {0x07, 0x7031}, //;;//07 + {0x06, 0x7011}, //;;//06 + {0x05, 0x7871}, // + {0x04, 0x7831}, //;;//04 + {0x03, 0x7811}, //;;//03 + {0x02, 0x7801}, //;;//02 + {0x01, 0x7800}, //;;//01 + {0x00, 0x7800}, //;;//00 + {0x3F, 0x0000}, +}; + +static const u16 wf_agc_setting[][2] = { + {0x3F, 0x0000}, + {0x0F, 0x01F7}, //;//0F + {0x0E, 0x01F0}, // + {0x0D, 0x00F0}, // + {0x0C, 0x0070}, // + {0x0B, 0x0030}, // + {0x0A, 0x0010}, // + {0x09, 0x3033}, // + {0x08, 0x0830}, //;;//08 + {0x3F, 0x0001}, + {0x07, 0x7031}, //;;//07 + {0x06, 0x7011}, //;;//06 + {0x05, 0x7871}, // + {0x04, 0x7831}, //;;//04 + {0x03, 0x7811}, //;;//03 + {0x02, 0x7801}, //;;//02 + {0x01, 0x7800}, //;;//01 + {0x00, 0x7800}, //;;//00 + {0x3F, 0x0000}, +}; + +static const u16 wf_calibration[][2] = { +#if 1 //hongjun's new config + {0x3F,0x0000}, + {0x1a,0x0026},//设定频点2487MHZ + {0x1B,0xDC00},//设定频点2487MHZ + {0x28,0x1F20}, + {0x28,0x1320}, + {0x30,0x0159},//设定frequency mode + {0x30,0x0158}, + {0x30,0x0159},//dc_cal + DELAY_MS(200) +#else + {0x3F, 0x0000}, + {0x30, 0x0148}, + DELAY_MS(100) + {0x28, 0x1F20}, //mdll_startup + {0x28, 0x1320}, //mdll_startup_done + {0x30, 0x0149}, + DELAY_MS(100) + {0x30, 0x0349}, //wf_chip_self_cal_en=1 +#endif +}; + +static const u16 bt_rf_setting[][2] = { + {0x3F, 0x0000}, + {0x02, 0x0E00}, //BT_Agc<2:0>; + {0x08, 0xEFFF}, //bt_lna_gain2_7[2:0=11111 + {0x0A, 0x09FF}, //bt_rxflt_gain_5=11 + {0x11, 0x0035}, // + {0x13, 0x2C68}, // + {0x14, 0x91C4}, //bt_adc_digi_pwr_bit_reg[2:0]=011 + {0x18, 0x2010}, //bt_pll_phase_ctrl_dly[1:0]=00 + {0x30, 0x0141}, + {0x3F, 0x0001}, + {0x01, 0x66F3}, //bt_tmx_therm_gain_f[3:0]=0011 + {0x3F, 0x0000}, + {0x2E, 0xCAA3}, //bt_swtrx_dr=1;bt_swtrx_reg=1 + {0x37, 0x4411}, //PSK + {0x38, 0x1348}, //PSK + {0x3B, 0x2200}, //GFSK + {0x3C, 0x0124}, //GFSK + {0x3F, 0x0001}, + {0x00, 0xBBBB}, // + {0x01, 0x66F3}, // + {0x02, 0xBBBB}, // + {0x03, 0x66F3}, // + {0x04, 0xBBBB}, // + {0x05, 0x66F3}, // + {0x06, 0xBBBB}, // + {0x07, 0x66FF}, // + {0x08, 0xBBBB}, // + {0x09, 0x66F7}, // + {0x0A, 0xBBBB}, // + {0x0B, 0x66F0}, // + {0x39, 0x1200}, //uart_bypass_en=0 + {0x3F, 0x0000}, +}; + +static const u16 control_mode_disable[][2] = { +#if 1 //hongjun's new config + {0x3F,0x0000}, + {0x30,0x0149},//设定channel mode + {0x30,0x014D}, + {0x30,0x0141}, +#else + {0x3F, 0x0000}, + {0x30, 0x0141}, +#endif +}; + +static const u16 bt_en[][2] = { + {0x3F, 0x0001}, + {0x28, 0x85A1}, //;bt_en=1 + {0x3F, 0x0000}, +}; + +static const u16 bt_disable[][2] = { + {0x3F, 0x0001}, + {0x28, 0x05A1}, //;bt_en=1 + {0x3F, 0x0000}, +}; +static const u16 rda_5991_bt_dc_ca_fix_gain[][2] = +{ + {0x3f, 0x0000 }, + {0x30, 0x0141 }, + {0x30, 0x0140 }, + {0x30, 0x0141 }, + {0x30, 0x0341 }, //force gain level to 7 before lna issue fixed + {0x2e, 0x8aa3 }, //force gain level to 7 before lna issue fixed + {0x3f, 0x0000 }, +}; +static const u16 rda_5991_bt_dc_ca_fix_gain_no_wf[][2] = +{ + {0x3f, 0x0000 }, + {0x30, 0x0140 }, + {0x30, 0x0141 }, + {0x3f, 0x0000 }, +}; +// add for pta + +// add for pta +static const u16 rda_5991_bt_force_swtrx[][2] = +{ + {0x3f, 0x0000 }, + {0x2e, 0xcaa3 }, //force gain level to 7 before lna issue fixed + {0x3f, 0x0000 }, +}; +static const u16 rda_5991_bt_no_force_swtrx[][2] = +{ + {0x3f, 0x0000 }, + {0x2e, 0x8aa3 }, //force gain level to 7 before lna issue fixed + {0x3f, 0x0000 }, +}; + +static int check_wifi_power_on(void) +{ + int ret = 0; + u16 temp_data; + + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x3f, 0x0001); + if (ret) + goto err; + + ret = i2c_read_1_addr_2_data(rda_wifi_rf_client, 0x31, &temp_data); + if (ret) + goto err; + + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x3f, 0x0000); + + if (temp_data & 0x8000) + return 1; +err: + return 0; +} + +static int check_bt_power_on(void) +{ + int ret = 0; + u16 temp_data; + + ret = i2c_write_1_addr_2_data(rda_bt_rf_client, 0x3f, 0x0001); + if (ret) + goto err; + + ret = i2c_read_1_addr_2_data(rda_bt_rf_client, 0x28, &temp_data); + if (ret) + goto err; + + ret = i2c_write_1_addr_2_data(rda_bt_rf_client, 0x3f, 0x0000); + if (temp_data & 0x8000) + return 1; +err: + return 0; +} + +static int power_on(int isWifi) +{ + int ret = 0; + ret = RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, pmu_setting); + if (ret) + goto err; + printk(KERN_INFO "%s write pmu_setting succeed!! \n", __func__); + + if (isWifi) { // for wifi + ret = RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, wf_en); + if (ret) + goto err; + printk(KERN_INFO "%s write wf_en succeed!! \n", __func__); + } else { // for bt + ret = RDA_WRITE_DATA_TO_RF(rda_bt_rf_client, bt_en); + if (ret) + goto err; + printk(KERN_INFO "%s write bt_en succeed!! \n", __func__); + } + + rda_combo_i2c_unlock(); + msleep(5); + rda_combo_i2c_lock(); + + ret = RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, soft_reset); + if (ret) + goto power_off; + printk(KERN_INFO "%s write soft_reset succeed!! \n", __func__); + + rda_combo_i2c_unlock(); + msleep(10); + rda_combo_i2c_lock(); + + ret = RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, wf_rf_setting); + if (ret) + goto power_off; + printk(KERN_INFO "%s write wf_rf_setting succeed!! \n", __func__); + + ret = RDA_WRITE_DATA_TO_RF(rda_bt_rf_client, bt_rf_setting); + if (ret) + goto power_off; + printk(KERN_INFO "%s write bt_rf_setting succeed!! \n", __func__); + + ret = + RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, wf_agc_setting_for_dccal); + if (ret) + goto power_off; + printk(KERN_INFO "%s write wf_agc_setting_for_dccal succeed!! \n", + __func__); + + ret = RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, wf_calibration); + if (ret) + goto power_off; + printk(KERN_INFO "%s write wf_calibration succeed!! \n", __func__); + + ret = RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, wf_agc_setting); + if (ret) + goto power_off; + printk(KERN_INFO "%s write wf_agc_setting succeed!! \n", __func__); + + return 0; +power_off: + if (isWifi) { // for wifi + RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, wifi_disable); + } else { + RDA_WRITE_DATA_TO_RF(rda_bt_rf_client, bt_disable); + } +err: + return -1; +} + +static int rda_5991_wifi_debug_en(void) +{ + u16 temp_data = 0; + int ret = 0; + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x3f, 0x0001); + if (ret < 0) + return -1; + + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x28, 0x80a1); + if (ret < 0) + return -1; + ret = i2c_read_1_addr_2_data(rda_wifi_rf_client, 0x39, &temp_data); + if (ret < 0) + return -1; + + ret = + i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x39, temp_data | 0x04); + if (ret < 0) + return -1; + + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x3f, 0x0000); + if (ret < 0) + return -1; + return ret; +} + +int rda_5991_wifi_power_on(void) +{ + int ret = 0, bt_power_on = 0; + + //if bt is power on wait until it's complete + wait_for_completion(&rda_wifi_bt_comp); + + rda_combo_i2c_lock(); + #ifdef RDA_KERNEL_PLATFORM + enable_26m_regulator(CLOCK_WLAN); + enable_32k_rtc(CLOCK_WLAN); + enable_26m_rtc(CLOCK_WLAN); + #endif + bt_power_on = check_bt_power_on(); + printk(KERN_INFO "%s bt_power_on=%d \n", __func__, bt_power_on); + + if (bt_power_on) { + ret = RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, wf_en); + if (ret) + goto err; + printk(KERN_INFO "%s write wf_en succeed!! \n", __func__); + ret = RDA_WRITE_DATA_TO_RF(rda_bt_rf_client, rda_5991_bt_no_force_swtrx); + if (ret) + goto err; + printk(KERN_INFO "%s write rda_5991_bt_no_force_swtrx succeed!! \n", __func__); + rda_combo_i2c_unlock(); + msleep(5); + rda_combo_i2c_lock(); + } else { + ret = power_on(1); + if (ret) + goto err; + } + + ret = RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, control_mode_disable); + if (ret) + goto power_off; + printk(KERN_INFO "%s write control_mode_disable succeed!! \n", + __func__); + if (rda_combo_wifi_in_test_mode()) { + rda_5991_wifi_debug_en(); + printk(KERN_INFO + "%s: IN test mode, switch uart to WIFI succeed!! \n", + __func__); + } + + rda_combo_i2c_unlock(); + msleep(100); + complete(&rda_wifi_bt_comp); + return ret; + +power_off: + RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, wifi_disable); +err: + #ifdef RDA_KERNEL_PLATFORM + disable_26m_rtc(CLOCK_WLAN); + disable_32k_rtc(CLOCK_WLAN); + disable_26m_regulator(CLOCK_WLAN); + #endif + rda_combo_i2c_unlock(); + return -1; +} + +int rda_5991_wifi_power_off(void) +{ + int ret = 0; + int bt_power_on = 0; // add for pta + rda_combo_i2c_lock(); + bt_power_on = check_bt_power_on(); + if(bt_power_on){ + ret = RDA_WRITE_DATA_TO_RF(rda_bt_rf_client, rda_5991_bt_force_swtrx); + if (ret) { + printk(KERN_INFO "%s rda_5991_bt_force_swtrx failed!! \n", __func__); + } else { + printk(KERN_INFO "%s rda_5991_bt_force_swtrx succeed!! \n", __func__); + } + } + ret = RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, wifi_disable); + if (ret) { + printk(KERN_INFO "%s failed!! \n", __func__); + } else { + printk(KERN_INFO "%s succeed!! \n", __func__); + } + #ifdef RDA_KERNEL_PLATFORM + disable_26m_rtc(CLOCK_WLAN); + disable_32k_rtc(CLOCK_WLAN); + disable_26m_regulator(CLOCK_WLAN); + #endif + rda_combo_i2c_unlock(); + return ret; +} + +int rda_5991_bt_power_on(void) +{ + int ret = 0, wifi_power_on = 0; + + //if wifi is power on wait until it's complete + wait_for_completion(&rda_wifi_bt_comp); + + rda_combo_i2c_lock(); + #ifdef RDA_KERNEL_PLATFORM + enable_26m_regulator(CLOCK_BT); + enable_26m_rtc(CLOCK_BT); + enable_32k_rtc(CLOCK_BT); + #endif + wifi_power_on = check_wifi_power_on(); + printk(KERN_INFO "%s wifi_power_on=%d \n", __func__, wifi_power_on); + + if (wifi_power_on) { + ret = RDA_WRITE_DATA_TO_RF(rda_bt_rf_client, bt_en); + if (ret) + goto err; + printk(KERN_INFO "%s write bt_en succeed!! \n", __func__); + rda_combo_i2c_unlock(); + msleep(5); + rda_combo_i2c_lock(); + } else { + ret = power_on(0); + if (ret) + goto err; + } + + printk(KERN_INFO "%s succeed!! \n", __func__); + + rda_combo_i2c_unlock(); + msleep(10); + complete(&rda_wifi_bt_comp); + return ret; + +err: + #ifdef RDA_KERNEL_PLATFORM + disable_26m_rtc(CLOCK_BT); + disable_32k_rtc(CLOCK_BT); + disable_26m_regulator(CLOCK_BT); + #endif + rda_combo_i2c_unlock(); + return -1; +} + +int rda_5991_bt_power_off(void) +{ + int ret = 0; + rda_combo_i2c_lock(); + ret = RDA_WRITE_DATA_TO_RF(rda_bt_rf_client, bt_disable); + if (ret) { + printk(KERN_INFO "%s failed!! \n", __func__); + } else { + printk(KERN_INFO "%s succeed!! \n", __func__); + } + #ifdef RDA_KERNEL_PLATFORM + disable_26m_rtc(CLOCK_BT); + disable_32k_rtc(CLOCK_BT); + disable_26m_regulator(CLOCK_BT); + #endif + rda_combo_i2c_unlock(); + return ret; +} +// add for pta +static int RDA5991_bt_dc_cal_fix_gain(void) +{ + int ret = 0; + int is_wfen; + if(!rda_bt_rf_client){ + printk(KERN_INFO "rda_bt_rf_client is NULL!\n"); + return -1; + } + rda_combo_i2c_lock(); + is_wfen= check_wifi_power_on(); + if(rda_wlan_version() == WLAN_VERSION_91) + { + if(is_wfen) + { + ret = RDA_WRITE_DATA_TO_RF(rda_bt_rf_client, rda_5991_bt_dc_ca_fix_gain); + } + else + { + ret = RDA_WRITE_DATA_TO_RF(rda_bt_rf_client, rda_5991_bt_dc_ca_fix_gain_no_wf); + } + if(ret) + goto err; + } + rda_combo_i2c_unlock(); + printk(KERN_INFO "***RDA5991_bt_dc_cal_fix_gain_update success!!! \n"); + msleep(200); //200ms + return 0; +err: + rda_combo_i2c_unlock(); + printk(KERN_INFO "***RDA5991_bt_dc_cal_fix_gain failed! \n"); + return -1; +} + +long rda_5991_pw_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + int ret = 0; + + switch (cmd) { + case RDA_WIFI_POWER_ON_IOCTL: + ret = rda_5991_wifi_power_on(); + break; + + case RDA_WIFI_POWER_OFF_IOCTL: + ret = rda_5991_wifi_power_off(); + break; + + case RDA_BT_POWER_ON_IOCTL: + ret = rda_5991_bt_power_on(); + break; + + case RDA_BT_POWER_OFF_IOCTL: + ret = rda_5991_bt_power_off(); + break; + + case RDA_WIFI_DEBUG_MODE_IOCTL: + ret = rda_5991_wifi_debug_en(); + break; + case RDA_BT_DC_CAL_IOCTL_FIX_5991_LNA_GAIN: + ret = RDA5991_bt_dc_cal_fix_gain(); + break; + default: + break; + } + + printk(KERN_INFO "rda_bt_pw_ioctl cmd=0x%02x \n", cmd); + return ret; +} + +int rda_5991_fm_power_on(void) +{ + int ret = 0; + u16 temp = 0; + + if (!rda_wifi_rf_client) { + printk(KERN_INFO + "rda_wifi_rf_client is NULL, rda_fm_power_on failed!\n"); + return -1; + } + + enable_32k_rtc(CLOCK_FM); + msleep(8); + rda_combo_i2c_lock(); + + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x3f, 0x0001); // page down + if (ret < 0) { + printk(KERN_INFO + "%s() write address(0x%02x) with value(0x%04x) failed! \n", + __func__, 0x3f, 0x0001); + goto err; + } + + if (rda_wlan_version() == WLAN_VERSION_91) { + + ret = i2c_read_1_addr_2_data(rda_wifi_rf_client, 0x27, &temp); //read 0xA7 + if (ret < 0) { + printk(KERN_INFO + "%s() read from address(0x%02x) failed! \n", + __func__, 0xA7); + goto err; + } + temp = temp | 0x1; //set bit[0] + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x27, temp); //write back + if (ret < 0) { + printk(KERN_INFO + "%s() write address(0x%02x) with value(0x%04x) failed! \n", + __func__, 0xA7, temp); + goto err; + } + + ret = i2c_read_1_addr_2_data(rda_wifi_rf_client, 0x39, &temp); //read 0xB9 + if (ret < 0) { + printk(KERN_INFO + "%s() read from address(0x%02x) failed! \n", + __func__, 0xB9); + goto err; + } + temp = temp | (0x1 << 15); //set bit[15] + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x39, temp); //write back + if (ret < 0) { + printk(KERN_INFO + "%s() write address(0x%02x) with value(0x%04x) failed! \n", + __func__, 0xB9, temp); + goto err; + } + } + + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x3f, 0x0000); // page up + if (ret < 0) { + printk(KERN_INFO + "%s() write address(0x%02x) with value(0x%04x) failed! \n", + __func__, 0x3f, 0x0001); + goto err; + } + + rda_combo_i2c_unlock(); + return 0; + +err: + rda_combo_i2c_unlock(); + disable_32k_rtc(CLOCK_FM); + printk(KERN_INFO "***rda_fm_power_on failed! \n"); + return -1; +} + +int rda_5991_fm_power_off(void) +{ + int ret = 0; + u16 temp = 0; + + if (!rda_wifi_rf_client) { + printk(KERN_INFO + "rda_wifi_rf_client is NULL, rda_fm_power_off failed!\n"); + return -1; + } + + rda_combo_i2c_lock(); + + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x3f, 0x0001); // page down + if (ret < 0) { + printk(KERN_INFO + "%s() write address(0x%02x) with value(0x%04x) failed! \n", + __func__, 0x3f, 0x0001); + goto err; + } + + if (rda_wlan_version() == WLAN_VERSION_91) { + ret = i2c_read_1_addr_2_data(rda_wifi_rf_client, 0x27, &temp); //read 0xA7 + if (ret < 0) { + printk(KERN_INFO + "%s() read from address(0x%02x) failed! \n", + __func__, 0xA7); + goto err; + } + temp = temp & ~(0x1 << 15); //clear bit[0] + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x27, temp); //write back + if (ret < 0) { + printk(KERN_INFO + "%s() write address(0x%02x) with value(0x%04x) failed! \n", + __func__, 0xA7, temp); + goto err; + } + } + + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x3f, 0x0000); // page up + if (ret < 0) { + printk(KERN_INFO + "%s() write address(0x%02x) with value(0x%04x) failed! \n", + __func__, 0x3f, 0x0001); + goto err; + } + + rda_combo_i2c_unlock(); + disable_32k_rtc(CLOCK_FM); + return 0; +err: + rda_combo_i2c_unlock(); + printk(KERN_INFO "***rda_fm_power_off failed! \n"); + return -1; +} diff --git a/drivers/net/wireless/rda/rda_combo_power_ctrl/rda_5991e_power_ctrl.c b/drivers/net/wireless/rda/rda_combo_power_ctrl/rda_5991e_power_ctrl.c new file mode 100755 index 00000000..2c330e4c --- /dev/null +++ b/drivers/net/wireless/rda/rda_combo_power_ctrl/rda_5991e_power_ctrl.c @@ -0,0 +1,796 @@ +#include "rda_combo.h" + +#define COMBO_WITH_26MHZ + +#ifdef WLAN_USE_DCDC +static const u16 pmu_setting[][2] = { + {0x3F, 0x0001}, + {0x22, 0xA1F3}, + {0x24, 0x8906}, //{0x24, 0x8908} sleep mode with analog power on + {0x26, 0x8055}, + {0x33, 0x0510}, + {0x39, 0xC208}, + {0x23, 0xA200}, //{0x23, 0x8200} + {0x25, 0xA247}, //{0x25, 0x8247} heavy_load_dig + {0x37, 0x0B8A}, + {0x3F, 0x0000}, +}; +#else +static const u16 pmu_setting[][2] = { + {0x3F, 0x0001}, + {0x22, 0xA1F3}, + {0x24, 0x8906}, + {0x26, 0x8555}, + {0x33, 0x0510}, + {0x39, 0xC208}, + {0x23, 0x0200}, + {0x25, 0x027F}, + {0x3F, 0x0000}, +}; +#endif + +/*add according to hongjun's new config*/ +static const u16 soft_reset[][2] = { + {0x3F, 0x0000}, + {0x30, 0x8000}, + {0x30, 0x0000}, +}; + +static const u16 wf_en[][2] = { + {0x3F, 0x0001}, + {0x31, 0x8B40}, //;WIFI_en=1 + {0x3F, 0x0000}, +}; + +static const u16 wifi_disable[][2] = { + {0x3F, 0x0001}, + {0x31, 0x0B40}, //;WIFI_en=0 + {0x3F, 0x0000}, +}; + +#ifdef COMBO_WITH_26MHZ +static const u16 wf_rf_setting[][2] = { + {0x3F, 0x0000}, + {0x05, 0x0000}, + {0x06, 0x1124}, //wf_bbpll_cpaux_bit[2:0]=100 + {0x07, 0x0820}, + {0x10, 0x9ff7}, + {0x11, 0xFF8A}, + {0x13, 0x5054}, + {0x14, 0x988C}, + {0x15, 0x58e8}, + {0x16, 0x200B}, + {0x19, 0x9C01}, + {0x1C, 0x06E4}, + {0x1D, 0x3A8C}, + {0x22, 0xFF7B}, + {0x23, 0x283C}, + {0x24, 0xA0C4}, + {0x28, 0x4320}, + //add by LA, set different value according to different type 26M crystal + //{0x2A, 0x0036}, + {0x2A, 0x103A},//for pingwang a23 5991e + {0x2B, 0x41BB}, + {0x2D, 0xFF03}, + {0x2F, 0x15DE}, + {0x34, 0x3000}, + {0x35, 0x8011}, + {0x39, 0x6018}, + {0x3B, 0x3218}, + {0x40, 0x7FFF},//wf_tmx_gain,wf_pabias + {0x41, 0xFFFF}, + {0x7D, 0x4020},//paon delay + {0x3F, 0x0001}, + {0x37, 0x0B8A}, + {0x3F, 0x0000}, + {0x30, 0x0100}, + {0x28, 0x4F20}, + DELAY_MS(1) + {0x28, 0x4320}, + {0x30, 0x0149}, +}; +#else +static const u16 wf_rf_setting[][2] = { + {0x3F, 0x0000}, + {0x03, 0x16AA}, + {0x04, 0xAAAB}, + {0x05, 0x0000}, + {0x06, 0x1124}, //wf_bbpll_cpaux_bit[2:0]=100 + {0x07, 0x0820}, + {0x10, 0x9ff7}, + {0x11, 0xFF8A}, + {0x13, 0x5054}, + {0x14, 0x988C}, + {0x15, 0x58e8}, + {0x16, 0x200B}, + {0x19, 0x9C01}, + {0x1C, 0x06E4}, + {0x1D, 0x3A8C}, + {0x22, 0xFF7B}, + {0x23, 0x3D3C}, + {0x24, 0xA0C4}, + {0x27, 0x5318}, + {0x28, 0x3318}, + {0x2A, 0x0036}, + {0x2B, 0x41BB}, + {0x2D, 0xFF03}, + {0x2F, 0x15DE}, + {0x34, 0x3000}, + {0x35, 0x8011}, + {0x39, 0x6018}, + {0x3B, 0x3218}, + {0x40, 0x7FFF},//wf_tmx_gain,wf_pabias + {0x41, 0xFFFF}, + {0x7D, 0x4020},//paon delay + {0x3F, 0x0001}, + {0x37, 0x0B8A}, + {0x3F, 0x0000}, + {0x28, 0x1F20}, + {0x28, 0x1320}, + {0x30, 0x0100}, + {0x28, 0x3F18}, + DELAY_MS(1) + {0x28, 0x3318}, + {0x30, 0x0149}, +}; +#endif + +static const u16 wf_agc_setting_for_dccal[][2] = { + +}; + +static const u16 wf_agc_setting[][2] = { + {0x3F, 0x0000}, + {0x0F, 0x01F7}, + {0x0E, 0x01F0}, + {0x0D, 0x00F0}, + {0x0C, 0x0070}, + {0x0B, 0x0030}, + {0x0A, 0x0010}, + {0x09, 0x3033}, + {0x08, 0x0830}, + {0x3F, 0x0001}, + {0x07, 0x7030}, + {0x06, 0x7010}, + {0x05, 0x7870}, + {0x04, 0x7830}, + {0x03, 0x7811}, + {0x02, 0x7800}, + {0x01, 0x7800}, + {0x00, 0x7800}, + {0x3F, 0x0000}, +}; + +static const u16 wf_calibration[][2] = { + {0x3F, 0x0000}, + {0x30, 0x0148}, + {0x30, 0x0149}, + DELAY_MS(50) +}; + +static const u16 fix_agc_gain[][2] = { + {0x3F, 0x0000}, + {0x30, 0x0349}, +}; + +static const u16 bt_rf_setting[][2] = { + {0x3F, 0x0000}, + {0x02, 0x0E00}, + {0x08, 0xEFFF}, + {0x0A, 0x09FF}, + {0x11, 0x00B5}, + {0x13, 0x07C0}, + {0x14, 0xFDC4}, + {0x18, 0x2010}, + {0x19, 0x7956}, + {0x1B, 0xDFE0}, + {0x26, 0x7800}, + {0x2B, 0x007F}, + {0x2C, 0x600F}, + {0x2D, 0x007F}, +#ifdef COMBO_WITH_26MHZ + {0x2E, 0xCAB3}, +#else + {0x2E, 0xCAA3}, +#endif + {0x2F, 0x1000}, + {0x30, 0x0141}, + {0x37, 0x4244}, //PSK + {0x38, 0x4688}, //PSK + {0x3B, 0x2122}, //GFSK + {0x3C, 0x2355}, //GFSK + {0x3F, 0x0001}, + {0x00, 0xFFFF}, + {0x01, 0xFFFF}, // bt power + {0x02, 0xFFFF}, + {0x03, 0xFFF7}, + {0x04, 0xFFFF}, + {0x05, 0xFFF7}, + {0x06, 0xFFFF}, + {0x07, 0xFFF1}, + {0x08, 0xFFFF}, + {0x09, 0xFFE1}, + {0x0A, 0xFFFF}, + {0x0B, 0xFFE1}, + //{0x39, 0x1208}, + {0x3F, 0x0000}, +}; + +static const u16 control_mode_disable[][2] = { + {0x3F, 0x0000}, + {0x30, 0x0141}, +}; + +static const u16 bt_en[][2] = { + {0x3F, 0x0001}, + {0x28, 0x85A1}, //;bt_en=1 + {0x3F, 0x0000}, +}; + +static const u16 bt_disable[][2] = { + {0x3F, 0x0001}, + {0x28, 0x05A1}, //;bt_en=1 + {0x3F, 0x0000}, +}; +static const u16 rda_5991e_bt_dc_ca_fix_gain[][2] = +{ + {0x3f, 0x0000 }, + {0x30, 0x0141 }, + {0x30, 0x0140 }, + {0x30, 0x0141 }, +#ifdef COMBO_WITH_26MHZ + {0x2e, 0x8ab3 }, //force gain level to 7 before lna issue fixed +#else + {0x2e, 0x8aa3 }, //force gain level to 7 before lna issue fixed +#endif + {0x3f, 0x0000 }, +}; +static const u16 rda_5991e_bt_dc_ca_fix_gain_no_wf[][2] = +{ + {0x3f, 0x0000 }, + {0x30, 0x0140 }, + {0x30, 0x0141 }, + {0x3f, 0x0000 }, +}; +static const u16 rda_5991e_bt_force_swtrx[][2] = +{ + {0x3f, 0x0000 }, +#ifdef COMBO_WITH_26MHZ + {0x2e, 0xcab3 }, //force gain level to 7 before lna issue fixed +#else + {0x2e, 0xcaa3 }, //force gain level to 7 before lna issue fixed +#endif + {0x3f, 0x0000 }, +}; +static const u16 rda_5991e_bt_no_force_swtrx[][2] = +{ + {0x3f, 0x0000 }, +#ifdef COMBO_WITH_26MHZ + {0x2e, 0x8ab3 }, //force gain level to 7 before lna issue fixed +#else + {0x2e, 0x8aa3 }, //force gain level to 7 before lna issue fixed +#endif + {0x3f, 0x0000 }, +}; + +static const u16 bt_dc_cal[][2] = { + {0x3F, 0x0000}, + {0x30, 0x0140}, + {0x30, 0x0141}, + DELAY_MS(50) +}; +static int check_wifi_power_on(void) +{ + int ret = 0; + u16 temp_data; + + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x3f, 0x0001); + if (ret) + goto err; + + ret = i2c_read_1_addr_2_data(rda_wifi_rf_client, 0x31, &temp_data); + if (ret) + goto err; + + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x3f, 0x0000); + + if (temp_data & 0x8000) + return 1; +err: + return 0; +} + +static int check_bt_power_on(void) +{ + int ret = 0; + u16 temp_data; + + ret = i2c_write_1_addr_2_data(rda_bt_rf_client, 0x3f, 0x0001); + if (ret) + goto err; + + ret = i2c_read_1_addr_2_data(rda_bt_rf_client, 0x28, &temp_data); + if (ret) + goto err; + + ret = i2c_write_1_addr_2_data(rda_bt_rf_client, 0x3f, 0x0000); + if (temp_data & 0x8000) + return 1; +err: + return 0; +} + +static int power_on(int isWifi) +{ + int ret = 0; + ret = RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, pmu_setting); + if (ret) + goto err; + printk(KERN_INFO "%s write pmu_setting succeed!! \n", __func__); + + if (isWifi) { // for wifi + ret = RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, wf_en); + if (ret) + goto err; + printk(KERN_INFO "%s write wf_en succeed!! \n", __func__); + } else { // for bt + ret = RDA_WRITE_DATA_TO_RF(rda_bt_rf_client, bt_en); + if (ret) + goto err; + printk(KERN_INFO "%s write bt_en succeed!! \n", __func__); + } + + rda_combo_i2c_unlock(); + msleep(5); + rda_combo_i2c_lock(); + + ret = RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, soft_reset); + if (ret) + goto power_off; + printk(KERN_INFO "%s write soft_reset succeed!! \n", __func__); + + rda_combo_i2c_unlock(); + msleep(10); + rda_combo_i2c_lock(); + + ret = RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, wf_rf_setting); + if (ret) + goto power_off; + printk(KERN_INFO "%s write wf_rf_setting succeed!! \n", __func__); + + ret = RDA_WRITE_DATA_TO_RF(rda_bt_rf_client, bt_rf_setting); + if (ret) + goto power_off; + printk(KERN_INFO "%s write bt_rf_setting succeed!! \n", __func__); + + ret = RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, wf_agc_setting); + if (ret) + goto power_off; + printk(KERN_INFO "%s write wf_agc_setting succeed!! \n", + __func__); + + ret = RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, wf_calibration); + if (ret) + goto power_off; + printk(KERN_INFO "%s write wf_calibration succeed!! \n", __func__); + + + ret = RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, fix_agc_gain); + if(ret) + goto power_off; + printk(KERN_INFO "%s write fix_agc_gain succeed!! \n", __func__); + return 0; +power_off: + if (isWifi) { // for wifi + RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, wifi_disable); + } else { + RDA_WRITE_DATA_TO_RF(rda_bt_rf_client, bt_disable); + } +err: + return -1; +} + +static int rda_5991e_wifi_debug_en(int enable) +{ + u16 temp_data = 0; + int ret = 0; + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x3f, 0x0001); + if (ret < 0) + return -1; + if (enable == 1){ + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x28, 0x80a1); + if (ret < 0) + return -1; + ret = i2c_read_1_addr_2_data(rda_wifi_rf_client, 0x39, &temp_data); + if (ret < 0) + return -1; + + ret = + i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x39, temp_data | (1 << 2)); + if (ret < 0) + return -1; + }else{ + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x28, 0x00a1); + if (ret < 0) + return -1; + ret = i2c_read_1_addr_2_data(rda_wifi_rf_client, 0x39, &temp_data); + if (ret < 0) + return -1; + ret = + i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x39, temp_data & (~(1 << 2))); + if (ret < 0) + return -1; + } + + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x3f, 0x0000); + if (ret < 0) + return -1; + return ret; +} + +int rda_5991e_wifi_power_on(void) +{ + int ret = 0, bt_power_on = 0; + + //if bt is power on wait until it's complete + wait_for_completion(&rda_wifi_bt_comp); + + rda_combo_i2c_lock(); + #ifdef RDA_KERNEL_PLATFORM + enable_26m_regulator(CLOCK_WLAN); + enable_32k_rtc(CLOCK_WLAN); + enable_26m_rtc(CLOCK_WLAN); + #endif + bt_power_on = check_bt_power_on(); + printk(KERN_INFO "%s bt_power_on=%d \n", __func__, bt_power_on); + + if (bt_power_on) { + ret = RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, wf_en); + if (ret) + goto err; + printk(KERN_INFO "%s write wf_en succeed!! \n", __func__); + //add for pta + //handle btswtrx dr + ret = RDA_WRITE_DATA_TO_RF(rda_bt_rf_client, rda_5991e_bt_no_force_swtrx); + if (ret) + goto err; + printk(KERN_INFO "%s write rda_5991_bt_no_force_swtrx succeed!! \n", __func__); + rda_combo_i2c_unlock(); + msleep(5); + rda_combo_i2c_lock(); + } else { + ret = power_on(1); + if (ret) + goto err; + } + + ret = RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, control_mode_disable); + if (ret) + goto power_off; + printk(KERN_INFO "%s write control_mode_disable succeed!! \n", __func__); + if (rda_combo_wifi_in_test_mode()) { + rda_5991e_wifi_debug_en(1); + printk(KERN_INFO "%s: IN test mode, switch uart to WIFI succeed!! \n", __func__); + } + + rda_combo_i2c_unlock(); + msleep(100); + complete(&rda_wifi_bt_comp); + return ret; + +power_off: + RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, wifi_disable); +err: +#ifdef RDA_KERNEL_PLATFORM + disable_26m_rtc(CLOCK_WLAN); + disable_32k_rtc(CLOCK_WLAN); + disable_26m_regulator(CLOCK_WLAN); +#endif + rda_combo_i2c_unlock(); + return -1; +} + +int rda_5991e_wifi_power_off(void) +{ + int ret = 0, bt_power_on = 0; + rda_combo_i2c_lock(); + bt_power_on = check_bt_power_on(); + if(bt_power_on){ + ret = RDA_WRITE_DATA_TO_RF(rda_bt_rf_client, rda_5991e_bt_force_swtrx); + if (ret) { + printk(KERN_INFO "%s rda_5991_bt_force_swtrx failed!! \n", __func__); + } else { + printk(KERN_INFO "%s rda_5991_bt_force_swtrx succeed!! \n", __func__); + } + } + ret = RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, wifi_disable); + if (ret) { + printk(KERN_INFO "%s failed!! \n", __func__); + } else { + printk(KERN_INFO "%s succeed!! \n", __func__); + } + bt_power_on = check_bt_power_on(); + if (bt_power_on) { + ret = RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, fix_agc_gain); + printk(KERN_INFO "%s write fix_agc_gain succeed!! \n", __func__); + } + #ifdef RDA_KERNEL_PLATFORM + disable_26m_rtc(CLOCK_WLAN); + disable_32k_rtc(CLOCK_WLAN); + disable_26m_regulator(CLOCK_WLAN); + #endif + rda_combo_i2c_unlock(); + return ret; +} + +int rda_5991e_bt_power_on(void) +{ + int ret = 0, wifi_power_on = 0; + + //if wifi is power on wait until it's complete + wait_for_completion(&rda_wifi_bt_comp); + + rda_combo_i2c_lock(); + #ifdef RDA_KERNEL_PLATFORM + enable_26m_regulator(CLOCK_BT); + enable_26m_rtc(CLOCK_BT); + enable_32k_rtc(CLOCK_BT); +#endif + + wifi_power_on = check_wifi_power_on(); + printk(KERN_INFO "%s wifi_power_on=%d \n", __func__, wifi_power_on); + + if (wifi_power_on) { + ret = RDA_WRITE_DATA_TO_RF(rda_bt_rf_client, bt_en); + if (ret) + goto err; + printk(KERN_INFO "%s write bt_en succeed!! \n", __func__); + rda_combo_i2c_unlock(); + msleep(5); + rda_combo_i2c_lock(); + } else { + ret = power_on(0); + if (ret) + goto err; + } + + printk(KERN_INFO "%s succeed!! \n", __func__); + + rda_combo_i2c_unlock(); + msleep(10); + complete(&rda_wifi_bt_comp); + return ret; + +err: +#ifdef RDA_KERNEL_PLATFORM + disable_26m_rtc(CLOCK_BT); + disable_32k_rtc(CLOCK_BT); + disable_26m_regulator(CLOCK_BT); +#endif + rda_combo_i2c_unlock(); + return -1; +} + +int rda_5991e_bt_power_off(void) +{ + int ret = 0; + rda_combo_i2c_lock(); + ret = RDA_WRITE_DATA_TO_RF(rda_bt_rf_client, bt_disable); + if (ret) { + printk(KERN_INFO "%s failed!! \n", __func__); + } else { + printk(KERN_INFO "%s succeed!! \n", __func__); + } + #ifdef RDA_KERNEL_PLATFORM + disable_26m_rtc(CLOCK_BT); + disable_32k_rtc(CLOCK_BT); + disable_26m_regulator(CLOCK_BT); + #endif + rda_combo_i2c_unlock(); + return ret; +} +static int RDA5991e_bt_dc_cal_fix_gain(void) +{ + int ret = 0; + int is_wfen; + + if(!rda_bt_rf_client){ + printk(KERN_INFO "rda_bt_rf_client is NULL!\n"); + return -1; + } + rda_combo_i2c_lock(); + is_wfen= check_wifi_power_on(); + if(rda_wlan_version() == WLAN_VERSION_91_E) + { + if(is_wfen) + { + ret = RDA_WRITE_DATA_TO_RF(rda_bt_rf_client, rda_5991e_bt_dc_ca_fix_gain); + } + else + { + ret = RDA_WRITE_DATA_TO_RF(rda_bt_rf_client, rda_5991e_bt_dc_ca_fix_gain_no_wf); + } + if(ret) + goto err; + } + rda_combo_i2c_unlock(); + printk(KERN_INFO "***RDA5991e_bt_dc_cal_fix_gain success!!!\n"); + msleep(200); //200ms + return 0; +err: + rda_combo_i2c_unlock(); + printk(KERN_INFO "***RDA5991e_bt_dc_cal_fix_gain failed! \n"); + return -1; +} +long rda_5991e_pw_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + int ret = 0; + + switch (cmd) { + case RDA_WIFI_POWER_ON_IOCTL: + ret = rda_5991e_wifi_power_on(); + break; + + case RDA_WIFI_POWER_OFF_IOCTL: + ret = rda_5991e_wifi_power_off(); + break; + + case RDA_BT_POWER_ON_IOCTL: + ret = rda_5991e_bt_power_on(); + break; + + case RDA_BT_POWER_OFF_IOCTL: + ret = rda_5991e_bt_power_off(); + break; + + case RDA_WIFI_DEBUG_MODE_IOCTL: + { + int enable = 0; + if(copy_from_user(&enable, (void*)arg, sizeof(int))) { + printk(KERN_ERR "copy_from_user enable failed!\n"); + return -EFAULT; + } + ret = rda_5991e_wifi_debug_en(enable); + break; + } + case RDA_BT_DC_CAL_IOCTL_FIX_5991_LNA_GAIN: + ret = RDA5991e_bt_dc_cal_fix_gain(); + break; + default: + break; + } + + printk(KERN_INFO "rda_bt_pw_ioctl cmd=0x%02x \n", cmd); + return ret; +} + +int rda_5991e_fm_power_on(void) +{ + int ret = 0; + u16 temp = 0; + + if (!rda_wifi_rf_client) { + printk(KERN_INFO + "rda_wifi_rf_client is NULL, rda_fm_power_on failed!\n"); + return -1; + } + + enable_32k_rtc(CLOCK_FM); + msleep(8); + rda_combo_i2c_lock(); + + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x3f, 0x0001); // page down + if (ret < 0) { + printk(KERN_INFO "%s() write address(0x%02x) with value(0x%04x) failed! \n", + __func__, 0x3f, 0x0001); + goto err; + } + + if (rda_wlan_version() == WLAN_VERSION_91_E) { + + ret = i2c_read_1_addr_2_data(rda_wifi_rf_client, 0x27, &temp); //read 0xA7 + if (ret < 0) { + printk(KERN_INFO "%s() read from address(0x%02x) failed! \n", + __func__, 0xA7); + goto err; + } + temp = temp | 0x1; //set bit[0] + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x27, temp); //write back + if (ret < 0) { + printk(KERN_INFO "%s() write address(0x%02x) with value(0x%04x) failed! \n", + __func__, 0xA7, temp); + goto err; + } + + ret = i2c_read_1_addr_2_data(rda_wifi_rf_client, 0x39, &temp); //read 0xB9 + if (ret < 0) { + printk(KERN_INFO "%s() read from address(0x%02x) failed! \n", + __func__, 0xB9); + goto err; + } + temp = temp & 0x7fff; //set bit[15]=0 + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x39, temp); //write back + if (ret < 0) { + printk(KERN_INFO "%s() write address(0x%02x) with value(0x%04x) failed! \n", + __func__, 0xB9, temp); + goto err; + } + + temp = temp | (0x1 << 15); //set bit[15] + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x39, temp); //write back + if (ret < 0) { + printk(KERN_INFO "%s() write address(0x%02x) with value(0x%04x) failed! \n", + __func__, 0xB9, temp); + goto err; + } + } + + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x3f, 0x0000); // page up + if (ret < 0) { + printk(KERN_INFO "%s() write address(0x%02x) with value(0x%04x) failed! \n", + __func__, 0x3f, 0x0001); + goto err; + } + + rda_combo_i2c_unlock(); + return 0; + +err: + rda_combo_i2c_unlock(); + disable_32k_rtc(CLOCK_FM); + printk(KERN_INFO "***rda_fm_power_on failed! \n"); + return -1; +} + +int rda_5991e_fm_power_off(void) +{ + int ret = 0; + u16 temp = 0; + + if (!rda_wifi_rf_client) { + printk(KERN_INFO + "rda_wifi_rf_client is NULL, rda_fm_power_off failed!\n"); + return -1; + } + + rda_combo_i2c_lock(); + + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x3f, 0x0001); // page down + if (ret < 0) { + printk(KERN_INFO "%s() write address(0x%02x) with value(0x%04x) failed! \n", + __func__, 0x3f, 0x0001); + goto err; + } + + if (rda_wlan_version() == WLAN_VERSION_91_E) { + ret = i2c_read_1_addr_2_data(rda_wifi_rf_client, 0x27, &temp); //read 0xA7 + if (ret < 0) { + printk(KERN_INFO "%s() read from address(0x%02x) failed! \n", + __func__, 0xA7); + goto err; + } + temp = temp & ~(0x1 << 15); //clear bit[0] + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x27, temp); //write back + if (ret < 0) { + printk(KERN_INFO "%s() write address(0x%02x) with value(0x%04x) failed! \n", + __func__, 0xA7, temp); + goto err; + } + } + + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x3f, 0x0000); // page up + if (ret < 0) { + printk(KERN_INFO "%s() write address(0x%02x) with value(0x%04x) failed! \n", + __func__, 0x3f, 0x0001); + goto err; + } + + rda_combo_i2c_unlock(); + disable_32k_rtc(CLOCK_FM); + return 0; +err: + rda_combo_i2c_unlock(); + printk(KERN_INFO "***rda_fm_power_off failed! \n"); + return -1; +} + diff --git a/drivers/net/wireless/rda/rda_combo_power_ctrl/rda_5991f_power_ctrl.c b/drivers/net/wireless/rda/rda_combo_power_ctrl/rda_5991f_power_ctrl.c new file mode 100755 index 00000000..dfc64ffb --- /dev/null +++ b/drivers/net/wireless/rda/rda_combo_power_ctrl/rda_5991f_power_ctrl.c @@ -0,0 +1,803 @@ +#include "rda_combo.h" + +#define COMBO_WITH_26MHZ + +#ifdef WLAN_USE_DCDC +static const u16 pmu_setting[][2] = { + {0x3F, 0x0001}, + {0x22, 0xA1F3}, + {0x24, 0x8906}, //{0x24, 0x8908} sleep mode with analog power on + {0x26, 0x8057}, + {0x33, 0x0510}, + {0x39, 0x420C}, + {0x23, 0xA200}, //{0x23, 0x8200} + {0x25, 0xA247}, //{0x25, 0x8247} heavy_load_dig + {0x37, 0x0B8A}, + {0x3F, 0x0000}, +}; +#else +static const u16 pmu_setting[][2] = { + {0x3F, 0x0001}, + {0x22, 0xA1F3}, + {0x24, 0x8908}, + {0x26, 0x8555}, + {0x33, 0x0510}, + {0x39, 0x120C}, + {0x23, 0x0200}, + {0x25, 0x027F}, + {0x3F, 0x0000}, +}; +#endif + +/*add according to hongjun's new config*/ +static const u16 soft_reset[][2] = { + {0x3F, 0x0000}, + {0x30, 0x8000}, + {0x30, 0x0000}, +}; + +static const u16 wf_en[][2] = { + {0x3F, 0x0001}, + {0x31, 0x8B40}, //;WIFI_en=1 + {0x3F, 0x0000}, +}; + +static const u16 wifi_disable[][2] = { + {0x3F, 0x0001}, + {0x31, 0x0B40}, //;WIFI_en=0 + {0x3F, 0x0000}, +}; + +#ifdef COMBO_WITH_26MHZ +static const u16 wf_rf_setting[][2] = { + {0x3F, 0x0000}, + {0x05, 0x0000}, + {0x06, 0x193F}, //wf_bbpll_cpaux_bit[2:0]=100 + {0x07, 0x0820}, + {0x10, 0x9ff7}, + {0x11, 0xFF8A}, + {0x13, 0x5054}, + {0x14, 0x988C}, + {0x15, 0x58eF}, + {0x16, 0x200B}, + {0x19, 0x9C01}, + {0x1C, 0x06E4}, + {0x1D, 0x3A8C}, + {0x22, 0xFF7B}, + {0x23, 0x283C}, + {0x24, 0xA0C4}, + {0x28, 0x4320}, + {0x2A, 0x1036},//{0x2A, 0x0077} + {0x2B, 0x41BB}, + {0x2D, 0xFF03}, + {0x2F, 0x00DE}, + {0x34, 0x3000}, + {0x35, 0x8011}, + {0x39, 0x8C00}, + {0x40, 0x7FFF},//wf_tmx_gain,wf_pabias + {0x41, 0xFFFF}, + {0x3F, 0x0001}, + {0x37, 0x0B8A}, + {0x3F, 0x0000}, + {0x30, 0x0100}, + {0x28, 0x4F20}, + DELAY_MS(1) + {0x28, 0x4320}, + {0x30, 0x0149}, +}; +#else +static const u16 wf_rf_setting[][2] = { + {0x3F, 0x0000}, + {0x03, 0x16AA}, + {0x04, 0xAAAB}, + {0x05, 0x0000}, + {0x06, 0x112C}, //wf_bbpll_cpaux_bit[2:0]=100 + {0x07, 0x0820}, + {0x10, 0x9ff7}, + {0x11, 0xFF8A}, + {0x13, 0x5054}, + {0x14, 0x988C}, + {0x15, 0x58eF}, + {0x16, 0x200B}, + {0x19, 0x9C01}, + {0x1C, 0x06E4}, + {0x1D, 0x3A8C}, + {0x22, 0xFF7B}, + {0x23, 0x3D3C}, + {0x24, 0xA0C4}, + {0x27, 0x5318}, + {0x28, 0x3318}, + {0x2A, 0x0036}, + {0x2B, 0x41BB}, + {0x2D, 0xFF03}, + {0x2F, 0x00DE}, + {0x34, 0x3000}, + {0x35, 0x8011}, + {0x39, 0x8C00}, + {0x40, 0x7FFF},//wf_tmx_gain,wf_pabias + {0x41, 0xFFFF}, + {0x3F, 0x0001}, + {0x37, 0x0B8A}, + {0x3F, 0x0000}, + {0x28, 0x1F20}, + {0x28, 0x1320}, + {0x30, 0x0100}, + {0x28, 0x3F18}, + DELAY_MS(1) + {0x28, 0x3318}, + {0x30, 0x0149}, +}; +#endif + +static const u16 wf_agc_setting_for_dccal[][2] = { + +}; + +static const u16 wf_agc_setting[][2] = { + {0x3F, 0x0000}, + {0x0F, 0x01F7}, + {0x0E, 0x01F0}, + {0x0D, 0x00F0}, + {0x0C, 0x0070}, + {0x0B, 0x0030}, + {0x0A, 0x0010}, + {0x09, 0x3033}, + {0x08, 0x0830}, + {0x3F, 0x0001}, + {0x07, 0x7031}, + {0x06, 0x7011}, + {0x05, 0x7001}, + {0x04, 0x7831}, + {0x03, 0x7811}, + {0x02, 0x7801}, + {0x01, 0x7800}, + {0x00, 0x7800}, + {0x3F, 0x0000}, +}; + +static const u16 wf_calibration[][2] = { + {0x3F, 0x0000}, + {0x30, 0x0148}, + {0x30, 0x0149}, + DELAY_MS(50) +}; + +static const u16 fix_agc_gain[][2] = { + {0x3F, 0x0000}, + {0x30, 0x0349}, +}; + +static const u16 bt_rf_setting[][2] = { + {0x3F, 0x0000}, + {0x02, 0x0E00}, + {0x08, 0xEFFF}, + {0x0A, 0x09FF}, + {0x11, 0x00B5}, + {0x13, 0x07C0}, + {0x14, 0xFDC4}, + {0x18, 0x2010}, + {0x19, 0x7956}, + {0x1B, 0xDFE0}, + {0x26, 0x7800}, + {0x2B, 0x007F}, + {0x2C, 0x600F}, + {0x2D, 0x007F}, +#ifdef COMBO_WITH_26MHZ + {0x2E, 0xCAB3}, +#else + {0x2E, 0xCAA3}, +#endif + {0x2F, 0x1000}, + {0x30, 0x0141}, + {0x37, 0x4244}, //PSK + {0x38, 0x4688}, //PSK + {0x3B, 0x2122}, //GFSK + {0x3C, 0x2355}, //GFSK + {0x3F, 0x0001}, + {0x00, 0xFFFF}, + {0x01, 0xFFFF}, // bt power + {0x02, 0xFFFF}, + {0x03, 0xFFF7}, + {0x04, 0xFFFF}, + {0x05, 0xFFF7}, + {0x06, 0xFFFF}, + {0x07, 0xFFF1}, + {0x08, 0xFFFF}, + {0x09, 0xFFE1}, + {0x0A, 0xFFFF}, + {0x0B, 0xFFE1}, + {0x39, 0x1208}, + {0x3F, 0x0000}, +}; + +static const u16 control_mode_disable[][2] = { + {0x3F, 0x0000}, + {0x30, 0x0141}, +}; + +static const u16 bt_en[][2] = { + {0x3F, 0x0001}, + {0x28, 0x85A1}, //;bt_en=1 + {0x3F, 0x0000}, +}; + +static const u16 bt_disable[][2] = { + {0x3F, 0x0001}, + {0x28, 0x05A1}, //;bt_en=1 + {0x3F, 0x0000}, +}; + +// add for pta +static const u16 rda_5991f_bt_dc_ca_fix_gain[][2] = +{ + {0x3f, 0x0000 }, + {0x30, 0x0141 }, + {0x30, 0x0140 }, + {0x30, 0x0141 }, +// {0x30, 0x0341 }, //force gain level to 7 before lna issue fixed +#ifdef COMBO_WITH_26MHZ + {0x2e, 0x8ab3 }, //force gain level to 7 before lna issue fixed +#else + {0x2e, 0x8aa3 }, //force gain level to 7 before lna issue fixed +#endif + {0x3f, 0x0000 }, +}; +// add for pta + +// add for pta +static const u16 rda_5991f_bt_dc_ca_fix_gain_no_wf[][2] = +{ + {0x3f, 0x0000 }, + {0x30, 0x0140 }, + {0x30, 0x0141 }, + {0x3f, 0x0000 }, +}; +// add for pta + +// add for pta +static const u16 rda_5991f_bt_force_swtrx[][2] = +{ + {0x3f, 0x0000 }, +#ifdef COMBO_WITH_26MHZ + {0x2e, 0xcab3 }, //force gain level to 7 before lna issue fixed +#else + {0x2e, 0xcaa3 }, //force gain level to 7 before lna issue fixed +#endif + {0x3f, 0x0000 }, +}; +// add for pta + +// add for pta +static const u16 rda_5991f_bt_no_force_swtrx[][2] = +{ + {0x3f, 0x0000 }, +#ifdef COMBO_WITH_26MHZ + {0x2e, 0x8ab3 }, //force gain level to 7 before lna issue fixed +#else + {0x2e, 0x8aa3 }, //force gain level to 7 before lna issue fixed +#endif + {0x3f, 0x0000 }, +}; +// add for pta + + + +static const u16 bt_dc_cal[][2] = { + {0x3F, 0x0000}, + {0x30, 0x0140}, + {0x30, 0x0141}, + DELAY_MS(50) +}; +static int check_wifi_power_on(void) +{ + int ret = 0; + u16 temp_data; + + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x3f, 0x0001); + if (ret) + goto err; + + ret = i2c_read_1_addr_2_data(rda_wifi_rf_client, 0x31, &temp_data); + if (ret) + goto err; + + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x3f, 0x0000); + + if (temp_data & 0x8000) + return 1; +err: + return 0; +} + +static int check_bt_power_on(void) +{ + int ret = 0; + u16 temp_data; + + ret = i2c_write_1_addr_2_data(rda_bt_rf_client, 0x3f, 0x0001); + if (ret) + goto err; + + ret = i2c_read_1_addr_2_data(rda_bt_rf_client, 0x28, &temp_data); + if (ret) + goto err; + + ret = i2c_write_1_addr_2_data(rda_bt_rf_client, 0x3f, 0x0000); + if (temp_data & 0x8000) + return 1; +err: + return 0; +} + +static int power_on(int isWifi) +{ + int ret = 0; + ret = RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, pmu_setting); + if (ret) + goto err; + printk(KERN_INFO "%s write pmu_setting succeed!! \n", __func__); + + if (isWifi) { // for wifi + ret = RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, wf_en); + if (ret) + goto err; + printk(KERN_INFO "%s write wf_en succeed!! \n", __func__); + } else { // for bt + ret = RDA_WRITE_DATA_TO_RF(rda_bt_rf_client, bt_en); + if (ret) + goto err; + printk(KERN_INFO "%s write bt_en succeed!! \n", __func__); + } + + rda_combo_i2c_unlock(); + msleep(5); + rda_combo_i2c_lock(); + + ret = RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, soft_reset); + if (ret) + goto power_off; + printk(KERN_INFO "%s write soft_reset succeed!! \n", __func__); + + rda_combo_i2c_unlock(); + msleep(10); + rda_combo_i2c_lock(); + + ret = RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, wf_rf_setting); + if (ret) + goto power_off; + printk(KERN_INFO "%s write wf_rf_setting succeed!! \n", __func__); + + ret = RDA_WRITE_DATA_TO_RF(rda_bt_rf_client, bt_rf_setting); + if (ret) + goto power_off; + printk(KERN_INFO "%s write bt_rf_setting succeed!! \n", __func__); + + ret = RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, wf_agc_setting); + if (ret) + goto power_off; + printk(KERN_INFO "%s write wf_agc_setting succeed!! \n", + __func__); + + ret = RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, wf_calibration); + if (ret) + goto power_off; + printk(KERN_INFO "%s write wf_calibration succeed!! \n", __func__); + + ret = RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, fix_agc_gain); + if(ret) + goto power_off; + printk(KERN_INFO "%s write fix_agc_gain succeed!! \n", __func__); + return 0; +power_off: + if (isWifi) { // for wifi + RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, wifi_disable); + } else { + RDA_WRITE_DATA_TO_RF(rda_bt_rf_client, bt_disable); + } +err: + return -1; +} + +static int rda_5991f_wifi_debug_en(int enable) +{ + u16 temp_data = 0; + int ret = 0; + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x3f, 0x0001); + if (ret < 0) + return -1; + if (enable == 1){ + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x28, 0x80a1); + if (ret < 0) + return -1; + ret = i2c_read_1_addr_2_data(rda_wifi_rf_client, 0x39, &temp_data); + if (ret < 0) + return -1; + + ret = + i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x39, temp_data | (1 << 2)); + if (ret < 0) + return -1; + }else{ + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x28, 0x00a1); + if (ret < 0) + return -1; + ret = i2c_read_1_addr_2_data(rda_wifi_rf_client, 0x39, &temp_data); + if (ret < 0) + return -1; + + ret = + i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x39, temp_data & (~(1 << 2))); + if (ret < 0) + return -1; + } + + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x3f, 0x0000); + if (ret < 0) + return -1; + return ret; +} + +int rda_5991f_wifi_power_on(void) +{ + int ret = 0, bt_power_on = 0; + + //if bt is power on wait until it's complete + wait_for_completion(&rda_wifi_bt_comp); + + rda_combo_i2c_lock(); + enable_26m_regulator(CLOCK_WLAN); + enable_32k_rtc(CLOCK_WLAN); + enable_26m_rtc(CLOCK_WLAN); + bt_power_on = check_bt_power_on(); + printk(KERN_INFO "%s bt_power_on=%d \n", __func__, bt_power_on); + + if (bt_power_on) { + ret = RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, wf_en); + if (ret) + goto err; + printk(KERN_INFO "%s write wf_en succeed!! \n", __func__); + + //add for pta + //handle btswtrx dr + ret = RDA_WRITE_DATA_TO_RF(rda_bt_rf_client, rda_5991f_bt_no_force_swtrx); + if (ret) + goto err; + printk(KERN_INFO "%s write rda_5991_bt_no_force_swtrx succeed!! \n", __func__); + // add for pta + rda_combo_i2c_unlock(); + msleep(5); + rda_combo_i2c_lock(); + } else { + ret = power_on(1); + if (ret) + goto err; + } + + ret = RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, control_mode_disable); + if (ret) + goto power_off; + printk(KERN_INFO "%s write control_mode_disable succeed!! \n", __func__); + if (rda_combo_wifi_in_test_mode()) { + rda_5991f_wifi_debug_en(1); + printk(KERN_INFO "%s: IN test mode, switch uart to WIFI succeed!! \n", __func__); + } + + rda_combo_i2c_unlock(); + msleep(100); + disable_26m_rtc(CLOCK_WLAN); + complete(&rda_wifi_bt_comp); + return ret; + +power_off: + RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, wifi_disable); +err: + disable_26m_rtc(CLOCK_WLAN); + disable_32k_rtc(CLOCK_WLAN); + disable_26m_regulator(CLOCK_WLAN); + rda_combo_i2c_unlock(); + return -1; +} + +int rda_5991f_wifi_power_off(void) +{ + int ret = 0, bt_power_on = 0; + rda_combo_i2c_lock(); + bt_power_on = check_bt_power_on(); + //add for pta + if(bt_power_on){ + ret = RDA_WRITE_DATA_TO_RF(rda_bt_rf_client, rda_5991f_bt_force_swtrx); + if (ret) { + printk(KERN_INFO "%s rda_5991_bt_force_swtrx failed!! \n", __func__); + } else { + printk(KERN_INFO "%s rda_5991_bt_force_swtrx succeed!! \n", __func__); + } + } + // add for pta + ret = RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, wifi_disable); + if (ret) { + printk(KERN_INFO "%s failed!! \n", __func__); + } else { + printk(KERN_INFO "%s succeed!! \n", __func__); + } + + bt_power_on = check_bt_power_on(); + if (bt_power_on) { + ret = RDA_WRITE_DATA_TO_RF(rda_wifi_rf_client, fix_agc_gain); + printk(KERN_INFO "%s write fix_agc_gain succeed!! \n", __func__); + } + disable_26m_rtc(CLOCK_WLAN); + disable_32k_rtc(CLOCK_WLAN); + disable_26m_regulator(CLOCK_WLAN); + rda_combo_i2c_unlock(); + return ret; +} + +int rda_5991f_bt_power_on(void) +{ + int ret = 0, wifi_power_on = 0; + + //if wifi is power on wait until it's complete + wait_for_completion(&rda_wifi_bt_comp); + + rda_combo_i2c_lock(); + enable_26m_regulator(CLOCK_BT); + enable_26m_rtc(CLOCK_BT); + enable_32k_rtc(CLOCK_BT); + + wifi_power_on = check_wifi_power_on(); + printk(KERN_INFO "%s wifi_power_on=%d \n", __func__, wifi_power_on); + + if (wifi_power_on) { + ret = RDA_WRITE_DATA_TO_RF(rda_bt_rf_client, bt_en); + if (ret) + goto err; + printk(KERN_INFO "%s write bt_en succeed!! \n", __func__); + rda_combo_i2c_unlock(); + msleep(5); + rda_combo_i2c_lock(); + } else { + ret = power_on(0); + if (ret) + goto err; + } + + printk(KERN_INFO "%s succeed!! \n", __func__); + + rda_combo_i2c_unlock(); + msleep(10); + disable_26m_rtc(CLOCK_BT); + complete(&rda_wifi_bt_comp); + return ret; + +err: + disable_26m_rtc(CLOCK_BT); + disable_32k_rtc(CLOCK_BT); + disable_26m_regulator(CLOCK_BT); + rda_combo_i2c_unlock(); + return -1; +} + +int rda_5991f_bt_power_off(void) +{ + int ret = 0; + rda_combo_i2c_lock(); + ret = RDA_WRITE_DATA_TO_RF(rda_bt_rf_client, bt_disable); + if (ret) { + printk(KERN_INFO "%s failed!! \n", __func__); + } else { + printk(KERN_INFO "%s succeed!! \n", __func__); + } + disable_26m_rtc(CLOCK_BT); + disable_32k_rtc(CLOCK_BT); + disable_26m_regulator(CLOCK_BT); + rda_combo_i2c_unlock(); + return ret; +} +// add for pta +static int RDA5991f_bt_dc_cal_fix_gain(void) +{ + int ret = 0; + int is_wfen; + + if(!rda_bt_rf_client){ + printk(KERN_INFO "rda_bt_rf_client is NULL!\n"); + return -1; + } + + rda_combo_i2c_lock(); + is_wfen= check_wifi_power_on(); + //check the version and make sure this applies to 5991 + if(rda_wlan_version() == WLAN_VERSION_91_F) + { + if(is_wfen) + { + ret = RDA_WRITE_DATA_TO_RF(rda_bt_rf_client, rda_5991f_bt_dc_ca_fix_gain); + } + else + { + ret = RDA_WRITE_DATA_TO_RF(rda_bt_rf_client, rda_5991f_bt_dc_ca_fix_gain_no_wf); + } + + if(ret) + goto err; + } + + rda_combo_i2c_unlock(); + printk(KERN_INFO "***RDA5991f_bt_dc_cal_fix_gain success!!!\n"); + msleep(200); //200ms + + return 0; + +err: + rda_combo_i2c_unlock(); + printk(KERN_INFO "***RDA5991f_bt_dc_cal_fix_gain failed! \n"); + return -1; + +} +// add for pta +long rda_5991f_pw_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + int ret = 0; + + switch (cmd) { + case RDA_WIFI_POWER_ON_IOCTL: + ret = rda_5991f_wifi_power_on(); + break; + + case RDA_WIFI_POWER_OFF_IOCTL: + ret = rda_5991f_wifi_power_off(); + break; + + case RDA_BT_POWER_ON_IOCTL: + ret = rda_5991f_bt_power_on(); + break; + + case RDA_BT_POWER_OFF_IOCTL: + ret = rda_5991f_bt_power_off(); + break; + + case RDA_WIFI_DEBUG_MODE_IOCTL: + { + int enable = 0; + if(copy_from_user(&enable, (void*)arg, sizeof(int))) { + printk(KERN_ERR "copy_from_user enable failed!\n"); + return -EFAULT; + } + ret = rda_5991f_wifi_debug_en(enable); + break; + } + // add for pta + case RDA_BT_DC_CAL_IOCTL_FIX_5991_LNA_GAIN: + ret = RDA5991f_bt_dc_cal_fix_gain(); + break; + // add for pta + default: + break; + } + + printk(KERN_INFO "rda_bt_pw_ioctl cmd=0x%02x \n", cmd); + return ret; +} + +int rda_5991f_fm_power_on(void) +{ + int ret = 0; + u16 temp = 0; + + if (!rda_wifi_rf_client) { + printk(KERN_INFO + "rda_wifi_rf_client is NULL, rda_fm_power_on failed!\n"); + return -1; + } + + enable_32k_rtc(CLOCK_FM); + msleep(8); + rda_combo_i2c_lock(); + + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x3f, 0x0001); // page down + if (ret < 0) { + printk(KERN_INFO "%s() write address(0x%02x) with value(0x%04x) failed! \n", + __func__, 0x3f, 0x0001); + goto err; + } + + if (rda_wlan_version() == WLAN_VERSION_91_F) { + + ret = i2c_read_1_addr_2_data(rda_wifi_rf_client, 0x27, &temp); //read 0xA7 + if (ret < 0) { + printk(KERN_INFO "%s() read from address(0x%02x) failed! \n", + __func__, 0xA7); + goto err; + } + temp = temp | 0x1; //set bit[0] + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x27, temp); //write back + if (ret < 0) { + printk(KERN_INFO "%s() write address(0x%02x) with value(0x%04x) failed! \n", + __func__, 0xA7, temp); + goto err; + } + + ret = i2c_read_1_addr_2_data(rda_wifi_rf_client, 0x39, &temp); //read 0xB9 + if (ret < 0) { + printk(KERN_INFO "%s() read from address(0x%02x) failed! \n", + __func__, 0xB9); + goto err; + } + temp = temp | (0x1 << 15); //set bit[15] + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x39, temp); //write back + if (ret < 0) { + printk(KERN_INFO "%s() write address(0x%02x) with value(0x%04x) failed! \n", + __func__, 0xB9, temp); + goto err; + } + } + + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x3f, 0x0000); // page up + if (ret < 0) { + printk(KERN_INFO "%s() write address(0x%02x) with value(0x%04x) failed! \n", + __func__, 0x3f, 0x0001); + goto err; + } + + rda_combo_i2c_unlock(); + return 0; + +err: + rda_combo_i2c_unlock(); + disable_32k_rtc(CLOCK_FM); + printk(KERN_INFO "***rda_fm_power_on failed! \n"); + return -1; +} + +int rda_5991f_fm_power_off(void) +{ + int ret = 0; + u16 temp = 0; + + if (!rda_wifi_rf_client) { + printk(KERN_INFO + "rda_wifi_rf_client is NULL, rda_fm_power_off failed!\n"); + return -1; + } + + rda_combo_i2c_lock(); + + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x3f, 0x0001); // page down + if (ret < 0) { + printk(KERN_INFO "%s() write address(0x%02x) with value(0x%04x) failed! \n", + __func__, 0x3f, 0x0001); + goto err; + } + + if (rda_wlan_version() == WLAN_VERSION_91_F) { + ret = i2c_read_1_addr_2_data(rda_wifi_rf_client, 0x27, &temp); //read 0xA7 + if (ret < 0) { + printk(KERN_INFO "%s() read from address(0x%02x) failed! \n", + __func__, 0xA7); + goto err; + } + temp = temp & ~(0x1 << 15); //clear bit[0] + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x27, temp); //write back + if (ret < 0) { + printk(KERN_INFO "%s() write address(0x%02x) with value(0x%04x) failed! \n", + __func__, 0xA7, temp); + goto err; + } + } + + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x3f, 0x0000); // page up + if (ret < 0) { + printk(KERN_INFO "%s() write address(0x%02x) with value(0x%04x) failed! \n", + __func__, 0x3f, 0x0001); + goto err; + } + + rda_combo_i2c_unlock(); + disable_32k_rtc(CLOCK_FM); + return 0; +err: + rda_combo_i2c_unlock(); + printk(KERN_INFO "***rda_fm_power_off failed! \n"); + return -1; +} + diff --git a/drivers/net/wireless/rda/rda_combo_power_ctrl/rda_combo.h b/drivers/net/wireless/rda/rda_combo_power_ctrl/rda_combo.h new file mode 100755 index 00000000..935e2722 --- /dev/null +++ b/drivers/net/wireless/rda/rda_combo_power_ctrl/rda_combo.h @@ -0,0 +1,132 @@ +#ifndef __RDA_COMBO_H__ +#define __RDA_COMBO_H__ + +#include +#include +#include +#include +#include +#include +#include +#include + +//if not RDA Platform,for example, you use Allwinner platform ,don't define RDA_KERNEL_PLATFORM +//#define RDA_KERNEL_PLATFORM +#define RDA_BT_IOCTL_MAGIC 'u' + +/* bt module */ +#define RDA_BT_POWER_ON_IOCTL _IO(RDA_BT_IOCTL_MAGIC ,0x01) +#define RDA_BT_RF_INIT_IOCTL _IO(RDA_BT_IOCTL_MAGIC ,0x02) +#define RDA_BT_DC_CAL_IOCTL _IO(RDA_BT_IOCTL_MAGIC ,0x03) +#define RDA_BT_RF_SWITCH_IOCTL _IO(RDA_BT_IOCTL_MAGIC ,0x04) +#define RDA_BT_POWER_OFF_IOCTL _IO(RDA_BT_IOCTL_MAGIC ,0x05) +#define RDA_BT_EN_CLK _IO(RDA_BT_IOCTL_MAGIC ,0x06) +#define RDA_BT_DC_DIG_RESET_IOCTL _IO(RDA_BT_IOCTL_MAGIC ,0x07) +#define RDA_BT_GET_ADDRESS_IOCTL _IO(RDA_BT_IOCTL_MAGIC ,0x08) +// add for pta +#define RDA_BT_DC_CAL_IOCTL_FIX_5991_LNA_GAIN _IO(RDA_BT_IOCTL_MAGIC ,0x26) +// add for pta +/* wifi module */ +#define RDA_WIFI_POWER_ON_IOCTL _IO(RDA_BT_IOCTL_MAGIC ,0x10) +#define RDA_WIFI_POWER_OFF_IOCTL _IO(RDA_BT_IOCTL_MAGIC ,0x11) +#define RDA_WIFI_POWER_SET_TEST_MODE_IOCTL _IO(RDA_BT_IOCTL_MAGIC ,0x12) +#define RDA_WIFI_POWER_CANCEL_TEST_MODE_IOCTL _IO(RDA_BT_IOCTL_MAGIC ,0x13) +#define RDA_WIFI_DEBUG_MODE_IOCTL _IO(RDA_BT_IOCTL_MAGIC ,0x14) +#define RDA_WLAN_COMBO_VERSION _IO(RDA_BT_IOCTL_MAGIC ,0x15) +#define RDA_COMBO_I2C_OPS _IO(RDA_BT_IOCTL_MAGIC ,0x16) + + +//#define WLAN_USE_CRYSTAL // if use share crystal should close this +#define WLAN_USE_DCDC // if use LDO mode, should close this +//#define WLAN_FOR_CTA // if need pass CTA authenticate, should open this define + +#define WLAN_USE_CRYSTAL +//config the correct channel according to schematic diagram +#define RDA_I2C_CHANNEL (4) +#define RDA_WIFI_CORE_ADDR (0x13) +#define RDA_WIFI_RF_ADDR (0x14) //correct add is 0x14 +#define RDA_BT_CORE_ADDR (0x15) +#define RDA_BT_RF_ADDR (0x16) + +#define I2C_MASTER_ACK (1<<0) +#define I2C_MASTER_RD (1<<4) +#define I2C_MASTER_STO (1<<8) +#define I2C_MASTER_WR (1<<12) +#define I2C_MASTER_STA (1<<16) +#define RDA_I2C_SPEED 100*1000 +#define WLAN_VERSION_90_D (1) +#define WLAN_VERSION_90_E (2) +#define WLAN_VERSION_91 (3) +#define WLAN_VERSION_91_E (4) +#define WLAN_VERSION_91_F (5) + +#define CLOCK_WLAN (1 << 0) +#define CLOCK_BT (1 << 1) +#define CLOCK_FM (1 << 2) +#define CLOCK_GPS (1 << 3) +#define CLOCK_MASK_ALL (0x0f) + +#define I2C_DELAY_FLAG (0xFFFF) +#define DELAY_MS(x) {I2C_DELAY_FLAG, x}, +#define RDA_WIFI_RF_I2C_DEVNAME "rda_wifi_rf_i2c" +#define RDA_WIFI_CORE_I2C_DEVNAME "rda_wifi_core_i2c" +#define RDA_BT_RF_I2C_DEVNAME "rda_bt_rf_i2c" +#define RDA_BT_CORE_I2C_DEVNAME "rda_bt_core_i2c" + +extern struct i2c_client * rda_wifi_core_client; +extern struct i2c_client * rda_wifi_rf_client; +extern struct i2c_client * rda_bt_core_client; +extern struct i2c_client * rda_bt_rf_client; +extern struct completion rda_wifi_bt_comp; + + +int i2c_write_1_addr_2_data(struct i2c_client* client, const u8 addr, const u16 data); +int i2c_read_1_addr_2_data(struct i2c_client* client, const u8 addr, u16* data); +int rda_write_data_to_rf(struct i2c_client* client, const u16 (*data)[2], u32 count); +#define RDA_WRITE_DATA_TO_RF(CLIENT, ARRAY_DATA) rda_write_data_to_rf(CLIENT, ARRAY_DATA, sizeof(ARRAY_DATA)/sizeof(ARRAY_DATA[0])) + +void enable_26m_regulator(u8 mask); +void disable_26m_regulator(u8 mask); +void enable_32k_rtc(u8 mask); +void disable_32k_rtc(u8 mask); +void enable_26m_rtc(u8 mask); +void disable_26m_rtc(u8 mask); + +void rda_combo_i2c_lock(void); +void rda_combo_i2c_unlock(void); + +u32 rda_wlan_version(void); +unsigned char rda_combo_wifi_in_test_mode(void); + +int rda_5990_wifi_power_off(void); +int rda_5990_wifi_power_on(void); +int rda_5990_bt_power_on(void); +int rda_5990_bt_power_off(void); +int rda_5990_fm_power_on(void); +int rda_5990_fm_power_off(void); +long rda_5990_pw_ioctl(struct file *file, unsigned int cmd, unsigned long arg); + +int rda_5991_wifi_power_on(void); +int rda_5991_wifi_power_off(void); +int rda_5991_bt_power_on(void); +int rda_5991_bt_power_off(void); +int rda_5991_fm_power_on(void); +int rda_5991_fm_power_off(void); +long rda_5991_pw_ioctl(struct file *file, unsigned int cmd, unsigned long arg); +int rda_5991e_wifi_power_on(void); +int rda_5991f_wifi_power_on(void); +int rda_5991e_wifi_power_off(void); +int rda_5991f_wifi_power_off(void); +int rda_5991e_bt_power_on(void); +int rda_5991f_bt_power_on(void); +int rda_5991e_bt_power_off(void); +int rda_5991f_bt_power_off(void); +int rda_5991e_fm_power_on(void); +int rda_5991f_fm_power_on(void); +int rda_5991e_fm_power_off(void); +int rda_5991f_fm_power_off(void); +long rda_5991e_pw_ioctl(struct file *file, unsigned int cmd, unsigned long arg); +long rda_5991f_pw_ioctl(struct file *file, unsigned int cmd, unsigned long arg); + +#endif + diff --git a/drivers/net/wireless/rda/rda_combo_power_ctrl/rda_combo_power_main.c b/drivers/net/wireless/rda/rda_combo_power_ctrl/rda_combo_power_main.c new file mode 100755 index 00000000..a54ffead --- /dev/null +++ b/drivers/net/wireless/rda/rda_combo_power_ctrl/rda_combo_power_main.c @@ -0,0 +1,1282 @@ +/* ----------------------------------------------------------------------- * + * + This file created by albert RDA Inc + */ + +#include +#include +#include +#include /* get the user-level API */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +//#include +//#include +//#include +#include "rda_combo.h" +#include +//#include +#include //WMT_MMAP_OFFSET +#include //for pwm +#include +#include +#include +#include +#include +#include +#include +void set_wifi_name(char * name); +static void enable_pwm1_32KHz(int enable); +static struct mutex i2c_rw_lock; +static struct rfkill *wlan_rfkill = NULL; +static struct rfkill *bt_rfkill = NULL; +static struct platform_device *platform_device; +static unsigned short wlan_version = 0; +static struct wake_lock rda_combo_wake_lock; +static struct delayed_work rda_combo_sleep_worker; +static struct work_struct rda_bt_interrupt; +struct i2c_client *rda_wifi_core_client = NULL; +struct i2c_client *rda_wifi_rf_client = NULL; +struct i2c_client *rda_bt_core_client = NULL; +struct i2c_client *rda_bt_rf_client = NULL; +struct completion rda_wifi_bt_comp; +struct regulator *combo_reg; + +static unsigned int bt_host_wake=9; +static unsigned int bt_host_wake_irq; + +static u8 isBigEnded = 0; +static u8 wifi_in_test_mode = 0; +#ifdef RDA_KERNEL_PLATFORM +static u8 clock_mask_32k = 0; +static u8 clock_mask_26m = 0; +static u8 regulator_mask = 0; +static struct clk * clk32k = NULL; +static struct clk * clk26m = NULL; +#endif +void enable_26m_regulator(u8 mask) +{ + #ifdef RDA_KERNEL_PLATFORM + if (regulator_mask & CLOCK_MASK_ALL) { + } else { + regulator_enable(combo_reg); + } + regulator_mask |= mask; + #endif + +} +void disable_26m_regulator(u8 mask) +{ + #ifdef RDA_KERNEL_PLATFORM + if (regulator_mask & mask) { + regulator_mask &= ~mask; + if (regulator_mask & CLOCK_MASK_ALL) { + } else { + regulator_disable(combo_reg); + } + } + #endif +} +void enable_32k_rtc(u8 mask) +{ + #ifdef RDA_KERNEL_PLATFORM + if (clock_mask_32k & CLOCK_MASK_ALL) { + + } else { + clk_prepare_enable(clk32k); + } + clock_mask_32k |= mask; + #endif +} + +void disable_32k_rtc(u8 mask) +{ + #ifdef RDA_KERNEL_PLATFORM + if (clock_mask_32k & mask) { + clock_mask_32k &= ~mask; + if (clock_mask_32k & CLOCK_MASK_ALL) { + + } else { + clk_disable_unprepare(clk32k); + } + } + #endif +} + +void enable_26m_rtc(u8 mask) +{ + #ifdef RDA_KERNEL_PLATFORM + if (clock_mask_26m & CLOCK_MASK_ALL) { + + } else { + clk_prepare_enable(clk26m); + } + clock_mask_26m |= mask; + #endif +} + +void disable_26m_rtc(u8 mask) +{ + #ifdef RDA_KERNEL_PLATFORM + if (clock_mask_26m & mask) { + clock_mask_26m &= ~mask; + if (clock_mask_26m & CLOCK_MASK_ALL) { + + } else { + clk_disable_unprepare(clk26m); + } + } + #endif +} + +int i2c_write_1_addr_2_data(struct i2c_client *client, const u8 addr, + const u16 data) +{ + unsigned char tmp_data[3]; + int ret = 0; + int retry = 3; + + if (!isBigEnded) { + tmp_data[0] = addr; + tmp_data[1] = data >> 8; + tmp_data[2] = data >> 0; + } else { + tmp_data[0] = addr; + tmp_data[1] = data >> 0; + tmp_data[2] = data >> 8; + } + + while (retry--) { + ret = i2c_master_send(client, (char *)tmp_data, 3); + if (ret >= 0) { + break; + } + } + + if (ret < 0) { + printk(KERN_INFO + "***i2c_write_1_addr_2_data send:0x%X err:%d bigendia: %d \n", + addr, ret, isBigEnded); + return -1; + } else { + return 0; + } + +} + +int i2c_read_1_addr_2_data(struct i2c_client *client, const u8 addr, u16 * data) +{ + unsigned char tmp_data[2]; + int ret = 0; + int retry = 3; + + while (retry--) { + ret = i2c_master_send(client, (char *)&addr, 1); + if (ret >= 0) { + break; + } + } + + if (ret < 0) { + printk(KERN_INFO "***i2c_read_1_addr_2_data send:0x%X err:%d\n", + addr, ret); + return -1; + } + + retry = 3; + while (retry--) { + ret = i2c_master_recv(client, tmp_data, 2); + if (ret >= 0) { + break; + } + } + + if (ret < 0) { + printk(KERN_INFO "***i2c_read_1_addr_2_data send:0x%X err:%d\n", + addr, ret); + return -1; + } + + if (!isBigEnded) { + *data = (tmp_data[0] << 8) | tmp_data[1]; + } else { + *data = (tmp_data[1] << 8) | tmp_data[0]; + } + return 0; +} + +static void wlan_read_version_from_chip(void) +{ + int ret; + u16 project_id = 0, chip_version = 0; + + if (wlan_version != 0 || !rda_wifi_rf_client) + return; + + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x3f, 0x0001); + if (ret) + goto err; + + ret = i2c_read_1_addr_2_data(rda_wifi_rf_client, 0x21, &chip_version); + if (ret) + goto err; + + ret = i2c_read_1_addr_2_data(rda_wifi_rf_client, 0x20, &project_id); + if (ret) + goto err; + + if (project_id == 0x5990) { + if (chip_version == 0x47) + wlan_version = WLAN_VERSION_90_D; + else if (chip_version == 0x44 || chip_version == 0x45) + wlan_version = WLAN_VERSION_90_E; + } else if (project_id == 0x5991) { + set_wifi_name("rda5991.ko"); + if (chip_version == 0x44) + wlan_version = WLAN_VERSION_91; + else if(chip_version == 0x45) + wlan_version = WLAN_VERSION_91_E; + else if(chip_version == 0x46) + wlan_version = WLAN_VERSION_91_F; + } + + printk("read project_id:%x version:%x wlan_version:%x \n", project_id, + chip_version, wlan_version); +err: + ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x3f, 0x0000); + return; + +} + +int rda_write_data_to_rf(struct i2c_client *client, const u16(*data)[2], + u32 count) +{ + int ret = 0; + u32 i = 0; + + for (i = 0; i < count; i++) { + if (data[i][0] == I2C_DELAY_FLAG) { + msleep(data[i][2]); + continue; + } + ret = i2c_write_1_addr_2_data(client, data[i][0], data[i][1]); + if (ret < 0) + break; + } + return ret; +} + +u32 rda_wlan_version(void) +{ + if(wlan_version == 0) + wlan_read_version_from_chip(); + return wlan_version; +} + +static int rda_wifi_rf_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int result = 0; + + rda_wifi_rf_client = client; + printk("rda_wifi_rf_probe \n"); + return result; +} + +static int rda_wifi_rf_remove(struct i2c_client *client) +{ + return 0; +} + +static int rda_wifi_rf_detect(struct i2c_client *client, + struct i2c_board_info *info) +{ + strcpy(info->type, RDA_WIFI_RF_I2C_DEVNAME); + return 0; +} + +static const struct i2c_device_id wifi_rf_i2c_id[] = + { {RDA_WIFI_RF_I2C_DEVNAME, RDA_I2C_CHANNEL}, {} }; +static struct i2c_driver rda_wifi_rf_driver = { + //.class = I2C_CLASS_HWMON, + .probe = rda_wifi_rf_probe, + .remove = rda_wifi_rf_remove, + .detect = rda_wifi_rf_detect, + .driver.name = RDA_WIFI_RF_I2C_DEVNAME, + .id_table = wifi_rf_i2c_id, +}; + +static int rda_wifi_core_detect(struct i2c_client *client, + struct i2c_board_info *info) +{ + strcpy(info->type, RDA_WIFI_CORE_I2C_DEVNAME); + return 0; +} + +static int rda_wifi_core_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int result = 0; + + rda_wifi_core_client = client; + printk("rda_wifi_core_probe \n"); + return result; +} + + +static int rda_suspend(struct i2c_client *client, pm_message_t state) +{ + + return 0; +} + +static int rda_resume(struct i2c_client *client) +{ + enable_pwm1_32KHz(1); + return 0; +} + + +static int rda_wifi_core_remove(struct i2c_client *client) +{ + return 0; +} + +int rda_wifi_power_off(void) +{ + if (wlan_version == WLAN_VERSION_90_D + || wlan_version == WLAN_VERSION_90_E) + return rda_5990_wifi_power_off(); + else if (wlan_version == WLAN_VERSION_91) + return rda_5991_wifi_power_off(); + else if (wlan_version == WLAN_VERSION_91_E) + return rda_5991e_wifi_power_off(); + else if (wlan_version == WLAN_VERSION_91_F) + return rda_5991f_wifi_power_off(); + return 0; +} + +int rda_wifi_power_on(void) +{ + wlan_read_version_from_chip(); + if (wlan_version == WLAN_VERSION_90_D + || wlan_version == WLAN_VERSION_90_E) { + return rda_5990_wifi_power_on(); + } else if (wlan_version == WLAN_VERSION_91) + return rda_5991_wifi_power_on(); + else if (wlan_version == WLAN_VERSION_91_E) + return rda_5991e_wifi_power_on(); + else if (wlan_version == WLAN_VERSION_91_F) + return rda_5991f_wifi_power_on(); + return 0; +} + +static void rda_wifi_shutdown(struct i2c_client *client) +{ + printk("rda_wifi_shutdown \n"); + rda_wifi_power_off(); +} + +static const struct i2c_device_id wifi_core_i2c_id[] = + { {RDA_WIFI_CORE_I2C_DEVNAME, RDA_I2C_CHANNEL}, {} }; +static struct i2c_driver rda_wifi_core_driver = { + //.class = I2C_CLASS_HWMON, + .probe = rda_wifi_core_probe, + .remove = rda_wifi_core_remove, + .detect = rda_wifi_core_detect, + .shutdown = rda_wifi_shutdown, + .suspend = rda_suspend, + .resume = rda_resume, + .driver.name = RDA_WIFI_CORE_I2C_DEVNAME, + .id_table = wifi_core_i2c_id, +}; + +static int rda_bt_rf_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int result = 0; + + rda_bt_rf_client = client; + printk("rda_bt_rf_probe \n"); + return result; +} + +static int rda_bt_rf_remove(struct i2c_client *client) +{ + rda_bt_rf_client = NULL; + return 0; +} + +static int rda_bt_rf_detect(struct i2c_client *client, + struct i2c_board_info *info) +{ + strcpy(info->type, RDA_BT_RF_I2C_DEVNAME); + return 0; +} + +static const struct i2c_device_id bt_rf_i2c_id[] = + { {RDA_BT_RF_I2C_DEVNAME, RDA_I2C_CHANNEL}, {} }; +static struct i2c_driver rda_bt_rf_driver = { + //.class = I2C_CLASS_HWMON, + .probe = rda_bt_rf_probe, + .remove = rda_bt_rf_remove, + .detect = rda_bt_rf_detect, + .driver.name = RDA_BT_RF_I2C_DEVNAME, + .id_table = bt_rf_i2c_id, +}; + +static int rda_bt_core_detect(struct i2c_client *client, + struct i2c_board_info *info) +{ + strcpy(info->type, RDA_BT_CORE_I2C_DEVNAME); + return 0; +} + +void rda_combo_set_wake_lock(void); + +#ifdef CONFIG_BLUEZ_SUPPORT +extern void hci_bt_wakeup_host(void); +#endif + + +static irqreturn_t rda_bt_host_wake_eirq_handler(int irq, void *dev_id) +{ + + int pin_state; + + if(!is_gpio_irqenable(bt_host_wake) || !gpio_irqstatus(bt_host_wake)) + return IRQ_NONE; + + pin_state = gpio_direction_input(bt_host_wake); + + + if(pin_state == 0) + { + printk("irq_handler\n"); + + +#ifdef CONFIG_BLUEZ_SUPPORT + hci_bt_wakeup_host(); + +#endif + //int *p=NULL,aaa; + //aaa=*p+3; + printk("rda_bt_host_wake_eirq_handler\n"); + //rda_combo_set_wake_lock(); + schedule_work(&rda_bt_interrupt); + + + + } + else + { + printk("fake interruption:%d\n",pin_state); + } + + + + return IRQ_HANDLED; +} + +int aaaa; +//tip,for different platform, you must check how to realize a interrupt. +int bt_register_host_wake_irq(void *dev) +{ + int ret = 0; +#ifdef ALLWINNER + script_item_u val; + script_item_value_type_e type; + + type = script_get_item("wifi_para", "rda5990_bt_host_wake", &val); + if (SCIRPT_ITEM_VALUE_TYPE_PIO!=type) + { + printk("get RDA rda5990_bt_host_wake gpio failed\n"); + goto err; + + } + else + bt_host_wake = val.gpio.gpio; + + bt_host_wake_irq = gpio_to_irq(bt_host_wake); + if (IS_ERR_VALUE(bt_host_wake_irq)) { + pr_warn("map gpio [%d] to virq failed, errno = %d\n", + bt_host_wake, bt_host_wake_irq); + ret = -1; + goto err; + } + ret = devm_request_irq(dev, bt_host_wake_irq, rda_bt_host_wake_eirq_handler, + IRQF_TRIGGER_RISING, "rda_combo_bt", NULL); + if (IS_ERR_VALUE(ret)) { + pr_warn("request virq %d failed, errno = %d\n", + bt_host_wake_irq, ret); + goto err; + } + + enable_irq(bt_host_wake_irq); + + +#endif + bt_host_wake_irq = IRQ_GPIO; + wmt_gpio_mask_irq(bt_host_wake); + wmt_gpio_set_irq_type(bt_host_wake,IRQ_TYPE_LEVEL_LOW); + + /*enable pull down*/ + wmt_gpio_setpull(bt_host_wake,WMT_GPIO_PULL_UP); + + ret = request_irq(bt_host_wake_irq, rda_bt_host_wake_eirq_handler, IRQF_SHARED, "rda_5991", (void*)&aaaa); + if (ret){ + printk("Request IRQ failed!ERRNO:%d.", ret); + goto err; + } + + + + return 0; + err: + return -1; +} + +int bt_unregister_host_wake_irq(void *dev) +{ + if(bt_host_wake_irq > 0) + { + //disable_irq_nosync(bt_host_wake_irq); + //devm_free_irq(dev, bt_host_wake_irq, NULL); + free_irq(IRQ_GPIO, (void*)&aaaa); + bt_host_wake_irq = -1; + } + return 0; + +} + +//tip end + + +static int rda_bt_core_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int result = 0; + rda_bt_core_client = client; + printk("rda_bt_core_probe\n"); + return result; +} + +static int rda_bt_core_remove(struct i2c_client *client) +{ + return 0; +} + +static const struct i2c_device_id bt_core_i2c_id[] = + { {RDA_BT_CORE_I2C_DEVNAME, RDA_I2C_CHANNEL}, {} }; +static struct i2c_driver rda_bt_core_driver = { + //.class = I2C_CLASS_HWMON, + .probe = rda_bt_core_probe, + .remove = rda_bt_core_remove, + .detect = rda_bt_core_detect, + .driver.name = RDA_BT_CORE_I2C_DEVNAME, + .id_table = bt_core_i2c_id, +}; + +#ifdef CONFIG_BT_RANDADDR +extern void bt_get_random_address(char *buf); +#endif + + +static int rda_combo_i2c_ops(unsigned long arg) +{ + int ret = 0, argc = 0; + u8 cmd[256], *argv[5], *pos, rw = 0, addr = 0, pageup = 0; + struct i2c_client * i2Client = NULL; + u16 data = 0; + void __user *argp = (void __user *)arg; + + if(copy_from_user(cmd, argp, 256)) + return -EFAULT; + else{ + pos = cmd; + while (*pos != '\0') { + if (*pos == '\n') { + *pos = '\0'; + break; + } + pos++; + } + argc = 0; + pos = cmd; + for (;;) { + while (*pos == ' ') + pos++; + if (*pos == '\0') + break; + argv[argc] = pos; + argc++; + if (argc == 5) + break; + if (*pos == '"') { + char *pos2 = strrchr(pos, '"'); + if (pos2) + pos = pos2 + 1; + } + while (*pos != '\0' && *pos != ' ') + pos++; + if (*pos == ' ') + *pos++ = '\0'; + } + } + + if(!memcmp(argv[1], "bt", 2)){ + i2Client = rda_bt_rf_client; + } + else + i2Client = rda_wifi_rf_client; + + if (kstrtou8(argv[3], 0, &addr)) + return -EINVAL; + + if(*(argv[2]) == 'r'){ + rw = 0; + } + else{ + rw = 1; + if (kstrtou16(argv[4], 0, &data)) + return -EINVAL; + } + + if(addr >= 0x80){ + i2c_write_1_addr_2_data(i2Client, 0x3F, 0x0001); + addr -= 0x80; + pageup = 1; + } + + if(*(argv[2]) == 'r'){ + int read_data = 0; + i2c_read_1_addr_2_data(i2Client, addr, &data); + read_data = (int)data; + + if(copy_to_user(argp, &read_data, sizeof(int))) + ret = -EFAULT; + } + else + i2c_write_1_addr_2_data(i2Client, addr, data); + + if(pageup == 1) + i2c_write_1_addr_2_data(i2Client, 0x3F, 0x0000); + + printk("wlan: %s %s %s %s :0x%x \n", argv[0], argv[1], argv[2], argv[3], data); + return ret; +} + + +static long rda_combo_pw_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + int ret = 0; + void __user *argp = (void __user *)arg; + + switch (cmd) { + + case RDA_WLAN_COMBO_VERSION: + { + u32 version = rda_wlan_version(); + if (copy_to_user(argp, &version, sizeof(version))) + ret = -EFAULT; + } + break; + + case RDA_WIFI_POWER_SET_TEST_MODE_IOCTL: + wifi_in_test_mode = 1; + printk("****set rda wifi in test mode \n"); + break; + + case RDA_WIFI_POWER_CANCEL_TEST_MODE_IOCTL: + wifi_in_test_mode = 0; + printk("****set rda wifi in normal mode \n"); + break; + + case RDA_BT_GET_ADDRESS_IOCTL: + { + u8 bt_addr[6] = { 0 }; + +#ifdef CONFIG_BT_RANDADDR + bt_get_random_address(bt_addr); +#endif + printk(KERN_INFO + "rdabt address[0x%x]:[0x%x]:[0x%x]:[0x%x]:[0x%x]:[0x%x].\n", + bt_addr[0], bt_addr[1], bt_addr[2], bt_addr[3], + bt_addr[4], bt_addr[5]); + //tmp for bt adr + if (copy_to_user(argp, &bt_addr[0], sizeof(bt_addr))) { + ret = -EFAULT; + } + } + break; + + case RDA_COMBO_I2C_OPS: + { + ret = rda_combo_i2c_ops(arg); + } + break; + + case RDA_WIFI_POWER_ON_IOCTL: + case RDA_BT_POWER_ON_IOCTL: + wlan_read_version_from_chip(); + default: + if (wlan_version == WLAN_VERSION_90_D + || wlan_version == WLAN_VERSION_90_E) { + ret = rda_5990_pw_ioctl(file, cmd, arg); + } else if (wlan_version == WLAN_VERSION_91) + ret = rda_5991_pw_ioctl(file, cmd, arg); + else if (wlan_version == WLAN_VERSION_91_E) + ret = rda_5991e_pw_ioctl(file, cmd, arg); + else if (wlan_version == WLAN_VERSION_91_F) + ret = rda_5991f_pw_ioctl(file, cmd, arg); + break; + } + return ret; +} + +static int rda_combo_major; +static struct class *rda_combo_class = NULL; +static const struct file_operations rda_combo_operations = { + .owner = THIS_MODULE, + .unlocked_ioctl = rda_combo_pw_ioctl, + .release = NULL +}; + +void rda_combo_sleep_worker_task(struct work_struct *work) +{ + printk("---rda_combo_sleep_worker_task end \n"); + wake_unlock(&rda_combo_wake_lock); +} +//add by LA +void rda_bt_interrupt_task(struct work_struct *work) +{ + printk("---rda_bt_interrupt_task \n"); + rda_combo_set_wake_lock(); + printk("---rda_bt_interrupt_task end \n"); + + +} +void rda_combo_set_wake_lock(void) +{ + printk("rda_combo_set_wake_lock\n"); + wake_lock(&rda_combo_wake_lock); + cancel_delayed_work(&rda_combo_sleep_worker); + schedule_delayed_work(&rda_combo_sleep_worker, 6 * HZ); + printk("rda_combo_set_wake_lock end \n"); +} + +static struct platform_driver platform_driver = { + .driver = { + .name = "rda_combo_rfkill_device", + .owner = THIS_MODULE, + } +}; + +static int wlan_rfkill_set(void *data, bool blocked) +{ + printk("wlan_rfkill_set %d \n", blocked); + if (blocked) { + rda_wifi_power_off(); + } else { + rda_wifi_power_on(); + } + return 0; +} + +static int rda_bt_power_off(void) +{ + if (wlan_version == WLAN_VERSION_90_D + || wlan_version == WLAN_VERSION_90_E) { + return rda_5990_bt_power_off(); + } else if (wlan_version == WLAN_VERSION_91) + return rda_5991_bt_power_off(); + else if (wlan_version == WLAN_VERSION_91_E) + return rda_5991e_bt_power_off(); + else if (wlan_version == WLAN_VERSION_91_F) + return rda_5991f_bt_power_off(); + return 0; +} + +static int rda_bt_power_on(void) +{ + wlan_read_version_from_chip(); + if (wlan_version == WLAN_VERSION_90_D + || wlan_version == WLAN_VERSION_90_E) { + return rda_5990_bt_power_on(); + } else if (wlan_version == WLAN_VERSION_91) + return rda_5991_bt_power_on(); + else if (wlan_version == WLAN_VERSION_91_E) + return rda_5991e_bt_power_on(); + else if (wlan_version == WLAN_VERSION_91_F) + return rda_5991f_bt_power_on(); + return 0; +} + +static const struct rfkill_ops wlan_rfkill_ops = { + .set_block = wlan_rfkill_set, +}; + +static int bt_rfkill_set(void *data, bool blocked) +{ + printk("bt_rfkill_set %d \n", blocked); + if (blocked) { + rda_bt_power_off(); + } else { + rda_bt_power_on(); + } + return 0; +} + +static const struct rfkill_ops bt_rfkill_ops = { + .set_block = bt_rfkill_set, +}; + + + + +//configure pwm1 pin +static void config_pwm1_pin(int enable) +{ + int val; + if(enable) { + val = readb(0xd8110200+WMT_MMAP_OFFSET); + val &= ~(1 << 7); + writeb(val, 0xd8110200+WMT_MMAP_OFFSET); + }else{ + val = readb(0xd8110200+WMT_MMAP_OFFSET); + val |= (1 << 7); + writeb(val, 0xd8110200+WMT_MMAP_OFFSET); + } +} + +struct pwm_device * g_pwm =NULL; + +static void enable_pwm1_32KHz(int enable) +{ + if(enable) { + //pwm_config(g_pwm, 15625, 31250);// configuration output 32KHZ + pwm_config(g_pwm, 15258, 30517);// configuration output 32768HZ + pwm_enable(g_pwm); + config_pwm1_pin(0x01); + printk("enable 32khz output\n"); + }else{ + pwm_disable(g_pwm); + config_pwm1_pin(0x00); + printk("disable 32khz output\n"); + } +} + +static struct i2c_client *rda_wifi_core=NULL; +static struct i2c_client *rda_wifi_rf=NULL; +static struct i2c_client *rda_bt_core=NULL; +static struct i2c_client *rda_bt_rf=NULL; + + +#define RDA_WIFI_CORE_ADDR (0x13) +#define RDA_WIFI_RF_ADDR (0x14) +#define RDA_BT_CORE_ADDR (0x15) +#define RDA_BT_RF_ADDR (0x16) +#define RDA_WIFI_RF_I2C_DEVNAME "rda_wifi_rf_i2c" +#define RDA_WIFI_CORE_I2C_DEVNAME "rda_wifi_core_i2c" +#define RDA_BT_RF_I2C_DEVNAME "rda_bt_rf_i2c" +#define RDA_BT_CORE_I2C_DEVNAME "rda_bt_core_i2c" + + + +struct i2c_board_info rda_wifi_core_i2c_board_info = { + .type = RDA_WIFI_CORE_I2C_DEVNAME, + .flags = 0x00, + .addr = RDA_WIFI_CORE_ADDR, + .platform_data = NULL, + .archdata = NULL, + .irq = -1, +}; +struct i2c_board_info rda_wifi_rf_i2c_board_info = { + .type = RDA_WIFI_RF_I2C_DEVNAME, + .flags = 0x00, + .addr = RDA_WIFI_RF_ADDR, + .platform_data = NULL, + .archdata = NULL, + .irq = -1, +}; +struct i2c_board_info rda_bt_core_i2c_board_info = { + .type = RDA_BT_CORE_I2C_DEVNAME, + .flags = 0x00, + .addr = RDA_BT_CORE_ADDR, + .platform_data = NULL, + .archdata = NULL, + .irq = -1, +}; +struct i2c_board_info rda_bt_rf_i2c_board_info = { + .type = RDA_BT_RF_I2C_DEVNAME, + .flags = 0x00, + .addr = RDA_BT_RF_ADDR, + .platform_data = NULL, + .archdata = NULL, + .irq = -1, +}; + + +static int rda_i2c_register_device (struct i2c_board_info *ts_i2c_bi,struct i2c_client **l_client) +{ + struct i2c_adapter *adapter = NULL; + adapter = i2c_get_adapter(4); + + if (NULL == adapter) { + printk("can not get i2c adapter, client address error\n"); + return -1; + } + + *l_client = i2c_new_device(adapter, ts_i2c_bi); + if (*l_client == NULL) { + printk("allocate i2c client failed\n"); + return -1; + } + + i2c_put_adapter(adapter); + + return 0; +} + +static void rda_i2c_unregister_device(struct i2c_client *l_client) +{ + if (l_client != NULL) + { + i2c_unregister_device(l_client); + l_client = NULL; + } +} + + + +int rda_combo_power_ctrl_init(void) +{ + int ret = 0; + int n; + + ret = rda_i2c_register_device(&rda_wifi_core_i2c_board_info,&rda_wifi_core); + if(ret!=0) + return -1; + rda_i2c_register_device(&rda_wifi_rf_i2c_board_info,&rda_wifi_rf); + rda_i2c_register_device(&rda_bt_core_i2c_board_info,&rda_bt_core); + rda_i2c_register_device(&rda_bt_rf_i2c_board_info,&rda_bt_rf); + + + + + + + + + + printk("begint to pwm request\n"); + g_pwm = pwm_request(0x01,"rda5991 bluetooth 32KHz"); + if(!g_pwm){ + printk("can not request pwm1 for bluetooth mtk6622\n"); + return -1; + } + + + if (gpio_request(bt_host_wake, "rda5991_intr") < 0) { + printk("gpio(%d) rda5991_intr gpio request fail\n", bt_host_wake); + return -1; + } + enable_pwm1_32KHz(1); + + + + + + + + + printk("rda_combo_power_ctrl_init begin\n"); + if (i2c_add_driver(&rda_wifi_core_driver)) { + printk("rda_wifi_core_driver failed!\n"); + ret = -ENODEV; + return ret; + } + + if (i2c_add_driver(&rda_wifi_rf_driver)) { + printk("rda_wifi_rf_driver failed!\n"); + ret = -ENODEV; + return ret; + } + + if (i2c_add_driver(&rda_bt_core_driver)) { + printk("rda_bt_core_driver failed!\n"); + ret = -ENODEV; + return ret; + } + + if (i2c_add_driver(&rda_bt_rf_driver)) { + printk("rda_bt_rf_driver failed!\n"); + ret = -ENODEV; + return ret; + } + + rda_combo_major = XENVBD_MAJOR; + + + n= register_chrdev(rda_combo_major, "rdacombo_power_ctrl", &rda_combo_operations); + if (n < 0) { + printk(KERN_INFO "register rdabt_power_ctrl failed!!! \n"); + return rda_combo_major; + }else + printk("rda_combo_major %d\n",rda_combo_major); + + rda_combo_class = class_create(THIS_MODULE, "rda_combo"); + if (IS_ERR(rda_combo_class)) { + unregister_chrdev(rda_combo_major, "rdacombo_power_ctrl"); + return PTR_ERR(rda_combo_class); + } + + device_create(rda_combo_class, NULL, MKDEV(rda_combo_major, 0), NULL, + "rdacombo"); + #ifdef RDA_KERNEL_PLATFORM + combo_reg = regulator_get(NULL, LDO_BT); + if (IS_ERR(combo_reg)) { + printk(KERN_INFO "could not find regulator devices\n"); + ret = PTR_ERR(combo_reg); + goto fail_platform_driver; + } + #endif + { + unsigned char *temp = NULL; + unsigned short testData = 0xffee; + temp = (unsigned char *)&testData; + if (*temp == 0xee) + isBigEnded = 0; + else + isBigEnded = 1; + } + + INIT_DELAYED_WORK(&rda_combo_sleep_worker, rda_combo_sleep_worker_task); + wake_lock_init(&rda_combo_wake_lock, WAKE_LOCK_SUSPEND, + "RDA_sleep_worker_wake_lock"); + //add by RDA + INIT_WORK(&rda_bt_interrupt,rda_bt_interrupt_task); + + mutex_init(&i2c_rw_lock); + + ret = platform_driver_register(&platform_driver); + if (ret) + goto fail_platform_driver; + + platform_device = platform_device_alloc("rda_combo_rfkill_device", -1); + if (!platform_device) { + ret = -ENOMEM; + } else + ret = platform_device_add(platform_device); + + if (ret) + goto fail_platform_device; + + wlan_rfkill = + rfkill_alloc("rda_wlan_rk", &platform_device->dev, RFKILL_TYPE_WLAN, + &wlan_rfkill_ops, NULL); + if (wlan_rfkill) { + rfkill_init_sw_state(wlan_rfkill, true); + ret = rfkill_register(wlan_rfkill); + } + + bt_rfkill = + rfkill_alloc("rda_bt_rk", &platform_device->dev, + RFKILL_TYPE_BLUETOOTH, &bt_rfkill_ops, NULL); + if (bt_rfkill) { + rfkill_init_sw_state(bt_rfkill, true); + ret = rfkill_register(bt_rfkill); + } else + printk("rda_bt_rk failed\n"); +#if 0 +//tip,for different platform, you must check how to realize a interrupt. + type = script_get_item("wifi_para", "rda5990_bt_host_wake", &val); + if (SCIRPT_ITEM_VALUE_TYPE_PIO!=type) + printk("get RDA rda5990_bt_host_wake gpio failed\n"); + else + bt_host_wake = val.gpio.gpio; + + bt_host_wake_irq = gpio_to_irq(bt_host_wake); + if (IS_ERR_VALUE(bt_host_wake_irq)) { + pr_warn("map gpio [%d] to virq failed, errno = %d\n", + bt_host_wake, bt_host_wake_irq); + ret = -1; + goto fail_platform_driver; + } + ret = devm_request_irq(&platform_device->dev, bt_host_wake_irq, rda_bt_host_wake_eirq_handler, + IRQF_TRIGGER_RISING, "rda_combo_bt", NULL); + if (IS_ERR_VALUE(ret)) { + pr_warn("request virq %d failed, errno = %d\n", + bt_host_wake_irq, ret); + goto fail_platform_driver; + } +//tip end +#else + //tip,for different platform, you must check how to realize a interrupt. + if(bt_register_host_wake_irq(&platform_device->dev) == -1) + goto fail_platform_driver; + //tip end + +#endif + #ifdef RDA_KERNEL_PLATFORM + clk32k = clk_get(NULL, RDA_CLK_OUT); + clk26m = clk_get(NULL, RDA_CLK_AUX); + #endif + init_completion(&rda_wifi_bt_comp); + complete(&rda_wifi_bt_comp); + + printk("rda_combo_power_ctrl_init end\n"); + return 0; + +fail_platform_driver: +fail_platform_device: + unregister_chrdev(rda_combo_major, "rdacombo_power_ctrl"); + printk("rda_combo_power_ctrl_init failed\n"); + + #ifdef RDA_KERNEL_PLATFORM + if (!IS_ERR(combo_reg)) { + regulator_put(combo_reg); + } + #endif + return ret; +} + +void rda_combo_power_ctrl_exit(void) +{ + i2c_del_driver(&rda_wifi_core_driver); + i2c_del_driver(&rda_wifi_rf_driver); + i2c_del_driver(&rda_bt_core_driver); + i2c_del_driver(&rda_bt_rf_driver); + + unregister_chrdev(rda_combo_major, "rdacombo_power_ctrl"); + device_destroy(rda_combo_class, MKDEV(rda_combo_major, 0)); + if (rda_combo_class) + class_destroy(rda_combo_class); + + cancel_delayed_work_sync(&rda_combo_sleep_worker); + cancel_work_sync(&rda_bt_interrupt); + wake_lock_destroy(&rda_combo_wake_lock); + disable_32k_rtc(CLOCK_MASK_ALL); + disable_26m_rtc(CLOCK_MASK_ALL); + #ifdef RDA_KERNEL_PLATFORM + clk_put(clk32k); + clk_put(clk26m); + #endif + if (wlan_rfkill) { + rfkill_unregister(wlan_rfkill); + rfkill_destroy(wlan_rfkill); + } + + if (bt_rfkill) { + rfkill_unregister(bt_rfkill); + rfkill_destroy(bt_rfkill); + } + + #if 0 + devm_free_irq(&platform_device->dev, bt_host_wake_irq, NULL); + bt_host_wake_irq = -1; + #else + bt_unregister_host_wake_irq(&platform_device->dev); + #endif + + if (platform_device) { + platform_device_unregister(platform_device); + platform_driver_unregister(&platform_driver); + } + #ifdef RDA_KERNEL_PLATFORM + if (!IS_ERR(combo_reg)) { + regulator_disable(combo_reg); + regulator_put(combo_reg); + } + #endif + + rda_i2c_unregister_device(rda_wifi_core); + rda_i2c_unregister_device(rda_wifi_rf); + rda_i2c_unregister_device(rda_bt_core); + rda_i2c_unregister_device(rda_bt_rf); + + enable_pwm1_32KHz(0); + if(g_pwm) + pwm_free(g_pwm); + gpio_free(bt_host_wake); + + +} + +unsigned char rda_combo_wifi_in_test_mode(void) +{ + return wifi_in_test_mode; +} + +void rda_combo_i2c_lock(void) +{ + mutex_lock(&i2c_rw_lock); +} + +void rda_combo_i2c_unlock(void) +{ + mutex_unlock(&i2c_rw_lock); +} + +int rda_fm_power_on(void) +{ + int ret = 0; + wlan_read_version_from_chip(); + if (wlan_version == WLAN_VERSION_90_D + || wlan_version == WLAN_VERSION_90_E) { + ret = rda_5990_fm_power_on(); + } else if (wlan_version == WLAN_VERSION_91) + ret = rda_5991_fm_power_on(); + else if (wlan_version == WLAN_VERSION_91_E) + ret = rda_5991e_fm_power_on(); + else if (wlan_version == WLAN_VERSION_91_F) + ret = rda_5991f_fm_power_on(); + return ret; +} + +int rda_fm_power_off(void) +{ + int ret = 0; + wlan_read_version_from_chip(); + if (wlan_version == WLAN_VERSION_90_D + || wlan_version == WLAN_VERSION_90_E) { + ret = rda_5990_fm_power_off(); + } else if (wlan_version == WLAN_VERSION_91) + ret = rda_5991_fm_power_off(); + else if (wlan_version == WLAN_VERSION_91_E) + ret = rda_5991e_fm_power_off(); + else if (wlan_version == WLAN_VERSION_91_F) + ret = rda_5991f_fm_power_off(); + return ret; + +} + +EXPORT_SYMBOL(rda_wlan_version); + +EXPORT_SYMBOL(rda_combo_wifi_in_test_mode); + +EXPORT_SYMBOL(rda_combo_set_wake_lock); +EXPORT_SYMBOL(rda_wifi_power_off); +EXPORT_SYMBOL(rda_wifi_power_on); +EXPORT_SYMBOL(rda_fm_power_on); +EXPORT_SYMBOL(rda_fm_power_off); + +module_init(rda_combo_power_ctrl_init); +module_exit(rda_combo_power_ctrl_exit); + +MODULE_LICENSE("GPL"); diff --git a/drivers/net/wireless/rda/rda_fm/Makefile b/drivers/net/wireless/rda/rda_fm/Makefile new file mode 100755 index 00000000..fe6851a5 --- /dev/null +++ b/drivers/net/wireless/rda/rda_fm/Makefile @@ -0,0 +1 @@ +obj-m := fm_drv.o diff --git a/drivers/net/wireless/rda/rda_fm/fm.h b/drivers/net/wireless/rda/rda_fm/fm.h new file mode 100755 index 00000000..c97c85e8 --- /dev/null +++ b/drivers/net/wireless/rda/rda_fm/fm.h @@ -0,0 +1,517 @@ +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + */ +/* MediaTek Inc. (C) 2010. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ + +/* alps/ALPS_SW/TRUNK/MAIN/alps/kernel/arch/arm/mach-mt6516/include/mach/fm.h + * + * (C) Copyright 2009 + * MediaTek + * William Chung + * + * MT6516 AR10x0 FM Radio Driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __FM_H__ +#define __FM_H__ + +//#define FMDEBUG + +#include +#include + +//scan sort algorithm +enum{ + FM_SCAN_SORT_NON = 0, + FM_SCAN_SORT_UP, + FM_SCAN_SORT_DOWN, + FM_SCAN_SORT_MAX +}; + +//***************************************************************************************** +//***********************************FM config for customer *********************************** +//***************************************************************************************** +//RX +#define FMR_RSSI_TH_LONG 0x0301 //FM radio long antenna RSSI threshold(11.375dBuV) +#define FMR_RSSI_TH_SHORT 0x02E0 //FM radio short antenna RSSI threshold(-1dBuV) +#define FMR_CQI_TH 0x00E9 //FM radio Channel quality indicator threshold(0x0000~0x00FF) +#define FMR_SEEK_SPACE 1 //FM radio seek space,1:100KHZ; 2:200KHZ +#define FMR_SCAN_CH_SIZE 40 //FM radio scan max channel size +#define FMR_BAND 1 //FM radio band, 1:87.5MHz~108.0MHz; 2:76.0MHz~90.0MHz; 3:76.0MHz~108.0MHz; 4:special +#define FMR_BAND_FREQ_L 875 //FM radio special band low freq(Default 87.5MHz) +#define FMR_BAND_FREQ_H 1080 //FM radio special band high freq(Default 108.0MHz) +#define FM_SCAN_SORT_SELECT FM_SCAN_SORT_NON + +//TX + +//***************************************************************************************** +//***********************************FM config for engineer *********************************** +//***************************************************************************************** +//RX +#define FMR_MR_TH 0x01BD //FM radio MR threshold +#define ADDR_SCAN_TH 0xE0 //scan thrshold register +#define ADDR_CQI_TH 0xE1 //scan CQI register + +//TX +#define FMTX_SCAN_HOLE_LOW 923 //92.3MHz~95.4MHz should not show to user +#define FMTX_SCAN_HOLE_HIGH 954 //92.3MHz~95.4MHz should not show to user +//***************************************************************************************** + +#define FM_NAME "fm" +#define FM_DEVICE_NAME "/dev/fm" + +// errno +#define FM_SUCCESS 0 +#define FM_FAILED 1 +#define FM_EPARM 2 +#define FM_BADSTATUS 3 +#define FM_TUNE_FAILED 4 +#define FM_SEEK_FAILED 5 +#define FM_BUSY 6 +#define FM_SCAN_FAILED 7 + +// band + +#define FM_BAND_UNKNOWN 0 +#define FM_BAND_UE 1 // US/Europe band 87.5MHz ~ 108MHz (DEFAULT) +#define FM_BAND_JAPAN 2 // Japan band 76MHz ~ 90MHz +#define FM_BAND_JAPANW 3 // Japan wideband 76MHZ ~ 108MHz +#define FM_BAND_SPECIAL 4 // special band between 76MHZ and 108MHz +#define FM_BAND_DEFAULT FM_BAND_UE +#define FM_FREQ_MIN FMR_BAND_FREQ_L +#define FM_FREQ_MAX FMR_BAND_FREQ_H +#define FM_RAIDO_BAND FM_BAND_UE +// space +#define FM_SPACE_UNKNOWN 0 +#define FM_SPACE_100K 1 +#define FM_SPACE_200K 2 +#define FM_SPACE_DEFAULT FMR_SEEK_SPACE +#define FM_SEEK_SPACE FMR_SEEK_SPACE + +//max scan chl num +#define FM_MAX_CHL_SIZE FMR_SCAN_CH_SIZE +// auto HiLo +#define FM_AUTO_HILO_OFF 0 +#define FM_AUTO_HILO_ON 1 + +// seek direction +#define FM_SEEK_UP 0 +#define FM_SEEK_DOWN 1 + +#define FM_CHIP_AR1000 0x1000 +#define FM_CHIP_MT5192 0x91 +#define FM_CHIP_MT5193 0x92 +#define FM_CHIP_MT6616 0x6616 +#define FM_CHIP_MT6626 0x6626 +#define FM_CHIP_MT6628 0x6628 +#define FM_CHIP_MT6620 0x6620 +#define FM_CHIP_UNSUPPORTED 0xffff + +// seek threshold +#define FM_SEEKTH_LEVEL_DEFAULT 4 + +#define FM_IOC_MAGIC 0xf5 // FIXME: any conflict? + +struct fm_tune_parm { + uint8_t err; + uint8_t band; + uint8_t space; + uint8_t hilo; + uint16_t freq; // IN/OUT parameter +}; + +struct fm_seek_parm { + uint8_t err; + uint8_t band; + uint8_t space; + uint8_t hilo; + uint8_t seekdir; + uint8_t seekth; + uint16_t freq; // IN/OUT parameter +}; + +struct fm_scan_parm { + uint8_t err; + uint8_t band; + uint8_t space; + uint8_t hilo; + uint16_t freq; // OUT parameter + uint16_t ScanTBL[16]; //need no less than the chip + uint16_t ScanTBLSize; //IN/OUT parameter +}; + +struct fm_ch_rssi{ + uint16_t freq; + uint16_t rssi; +}; + +struct fm_rssi_req{ + uint16_t num; + uint16_t read_cnt; + struct fm_ch_rssi cr[16*16]; +}; + +#if 1 +#define NEED_DEF_RDS 1 +#else +#define NEED_DEF_RDS 0 +#endif + +#if NEED_DEF_RDS +//For RDS feature +typedef struct +{ + uint8_t TP; + uint8_t TA; + uint8_t Music; + uint8_t Stereo; + uint8_t Artificial_Head; + uint8_t Compressed; + uint8_t Dynamic_PTY; + uint8_t Text_AB; + uint32_t flag_status; +}RDSFlag_Struct; + +typedef struct +{ + uint16_t Month; + uint16_t Day; + uint16_t Year; + uint16_t Hour; + uint16_t Minute; + uint8_t Local_Time_offset_signbit; + uint8_t Local_Time_offset_half_hour; +}CT_Struct; + +typedef struct +{ + int16_t AF_Num; + int16_t AF[2][25]; //100KHz + uint8_t Addr_Cnt; + uint8_t isMethod_A; + uint8_t isAFNum_Get; +}AF_Info; + +typedef struct +{ + uint8_t PS[4][8]; + uint8_t Addr_Cnt; +}PS_Info; + +typedef struct +{ + uint8_t TextData[4][64]; + uint8_t GetLength; + uint8_t isRTDisplay; + uint8_t TextLength; + uint8_t isTypeA; + uint8_t BufCnt; + uint16_t Addr_Cnt; +}RT_Info; + +struct rds_raw_data +{ + int dirty; //indicate if the data changed or not + int len; //the data len form chip + uint8_t data[146]; +}; + +struct rds_group_cnt +{ + unsigned long total; + unsigned long groupA[16]; //RDS groupA counter + unsigned long groupB[16]; //RDS groupB counter +}; + +enum rds_group_cnt_opcode +{ + RDS_GROUP_CNT_READ = 0, + RDS_GROUP_CNT_WRITE, + RDS_GROUP_CNT_RESET, + RDS_GROUP_CNT_MAX +}; + +struct rds_group_cnt_req +{ + int err; + enum rds_group_cnt_opcode op; + struct rds_group_cnt gc; +}; + +typedef struct +{ + CT_Struct CT; + RDSFlag_Struct RDSFlag; + uint16_t PI; + uint8_t Switch_TP; + uint8_t PTY; + AF_Info AF_Data; + AF_Info AFON_Data; + uint8_t Radio_Page_Code; + uint16_t Program_Item_Number_Code; + uint8_t Extend_Country_Code; + uint16_t Language_Code; + PS_Info PS_Data; + uint8_t PS_ON[8]; + RT_Info RT_Data; + uint16_t event_status; //will use RDSFlag_Struct RDSFlag->flag_status to check which event, is that ok? + struct rds_group_cnt gc; +} RDSData_Struct; + + +//Need care the following definition. +//valid Rds Flag for notify +typedef enum { + RDS_FLAG_IS_TP = 0x0001, // Program is a traffic program + RDS_FLAG_IS_TA = 0x0002, // Program currently broadcasts a traffic ann. + RDS_FLAG_IS_MUSIC = 0x0004, // Program currently broadcasts music + RDS_FLAG_IS_STEREO = 0x0008, // Program is transmitted in stereo + RDS_FLAG_IS_ARTIFICIAL_HEAD = 0x0010, // Program is an artificial head recording + RDS_FLAG_IS_COMPRESSED = 0x0020, // Program content is compressed + RDS_FLAG_IS_DYNAMIC_PTY = 0x0040, // Program type can change + RDS_FLAG_TEXT_AB = 0x0080 // If this flag changes state, a new radio text string begins +} RdsFlag; + +typedef enum { + RDS_EVENT_FLAGS = 0x0001, // One of the RDS flags has changed state + RDS_EVENT_PI_CODE = 0x0002, // The program identification code has changed + RDS_EVENT_PTY_CODE = 0x0004, // The program type code has changed + RDS_EVENT_PROGRAMNAME = 0x0008, // The program name has changed + RDS_EVENT_UTCDATETIME = 0x0010, // A new UTC date/time is available + RDS_EVENT_LOCDATETIME = 0x0020, // A new local date/time is available + RDS_EVENT_LAST_RADIOTEXT = 0x0040, // A radio text string was completed + RDS_EVENT_AF = 0x0080, // Current Channel RF signal strength too weak, need do AF switch + RDS_EVENT_AF_LIST = 0x0100, // An alternative frequency list is ready + RDS_EVENT_AFON_LIST = 0x0200, // An alternative frequency list is ready + RDS_EVENT_TAON = 0x0400, // Other Network traffic announcement start + RDS_EVENT_TAON_OFF = 0x0800, // Other Network traffic announcement finished. + RDS_EVENT_RDS = 0x2000, // RDS Interrupt had arrived durint timer period + RDS_EVENT_NO_RDS = 0x4000, // RDS Interrupt not arrived durint timer period + RDS_EVENT_RDS_TIMER = 0x8000 // Timer for RDS Bler Check. ---- BLER block error rate +} RdsEvent; +#endif + +struct fm_rds_tx_parm { + uint8_t err; + uint16_t pi; + uint16_t ps[12]; // 4 ps + uint16_t other_rds[87]; // 0~29 other groups + uint8_t other_rds_cnt; // # of other group +}; + +typedef struct fm_rds_tx_req{ + unsigned char pty; // 0~31 integer + unsigned char rds_rbds; // 0:RDS, 1:RBDS + unsigned char dyn_pty; // 0:static, 1:dynamic + unsigned short pi_code; // 2-byte hex + unsigned char ps_buf[8]; // hex buf of PS + unsigned char ps_len; // length of PS, must be 0 / 8" + unsigned char af; // 0~204, 0:not used, 1~204:(87.5+0.1*af)MHz + unsigned char ah; // Artificial head, 0:no, 1:yes + unsigned char stereo; // 0:mono, 1:stereo + unsigned char compress; // Audio compress, 0:no, 1:yes + unsigned char tp; // traffic program, 0:no, 1:yes + unsigned char ta; // traffic announcement, 0:no, 1:yes + unsigned char speech; // 0:music, 1:speech +}fm_rds_tx_req; + +#define TX_SCAN_MAX 10 +#define TX_SCAN_MIN 1 +struct fm_tx_scan_parm { + uint8_t err; + uint8_t band; //87.6~108MHz + uint8_t space; + uint8_t hilo; + uint16_t freq; // start freq, if less than band min freq, then will use band min freq + uint8_t scandir; + uint16_t ScanTBL[TX_SCAN_MAX]; //need no less than the chip + uint16_t ScanTBLSize; //IN: desired size, OUT: scan result size +}; + +struct fm_gps_rtc_info{ + int err; //error number, 0: success, other: err code + int retryCnt; //GPS mnl can decide retry times + int ageThd; //GPS 3D fix time diff threshold + int driftThd; //GPS RTC drift threshold + struct timeval tvThd; //time value diff threshold + int age; //GPS 3D fix time diff + int drift; //GPS RTC drift + union{ + unsigned long stamp; //time stamp in jiffies + struct timeval tv; //time stamp value in RTC + }; + int flag; //rw flag +}; + +typedef enum +{ + FM_I2S_ON = 0, + FM_I2S_OFF +}fm_i2s_state; + +typedef enum +{ + FM_I2S_MASTER = 0, + FM_I2S_SLAVE +}fm_i2s_mode; + +typedef enum +{ + FM_I2S_32K = 0, + FM_I2S_44K, + FM_I2S_48K +}fm_i2s_sample; + +struct fm_i2s_setting{ + int onoff; + int mode; + int sample; +}; + +typedef enum{ + FM_RX = 0, + FM_TX = 1 +}FM_PWR_T; + +#define FM_IOCTL_POWERUP _IOWR(FM_IOC_MAGIC, 0, struct fm_tune_parm*) +#define FM_IOCTL_POWERDOWN _IOWR(FM_IOC_MAGIC, 1, int32_t*) +#define FM_IOCTL_TUNE _IOWR(FM_IOC_MAGIC, 2, struct fm_tune_parm*) +#define FM_IOCTL_SEEK _IOWR(FM_IOC_MAGIC, 3, struct fm_seek_parm*) +#define FM_IOCTL_SETVOL _IOWR(FM_IOC_MAGIC, 4, uint32_t*) +#define FM_IOCTL_GETVOL _IOWR(FM_IOC_MAGIC, 5, uint32_t*) +#define FM_IOCTL_MUTE _IOWR(FM_IOC_MAGIC, 6, uint32_t*) +#define FM_IOCTL_GETRSSI _IOWR(FM_IOC_MAGIC, 7, int32_t*) +#define FM_IOCTL_SCAN _IOWR(FM_IOC_MAGIC, 8, struct fm_scan_parm*) +#define FM_IOCTL_STOP_SCAN _IO(FM_IOC_MAGIC, 9) +#define FM_IOCTL_POWERUP_TX _IOWR(FM_IOC_MAGIC, 20, struct fm_tune_parm*) +#define FM_IOCTL_TUNE_TX _IOWR(FM_IOC_MAGIC, 21, struct fm_tune_parm*) +#define FM_IOCTL_RDS_TX _IOWR(FM_IOC_MAGIC, 22, struct fm_rds_tx_parm*) + +//IOCTL and struct for test +#define FM_IOCTL_GETCHIPID _IOWR(FM_IOC_MAGIC, 10, uint16_t*) +#define FM_IOCTL_EM_TEST _IOWR(FM_IOC_MAGIC, 11, struct fm_em_parm*) +#define FM_IOCTL_RW_REG _IOWR(FM_IOC_MAGIC, 12, struct fm_ctl_parm*) +#define FM_IOCTL_GETMONOSTERO _IOWR(FM_IOC_MAGIC, 13, uint16_t*) +#define FM_IOCTL_GETCURPAMD _IOWR(FM_IOC_MAGIC, 14, uint16_t*) +#define FM_IOCTL_GETGOODBCNT _IOWR(FM_IOC_MAGIC, 15, uint16_t*) +#define FM_IOCTL_GETBADBNT _IOWR(FM_IOC_MAGIC, 16, uint16_t*) +#define FM_IOCTL_GETBLERRATIO _IOWR(FM_IOC_MAGIC, 17, uint16_t*) + + +//IOCTL for RDS +#define FM_IOCTL_RDS_ONOFF _IOWR(FM_IOC_MAGIC, 18, uint16_t*) +#define FM_IOCTL_RDS_SUPPORT _IOWR(FM_IOC_MAGIC, 19, int32_t*) + +#define FM_IOCTL_RDS_SIM_DATA _IOWR(FM_IOC_MAGIC, 23, uint32_t*) +#define FM_IOCTL_IS_FM_POWERED_UP _IOWR(FM_IOC_MAGIC, 24, uint32_t*) + +//IOCTL for FM Tx +#define FM_IOCTL_TX_SUPPORT _IOWR(FM_IOC_MAGIC, 25, int32_t*) +#define FM_IOCTL_RDSTX_SUPPORT _IOWR(FM_IOC_MAGIC, 26, int32_t*) +#define FM_IOCTL_RDSTX_ENABLE _IOWR(FM_IOC_MAGIC, 27, int32_t*) +#define FM_IOCTL_TX_SCAN _IOWR(FM_IOC_MAGIC, 28, struct fm_tx_scan_parm*) + +//IOCTL for FM over BT +#define FM_IOCTL_OVER_BT_ENABLE _IOWR(FM_IOC_MAGIC, 29, int32_t*) + +//IOCTL for FM ANTENNA SWITCH +#define FM_IOCTL_ANA_SWITCH _IOWR(FM_IOC_MAGIC, 30, int32_t*) +#define FM_IOCTL_GETCAPARRAY _IOWR(FM_IOC_MAGIC, 31, int32_t*) + +//IOCTL for FM compensation by GPS RTC +#define FM_IOCTL_GPS_RTC_DRIFT _IOWR(FM_IOC_MAGIC, 32, struct fm_gps_rtc_info*) + +//IOCTL for FM I2S Setting +#define FM_IOCTL_I2S_SETTING _IOWR(FM_IOC_MAGIC, 33, struct fm_i2s_setting*) + +#define FM_IOCTL_RDS_GROUPCNT _IOWR(FM_IOC_MAGIC, 34, struct rds_group_cnt_req*) +#define FM_IOCTL_RDS_GET_LOG _IOWR(FM_IOC_MAGIC, 35, struct rds_raw_data*) + +#define FM_IOCTL_SCAN_GETRSSI _IOWR(FM_IOC_MAGIC, 36, struct fm_rssi_req*) +#define FM_IOCTL_SETMONOSTERO _IOWR(FM_IOC_MAGIC, 37, int32_t) + +#define FM_IOCTL_RDS_BC_RST _IOWR(FM_IOC_MAGIC, 38, int32_t*) + +#define FM_IOCTL_DUMP_REG _IO(FM_IOC_MAGIC, 0xFF) + +enum group_idx { + mono=0, + stereo, + RSSI_threshold, + HCC_Enable, + PAMD_threshold, + Softmute_Enable, + De_emphasis, + HL_Side, + Demod_BW, + Dynamic_Limiter, + Softmute_Rate, + AFC_Enable, + Softmute_Level, + Analog_Volume, + GROUP_TOTAL_NUMS +}; + +enum item_idx { + Sblend_OFF=0, + Sblend_ON, + ITEM_TOTAL_NUMS +}; + +struct fm_ctl_parm { + uint8_t err; + uint8_t addr; + uint16_t val; + uint16_t rw_flag;//0:write, 1:read +}; + +struct fm_em_parm { + uint16_t group_idx; + uint16_t item_idx; + uint32_t item_value; +}; +#endif // __FM_H__ diff --git a/drivers/net/wireless/rda/rda_fm/fm_drv.c b/drivers/net/wireless/rda/rda_fm/fm_drv.c new file mode 100755 index 00000000..cc44d8f3 --- /dev/null +++ b/drivers/net/wireless/rda/rda_fm/fm_drv.c @@ -0,0 +1,2257 @@ +#include +#include +#include +#include // udelay() +#include // device_create() +#include +#include +#include +#include +#include /* constant of kernel version */ +#include // get_user() +#include + +//#include +#include "fm.h" +//#include +//#include +#include +#include +#include +#define FMDEBUG 1 +#define MTK_MT6515 1 +#define RDA599X_FM_SUPPORT 1 +#define FM_ALERT(f, s...) \ + do { \ + printk(KERN_ALERT "RDAFM " f, ## s); \ + } while(0) + +#ifdef FMDEBUG +#define FM_DEBUG(f, s...) \ + do { \ + printk("RDAFM " f, ## s); \ + } while(0) +#else +#define FM_DEBUG(f, s...) +#endif +#define RDA599X_SCANTBL_SIZE 16 //16*uinit16_t +#define RDA599X_FM_SCAN_UP 0x0 +#define RDA599X_FM_SCAN_DOWN 0x01 + + +typedef signed char int8; +typedef unsigned char uint8; +typedef signed short int16; +typedef unsigned short uint16; +typedef signed int int32; +typedef unsigned int uint32; + +extern int rda_fm_power_off(); +extern int rda_fm_power_on(); + +/****************************************************************************** + * CONSTANT DEFINITIONS + *****************************************************************************/ +#define RDAFM_SLAVE_ADDR (0x11) //RDA FM Chip address + +#define RDAFM_MASK_RSSI 0X7F // RSSI +#define RDAFM_DEV "RDA_FM" + +//customer need customize the I2C port +#define RDAFM_I2C_PORT 0 + + +#define ID_RDA5802E 0x5804 +#define ID_RDA5802H 0x5801 +#define ID_RDA5802N 0x5808 +#define ID_RDA5820 0x5805 +#define ID_RDA5820NS 0x5820 + + +static struct proc_dir_entry *g_fm_proc = NULL; +static struct fm *g_fm_struct = NULL; +static atomic_t scan_complete_flag; + +#define FM_PROC_FILE "fm" + +/****************************************************************************** + * STRUCTURE DEFINITIONS + *****************************************************************************/ + +enum RDAFM_CHIP_TYPE { + CHIP_TYPE_RDA5802E = 0, + CHIP_TYPE_RDA5802H, + CHIP_TYPE_RDA5802N, + CHIP_TYPE_RDA5820, + CHIP_TYPE_RDA5820NS, +}; + + + +typedef struct +{ + uint8_t address; + uint16_t value; +}RDA_FM_REG_T; + +typedef struct +{ + bool byPowerUp; + struct fm_tune_parm parm +}FM_TUNE_T; +static FM_TUNE_T fm_tune_data = {false, {}}; + +typedef enum +{ + FM_RECEIVER, //5800,5802,5804 + FM_TRANSMITTER, //5820 +}RDA_RADIO_WORK_E; + +typedef enum +{ + OFF, + ON, +}RDA_FM_POWER_STATE_T; + +struct fm { + uint32_t ref; + bool powerup; + uint16_t chip_id; + uint16_t device_id; + dev_t dev_t; + uint16_t min_freq; // KHz + uint16_t max_freq; // KHz + uint8_t band; // TODO + struct class *cls; + struct device *dev; + struct cdev cdev; + struct i2c_client *i2c_client; +}; + + +/****************************************************************************** + * FUNCTION PROTOTYPES + *****************************************************************************/ +//extern void fm_low_power_wa(int fmon); + +static int RDAFM_clear_hmute(struct i2c_client *client); +static int RDAFM_enable_hmute(struct i2c_client *client); +static int RDAFM_clear_tune(struct i2c_client *client); +static int RDAFM_enable_tune(struct i2c_client *client); +static int RDAFM_clear_seek(struct i2c_client *client); +static int RDAFM_enable_seek(struct i2c_client *client); +static int RDAFM_SetStereo(struct i2c_client *client,uint8_t b); +static int RDAFM_SetRSSI_Threshold(struct i2c_client *client,uint8_t RssiThreshold); +static int RDAFM_SetDe_Emphasis(struct i2c_client *client,uint8_t index); +static bool RDAFM_Scan(struct i2c_client *client, + uint16_t min_freq, uint16_t max_freq, + uint16_t *pFreq, //get the valid freq after scan + uint16_t *pScanTBL, + uint16_t *ScanTBLsize, + uint16_t scandir, + uint16_t space); + + +static int RDAFM_read(struct i2c_client *client, uint8_t addr, uint16_t *val); +static int RDAFM_write(struct i2c_client *client, uint8_t addr, uint16_t val); +static void RDAFM_em_test(struct i2c_client *client, uint16_t group_idx, uint16_t item_idx, uint32_t item_value); +static int fm_setup_cdev(struct fm *fm); +static int fm_ops_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); +static loff_t fm_ops_lseek(struct file *filp, loff_t off, int whence); +static int fm_ops_open(struct inode *inode, struct file *filp); +static int fm_ops_release(struct inode *inode, struct file *filp); + +static int fm_init(struct i2c_client *client); +static int fm_destroy(struct fm *fm); +static int fm_powerup(struct fm *fm, struct fm_tune_parm *parm); +static int fm_powerdown(struct fm *fm); + +static int fm_tune(struct fm *fm, struct fm_tune_parm *parm); +static int fm_seek(struct fm *fm, struct fm_seek_parm *parm); +static int fm_scan(struct fm *fm, struct fm_scan_parm *parm); +static int fm_setvol(struct fm *fm, uint32_t vol); +static int fm_getvol(struct fm *fm, uint32_t *vol); +static int fm_getrssi(struct fm *fm, uint32_t *rssi); +static int fm_proc_read(char *page, char **start, off_t off, int count, int *eof, void *data); + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31)) +static int fm_i2c_attach_adapter(struct i2c_adapter *adapter); +static int fm_i2c_detect(struct i2c_adapter *adapter, int addr, int kind); +static int fm_i2c_detach_client(struct i2c_client *client); +#else +static int fm_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id); +static int fm_i2c_detect(struct i2c_client *client, struct i2c_board_info *info); +static int fm_i2c_remove(struct i2c_client *client); +#endif + +/****************************************************************************** + * GLOBAL DATA + *****************************************************************************/ +/* Addresses to scan */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31)) +static unsigned short normal_i2c[] = {RDAFM_SLAVE_ADDR, I2C_CLIENT_END}; +static unsigned short ignore = I2C_CLIENT_END; + +static struct i2c_client_address_data RDAFM_addr_data = { + .normal_i2c = normal_i2c, + .probe = &ignore, + .ignore = &ignore, +}; +#else +static const struct i2c_device_id fm_i2c_id = {RDAFM_DEV, 0}; +static unsigned short force[] = {RDAFM_I2C_PORT, RDAFM_SLAVE_ADDR, I2C_CLIENT_END, I2C_CLIENT_END}; +static const unsigned short * const forces[] = {force, NULL}; +//static struct i2c_client_address_data addr_data = {.forces = forces}; +static unsigned short addr_data[] = {/*RDAFM_I2C_PORT,*/ RDAFM_SLAVE_ADDR, I2C_CLIENT_END, I2C_CLIENT_END}; + +#endif + +static struct i2c_driver RDAFM_driver = { +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31)) + .driver = { + .owner = THIS_MODULE, + .name = RDAFM_DEV, + }, + .attach_adapter = fm_i2c_attach_adapter, + .detach_client = fm_i2c_detach_client, +#else + .class = I2C_CLASS_HWMON, + .probe = fm_i2c_probe, + .remove = fm_i2c_remove, + .detect = fm_i2c_detect, + .driver.name = RDAFM_DEV, + .driver.owner = THIS_MODULE, + .id_table = &fm_i2c_id, + //.address_data = &addr_data, + .address_list = (const unsigned short*) addr_data, +#endif +}; + +static uint16_t RDAFM_CHIP_ID = 0x5808; +static RDA_RADIO_WORK_E RDA_RADIO_WorkType = FM_RECEIVER; + + + +#if 1 +static uint16_t RDA5802N_initialization_reg[]={ + 0xC005, //02h + 0x0000, + 0x0400, + 0xC6ED, //0x86AD, //05h + 0x6000, + 0x721A, + 0x0000, + 0x0000, + 0x0000, //0x0ah + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, //0x10h + 0x0019, + 0x2A11, + 0xB042, + 0x2A11, + 0xB831, //0x15h + 0xC000, + 0x2A91, + 0x9400, + 0x00A8, + 0xc400, //0x1ah + 0xF7CF, //提高远端噪声抑制 + 0x2414, //0x2ADC, //0x1ch 提升VIO VDD之间压差引起的不良 + 0x806F, + 0x4608, + 0x0086, + 0x0661, //0x20H + 0x0000, + 0x109E, + 0x23C8, + 0x0406, + 0x0E1C, //0x25H +}; +#else +static uint16_t RDA5802N_initialization_reg[]={ + 0xc401, //02h + 0x0000, + 0x0400, + 0x86ad, //05h// + 0x0000, + 0x42c6, + 0x0000, + 0x0000, + 0x0000, //0x0ah + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, //0x10h + 0x0019, + 0x2a11, + 0xa053,//0x80,0x53, + 0x3e11,//0x22,0x11, + 0xfc7d, //0x15h + 0xc000, + 0x2a91, + 0x9400, + 0x00a8, + 0xc400, //0x1ah + 0xe000, + 0x2b1d, //0x23,0x14 + 0x816a, + 0x4608, + 0x0086, + 0x0661, //0x20h + 0x0000, + 0x109e, + 0x2244, + 0x0408, //0x24 + 0x0408, //0x25 +}; +#endif + +static RDA_FM_REG_T RDA5820NS_TX_initialization_reg[]={ + {0x02, 0xE003}, + {0xFF, 100}, // if address is 0xFF, sleep value ms + {0x02, 0xE001}, + {0x19, 0x88A8}, + {0x1A, 0x4290}, + {0x68, 0x0AF0}, + {0x40, 0x0001}, + {0x41, 0x41FF}, + {0xFF, 500}, + {0x03, 0x1B90}, +}; + +static RDA_FM_REG_T RDA5820NS_RX_initialization_reg[]={ + {0x02, 0x0002}, //Soft reset + {0xFF, 100}, // wait + {0x02, 0xC001}, //Power Up + {0x05, 0x888F}, //LNAP 0x884F --LNAN + {0x06, 0x6000}, + {0x13, 0x80E1}, + {0x14, 0x2A11}, + {0x1C, 0x22DE}, + {0x21, 0x0020}, + {0x03, 0x1B90}, +}; + + + +static struct file_operations fm_ops = { + .owner = THIS_MODULE, + .unlocked_ioctl = fm_ops_ioctl, + .llseek = fm_ops_lseek, + .open = fm_ops_open, + .release = fm_ops_release, +}; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) +static DECLARE_MUTEX(fm_ops_mutex); +#else +DEFINE_SEMAPHORE(fm_ops_mutex); +#endif + +/****************************************************************************** + *****************************************************************************/ + +/****************************************************************************** + *****************************************************************************/ + + + +static int RDAFM_GetChipID(struct i2c_client *client, uint16_t *pChipID) +{ + int err; + int ret = -1; + uint16_t val = 0x0002; + + //Reset RDA FM + err = RDAFM_write(client, 0x02, val); + if(err < 0){ +#ifdef FMDEBUG + FM_DEBUG("RDAFM_GetChipID: reset FM chip failed!\n"); +#endif + ret = -1; + return ret; + } + msleep(80); + + val = 0; + err = RDAFM_read(client, 0x0C, &val); + if (err == 0) + { + if ((0x5802 == val) || (0x5803 == val)) + { + err = RDAFM_read(client, 0x0E, &val); + + if (err == 0) + *pChipID = val; + else + *pChipID = 0x5802; + +#ifdef FMDEBUG + FM_DEBUG("RDAFM_GetChipID: Chip ID = %04X\n", val); +#endif + + ret = 0; + + } + else if ((0x5805 == val) || (0x5820 == val)) + { + *pChipID = val; + ret = 0; + } + else + { +#ifdef FMDEBUG + FM_DEBUG("RDAFM_GetChipID: get chip ID failed! get value = %04X\n", val); +#endif + ret = -1; + } + + } + else + { +#ifdef FMDEBUG + FM_DEBUG("RDAFM_GetChipID: get chip ID failed!\n"); +#endif + ret = -1; + } + + return ret; +} + + +/* + * RDAFM_read + */ +static int RDAFM_read(struct i2c_client *client, uint8_t addr, uint16_t *val) +{ + int n; + char b[2] = {0}; + + // first, send addr to RDAFM + n = i2c_master_send(client, (char*)&addr, 1); + if (n < 0) + { + FM_ALERT("RDAFM_read send:0x%X err:%d\n", addr, n); + return -1; + } + + // second, receive two byte from RDAFM + n = i2c_master_recv(client, b, 2); + if (n < 0) + { + FM_ALERT("RDAFM_read recv:0x%X err:%d\n", addr, n); + return -1; + } + + *val = (uint16_t)(b[0] << 8 | b[1]); + + return 0; +} + +/* + * RDAFM_write + */ +static int RDAFM_write(struct i2c_client *client, uint8_t addr, uint16_t val) +{ + int n; + char b[3]; + + b[0] = addr; + b[1] = (char)(val >> 8); + b[2] = (char)(val & 0xFF); + + n = i2c_master_send(client, b, 3); + if (n < 0) + { + FM_ALERT("RDAFM_write send:0x%X err:%d\n", addr, n); + return -1; + } + + return 0; +} + + +static int RDAFM_clear_hmute(struct i2c_client *client) +{ + int ret = 0; + uint16_t tRegValue = 0; + + FM_DEBUG("RDAFM_clear_hmute\n"); + + ret = RDAFM_read(client, 0x02, &tRegValue); + if (ret < 0) + { + FM_ALERT("RDAFM_clear_hmute read register failed!\n"); + return -1; + } + + tRegValue |= (1 << 14); + + ret = RDAFM_write(client, 0x02, tRegValue); + + if (ret < 0) + { + FM_ALERT("RDAFM_clear_hmute write register failed!\n"); + return -1; + } + + if(fm_tune_data.byPowerUp){ + if (fm_tune(g_fm_struct, &(fm_tune_data.parm)) < 0) + { + fm_tune_data.byPowerUp = false; + memset(&fm_tune_data.parm, 0, sizeof(fm_tune_data.parm)); + return -EPERM; + } + fm_tune_data.byPowerUp = false; + memset(&fm_tune_data.parm, 0, sizeof(fm_tune_data.parm)); + } + + return 0; +} + + + +static int RDAFM_enable_hmute(struct i2c_client *client) +{ + int ret = 0; + uint16_t tRegValue = 0; + + FM_DEBUG("RDAFM_enable_hmute\n"); + + ret = RDAFM_read(client, 0x02, &tRegValue); + if (ret < 0) + { + FM_ALERT("RDAFM_enable_hmute read register failed!\n"); + return -1; + } + + tRegValue &= (~(1 << 14)); + + ret = RDAFM_write(client, 0x02, tRegValue); + + if (ret < 0) + { + FM_ALERT("RDAFM_enable_hmute write register failed!\n"); + return -1; + } + + return 0; +} + + + +static int RDAFM_clear_tune(struct i2c_client *client) +{ + //Don't need it + return 0; +} + + + +static int RDAFM_enable_tune(struct i2c_client *client) +{ + //Don't need it + return 0; +} + + + +static int RDAFM_clear_seek(struct i2c_client *client) +{ + //Don't need it + return 0; +} + + + +static int RDAFM_enable_seek(struct i2c_client *client) +{ + //Don't need it + return 0; +} + + +//b=true set stereo else set mono +static int RDAFM_SetStereo(struct i2c_client *client, uint8_t b) +{ + int ret = 0; + uint16_t tRegValue = 0; + + FM_DEBUG("RDAFM_SetStereo\n"); + + ret = RDAFM_read(client, 0x02, &tRegValue); + if (ret < 0) + { + FM_ALERT("RDAFM_SetStereo read register failed!\n"); + return -1; + } + if (b) + tRegValue &= (~(1 << 13));//set stereo + else + tRegValue |= (1 << 13); //set mono + + ret = RDAFM_write(client, 0x02, tRegValue); + + if (ret < 0) + { + FM_ALERT("RDAFM_SetStereo write register failed!\n"); + return -1; + } + + + return 0; + +} + + + +static int RDAFM_SetRSSI_Threshold(struct i2c_client *client, uint8_t RssiThreshold) +{ + int ret = 0; + uint16_t tRegValue = 0; + + FM_DEBUG("RDAFM_SetRSSI_Threshold\n"); + + ret = RDAFM_read(client, 0x05, &tRegValue); + if (ret < 0) + { + FM_ALERT("RDAFM_SetRSSI_Threshold read register failed!\n"); + return -1; + } + + tRegValue &= 0x80FF;//clear valume + tRegValue |= ((RssiThreshold & 0x7f) << 8); //set valume + + ret = RDAFM_write(client, 0x05, tRegValue); + + if (ret < 0) + { + FM_ALERT("RDAFM_SetRSSI_Threshold write register failed!\n"); + return -1; + } + + + return 0; + +} + + + +static int RDAFM_SetDe_Emphasis(struct i2c_client *client, uint8_t index) +{ + int ret = 0; + uint16_t tRegValue = 0; + + FM_DEBUG("RDAFM_SetRSSI_Threshold\n"); + + ret = RDAFM_read(client, 0x04, &tRegValue); + if (ret < 0) + { + FM_ALERT("RDAFM_SetRSSI_Threshold read register failed!\n"); + return -1; + } + + if (0 == index) + { + tRegValue &= (~(1 << 11));//De_Emphasis=75us + } + else if (1 == index) + { + tRegValue |= (1 << 11);//De_Emphasis=50us + } + + + ret = RDAFM_write(client, 0x04, tRegValue); + + if (ret < 0) + { + FM_ALERT("RDAFM_SetRSSI_Threshold write register failed!\n"); + return -1; + } + + + return 0; + + +} + +static void RDAFM_em_test(struct i2c_client *client, uint16_t group_idx, uint16_t item_idx, uint32_t item_value) +{ + FM_ALERT("RDAFM_em_test %d:%d:%d\n", group_idx, item_idx, item_value); + switch (group_idx) + { + case mono: + if(item_value == 1) + { + RDAFM_SetStereo(client, 0); //force mono + } + else + { + RDAFM_SetStereo(client, 1); //stereo + + } + + break; + case stereo: + if(item_value == 0) + { + RDAFM_SetStereo(client, 1); //stereo + } + else + { + RDAFM_SetStereo(client, 0); //force mono + } + break; + case RSSI_threshold: + item_value &= 0x7F; + RDAFM_SetRSSI_Threshold(client, item_value); + break; + case Softmute_Enable: + if (item_idx) + { + RDAFM_enable_hmute(client); + } + else + { + RDAFM_clear_hmute(client); + } + break; + case De_emphasis: + if(item_idx >= 2) //0us + { + FM_ALERT("RDAFM not support De_emphasis 0\n"); + } + else + { + RDAFM_SetDe_Emphasis(client,item_idx);//0=75us,1=50us + } + break; + + case HL_Side: + + break; + default: + FM_ALERT("RDAFM not support this setting\n"); + break; + } +} + +static bool RDAFM_Scan(struct i2c_client *client, + uint16_t min_freq, uint16_t max_freq, + uint16_t *pFreq, + uint16_t *pScanTBL, + uint16_t *ScanTBLsize, + uint16_t scandir, + uint16_t space) +{ + uint16_t tFreq, tRegValue = 0; + uint16_t tmp_scanTBLsize = *ScanTBLsize; + int ret = -1; + bool isTrueStation = false; + uint16_t oldValue = 0; + int channel = 0; + if((!pScanTBL) || (tmp_scanTBLsize == 0)) { + return false; + } + + //clear the old value of pScanTBL + memset(pScanTBL, 0, sizeof(uint16_t)*RDA599X_SCANTBL_SIZE); + + if(tmp_scanTBLsize > RDA599X_SCANTBL_SIZE) + { + tmp_scanTBLsize = RDA599X_SCANTBL_SIZE; + } + + //scan up + if(scandir == RDA599X_FM_SCAN_UP){ // now, only support scan up + tFreq = min_freq; + }else{ //scan down + tFreq = max_freq;//max_freq compare need or not + } + + //mute FM + RDAFM_enable_hmute(client); +#if 0 + //set seekth + tRegValue = 0; + RDAFM_read(client, 0x05, &tRegValue); + tRegValue &= (~(0x7f<<8)); + tRegValue |= ((0x8 & 0x7f) << 8); + RDAFM_write(client, 0x05, tRegValue); + msleep(50); +#endif + atomic_set(&scan_complete_flag, 1); + do { + if(atomic_read(&scan_complete_flag) == 0) + break; + isTrueStation = false; + + //set channel and enable TUNE + tRegValue = 0; + RDAFM_read(client, 0x03, &tRegValue); + tRegValue &= (~(0x03ff<<6)); //clear bit[15:6] + channel = tFreq - min_freq; + tRegValue |= ((channel << 6) | (1 << 4)); //set bit[15:6] and bit[4] + ret = RDAFM_write(client, 0x03, tRegValue); + msleep(40); + + //read 0x0B and check FM_TRUE(bit[8]) + tRegValue = 0; + ret = RDAFM_read(client, 0x0B, &tRegValue); + if(!ret){ + if((tRegValue & 0x0100) == 0x0100){ + isTrueStation = true; + } + } + + //if this freq is a true station, read the channel + if(isTrueStation){ + //tRegValue = 0; + //RDAFM_read(client, 0x03, &tRegValue); + //channel = ((tRegValue>>6) & 0x03ff) - 5; + channel = channel - 5; + if((channel >= 0) && (channel != 85)){ + oldValue = *(pScanTBL+(channel/16)); + oldValue |= (1<<(channel%16)); + *(pScanTBL+(channel/16)) = oldValue; + } + } + + //increase freq + tFreq += space; + }while( tFreq <= max_freq ); + +#if defined(MTK_MT6515) && defined(MT6626) + *(pScanTBL+13) = 0xb2d4; + *(pScanTBL+14) = 0xb2d4; + *(pScanTBL+15) = 0xb2d4; +#endif + + *ScanTBLsize = tmp_scanTBLsize; + *pFreq = 0; + + //clear FM mute + RDAFM_clear_hmute(client); + + return true; +} + + +static int fm_setup_cdev(struct fm *fm) +{ + int err; + + err = alloc_chrdev_region(&fm->dev_t, 0, 1, FM_NAME); + if (err) { + FM_ALERT("alloc dev_t failed\n"); + return -1; + } + + FM_ALERT("alloc %s:%d:%d\n", FM_NAME, + MAJOR(fm->dev_t), MINOR(fm->dev_t)); + + cdev_init(&fm->cdev, &fm_ops); + + fm->cdev.owner = THIS_MODULE; + fm->cdev.ops = &fm_ops; + + err = cdev_add(&fm->cdev, fm->dev_t, 1); + if (err) { + FM_ALERT("alloc dev_t failed\n"); + return -1; + } + + fm->cls = class_create(THIS_MODULE, FM_NAME); + if (IS_ERR(fm->cls)) { + err = PTR_ERR(fm->cls); + FM_ALERT("class_create err:%d\n", err); + return err; + } + fm->dev = device_create(fm->cls, NULL, fm->dev_t, NULL, FM_NAME); + + return 0; +} + + + +static int fm_ops_ioctl(struct file *filp, + unsigned int cmd, unsigned long arg) +{ + int ret = 0; + struct fm *fm = container_of(filp->f_dentry->d_inode->i_cdev, struct fm, cdev); + + FM_DEBUG("%s cmd(%x)\n", __func__, cmd); + + switch(cmd) + { + case FM_IOCTL_POWERUP: + { + struct fm_tune_parm parm; + FM_DEBUG("FM_IOCTL_POWERUP\n"); + + // FIXME!! + // if (!capable(CAP_SYS_ADMIN)) + // return -EPERM; + + if (copy_from_user(&parm, (void*)arg, sizeof(struct fm_tune_parm))) + return -EFAULT; + + if (down_interruptible(&fm_ops_mutex)) + return -EFAULT; + ret = fm_powerup(fm, &parm); + up(&fm_ops_mutex); + if (copy_to_user((void*)arg, &parm, sizeof(struct fm_tune_parm))) + return -EFAULT; + // fm_low_power_wa(1); + break; + } + + case FM_IOCTL_POWERDOWN: + { + FM_DEBUG("FM_IOCTL_POWERDOWN\n"); + // FIXME!! + // if (!capable(CAP_SYS_ADMIN)) + // return -EPERM; + if (down_interruptible(&fm_ops_mutex)) + return -EFAULT; + ret = fm_powerdown(fm); + up(&fm_ops_mutex); +// fm_low_power_wa(0); + break; + } + + // tune (frequency, auto Hi/Lo ON/OFF ) + case FM_IOCTL_TUNE: + { + struct fm_tune_parm parm; + FM_DEBUG("FM_IOCTL_TUNE\n"); +// FIXME! +// if (!capable(CAP_SYS_ADMIN)) +// return -EPERM; + + if (copy_from_user(&parm, (void*)arg, sizeof(struct fm_tune_parm))) + return -EFAULT; + + if (down_interruptible(&fm_ops_mutex)) + return -EFAULT; + ret = fm_tune(fm, &parm); + up(&fm_ops_mutex); + + if (copy_to_user((void*)arg, &parm, sizeof(struct fm_tune_parm))) + return -EFAULT; + + break; + } + + case FM_IOCTL_SEEK: + { + struct fm_seek_parm parm; + FM_DEBUG("FM_IOCTL_SEEK\n"); + +// FIXME!! +// if (!capable(CAP_SYS_ADMIN)) +// return -EPERM; + + if (copy_from_user(&parm, (void*)arg, sizeof(struct fm_seek_parm))) + return -EFAULT; + + if (down_interruptible(&fm_ops_mutex)) + return -EFAULT; + ret = fm_seek(fm, &parm); + up(&fm_ops_mutex); + + if (copy_to_user((void*)arg, &parm, sizeof(struct fm_seek_parm))) + return -EFAULT; + + break; + } + + case FM_IOCTL_SETVOL: + { + uint32_t vol; + FM_DEBUG("FM_IOCTL_SETVOL\n"); + +// FIXME!! +// if (!capable(CAP_SYS_ADMIN)) +// return -EPERM; + + if(copy_from_user(&vol, (void*)arg, sizeof(uint32_t))) { + FM_ALERT("copy_from_user failed\n"); + return -EFAULT; + } + + if (down_interruptible(&fm_ops_mutex)) + return -EFAULT; + ret = fm_setvol(fm, vol); + up(&fm_ops_mutex); + + break; + } + + case FM_IOCTL_GETVOL: + { + uint32_t vol; + FM_DEBUG("FM_IOCTL_GETVOL\n"); + +// FIXME!! +// if (!capable(CAP_SYS_ADMIN)) +// return -EPERM; + + if (down_interruptible(&fm_ops_mutex)) + return -EFAULT; + ret = fm_getvol(fm, &vol); + up(&fm_ops_mutex); + + if (copy_to_user((void*)arg, &vol, sizeof(uint32_t))) + return -EFAULT; + + break; + } + + case FM_IOCTL_MUTE: + { + uint32_t bmute; + FM_DEBUG("FM_IOCTL_MUTE\n"); + + // FIXME!! + // if (!capable(CAP_SYS_ADMIN)) + // return -EPERM; + if (copy_from_user(&bmute, (void*)arg, sizeof(uint32_t))) + { + FM_DEBUG("copy_from_user mute failed!\n"); + return -EFAULT; + } + + FM_DEBUG("FM_IOCTL_MUTE:%d\n", bmute); + if (down_interruptible(&fm_ops_mutex)) + return -EFAULT; + + if (bmute){ + ret = RDAFM_enable_hmute(fm->i2c_client); + }else{ + ret = RDAFM_clear_hmute(fm->i2c_client); + } + + up(&fm_ops_mutex); + + break; + } + + case FM_IOCTL_GETRSSI: + { + uint32_t rssi; + FM_DEBUG("FM_IOCTL_GETRSSI\n"); + +// FIXME!! +// if (!capable(CAP_SYS_ADMIN)) +// return -EPERM; + + if (down_interruptible(&fm_ops_mutex)) + return -EFAULT; + + ret = fm_getrssi(fm, &rssi); + up(&fm_ops_mutex); + + if (copy_to_user((void*)arg, &rssi, sizeof(uint32_t))) + return -EFAULT; + + break; + } + + case FM_IOCTL_RW_REG: + { + struct fm_ctl_parm parm_ctl; + FM_DEBUG("FM_IOCTL_RW_REG\n"); + +// FIXME!! +// if (!capable(CAP_SYS_ADMIN)) +// return -EPERM; + + if (copy_from_user(&parm_ctl, (void*)arg, sizeof(struct fm_ctl_parm))) + return -EFAULT; + + if (down_interruptible(&fm_ops_mutex)) + return -EFAULT; + + if(parm_ctl.rw_flag == 0) //write + { + ret = RDAFM_write(fm->i2c_client, parm_ctl.addr, parm_ctl.val); + } + else + { + ret = RDAFM_read(fm->i2c_client, parm_ctl.addr, &parm_ctl.val); + } + + up(&fm_ops_mutex); + if ((parm_ctl.rw_flag == 0x01) && (!ret)) // Read success. + { + if (copy_to_user((void*)arg, &parm_ctl, sizeof(struct fm_ctl_parm))) + return -EFAULT; + } + break; + } + + case FM_IOCTL_GETCHIPID: + { + uint16_t chipid; + + if (down_interruptible(&fm_ops_mutex)) + return -EFAULT; + + RDAFM_GetChipID(fm->i2c_client, &chipid); + //chipid = fm->chip_id; + chipid = 0x6620; + FM_DEBUG("FM_IOCTL_GETCHIPID:%04x\n", chipid); + up(&fm_ops_mutex); + + if (copy_to_user((void*)arg, &chipid, sizeof(uint16_t))) + return -EFAULT; + + break; + } + + case FM_IOCTL_EM_TEST: + { + struct fm_em_parm parm_em; + FM_DEBUG("FM_IOCTL_EM_TEST\n"); + +// FIXME!! +// if (!capable(CAP_SYS_ADMIN)) +// return -EPERM; + + if (copy_from_user(&parm_em, (void*)arg, sizeof(struct fm_em_parm))) + return -EFAULT; + + if (down_interruptible(&fm_ops_mutex)) + return -EFAULT; + + RDAFM_em_test(fm->i2c_client, parm_em.group_idx, parm_em.item_idx, parm_em.item_value); + + up(&fm_ops_mutex); + + break; + } + case FM_IOCTL_IS_FM_POWERED_UP: + { + uint32_t powerup; + FM_DEBUG("FM_IOCTL_IS_FM_POWERED_UP"); + if (fm->powerup) { + powerup = 1; + } else { + powerup = 0; + } + if (copy_to_user((void*)arg, &powerup, sizeof(uint32_t))) + return -EFAULT; + break; + } + +#ifdef FMDEBUG + case FM_IOCTL_DUMP_REG: + { + uint16_t chipid = 0; + if (down_interruptible(&fm_ops_mutex)) + return -EFAULT; + RDAFM_GetChipID(fm->i2c_client, &chipid); + up(&fm_ops_mutex); + + break; + } +#endif + + case FM_IOCTL_SCAN: + { + struct fm_scan_parm parm; + FM_DEBUG("FM_IOCTL_SCAN\n"); + if (false == fm->powerup){ + return -EFAULT; + } + if(copy_from_user(&parm, (void*)arg, sizeof(struct fm_scan_parm))){ + return -EFAULT; + } + if (down_interruptible(&fm_ops_mutex)){ + return -EFAULT; + } + fm_scan(fm, &parm); + up(&fm_ops_mutex); + + if(copy_to_user((void*)arg, &parm, sizeof(struct fm_scan_parm))){ + return -EFAULT; + } + + break; + } + + case FM_IOCTL_STOP_SCAN: + { + FM_DEBUG("FM_IOCTL_STOP_SCAN\n"); + break; + } + + default: + { + FM_DEBUG("default\n"); + break; + } + } + + return ret; +} +static loff_t fm_ops_lseek(struct file *filp, loff_t off, int whence) +{ +// struct fm *fm = filp->private_data; + + if(whence == SEEK_END){ + //fm_hwscan_stop(fm); + atomic_set(&scan_complete_flag, 0); + }else if(whence == SEEK_SET){ + //FM_EVENT_SEND(fm->rds_event, FM_RDS_DATA_READY); + } + return off; +} + +static int fm_ops_open(struct inode *inode, struct file *filp) +{ + struct fm *fm = container_of(inode->i_cdev, struct fm, cdev); + + FM_DEBUG("%s\n", __func__); + + if (down_interruptible(&fm_ops_mutex)) + return -EFAULT; + + // TODO: only have to set in the first time? + // YES!!!! + + fm->ref++; + + up(&fm_ops_mutex); + + filp->private_data = fm; + + // TODO: check open flags + + return 0; +} + +static int fm_ops_release(struct inode *inode, struct file *filp) +{ + int err = 0; + struct fm *fm = container_of(inode->i_cdev, struct fm, cdev); + + FM_DEBUG("%s\n", __func__); + + if (down_interruptible(&fm_ops_mutex)) + return -EFAULT; + fm->ref--; + if(fm->ref < 1) { + if(fm->powerup == true) { + fm_powerdown(fm); + } + } + + up(&fm_ops_mutex); + + return err; +} + +//#define WMT_TEST_ORI 1 + +static int fm_init(struct i2c_client *client) +{ + int err; + struct fm *fm = NULL; + int ret = -1; + + + FM_DEBUG("%s()\n", __func__); + if (!(fm = kzalloc(sizeof(struct fm), GFP_KERNEL))) + { + FM_ALERT("-ENOMEM\n"); + err = -ENOMEM; + goto ERR_EXIT; + } + + fm->ref = 0; + fm->powerup = false; + atomic_set(&scan_complete_flag, 0); + +#ifdef RDA599X_FM_SUPPORT + + ret = rda_fm_power_on(); + if(ret < 0){ + err = -ENOMEM; + goto ERR_EXIT; + } + msleep(100); +#endif + + // First, read 5802NM chip ID + FM_DEBUG("%s()First, read 5802NM chip ID\n", __func__); + ret = RDAFM_GetChipID(client, &RDAFM_CHIP_ID); + if(ret < 0){ + FM_DEBUG("%s() read RDA chip ID failed\n", __func__); + err = -ENOMEM; + goto ERR_EXIT; + } + else{ + fm->chip_id = RDAFM_CHIP_ID; + } + + FM_DEBUG("%s() 5802NM chip ID = 0x%04x\n", __func__, RDAFM_CHIP_ID); + +#ifdef RDA599X_FM_SUPPORT + ret = rda_fm_power_off(); + if(ret < 0){ + err = -ENOMEM; + goto ERR_EXIT; + } +#endif + + +#if WMT_TEST_ORI + printk("ori code\n"); + // if failed, means use FM in 5990P_E + if(ret < 0){ + // enable the FM chip in combo + FM_DEBUG("%s() enable the FM chip in combo\n", __func__); + ret = rda_fm_power_on(); + if(ret < 0){ + err = -ENOMEM; + goto ERR_EXIT; + } + msleep(100); + ret = RDAFM_GetChipID(client, &RDAFM_CHIP_ID); + FM_DEBUG("%s() the FM in combo chip ID = 0x%04x\n", __func__, RDAFM_CHIP_ID); + if(ret < 0){ + err = -ENOMEM; + goto ERR_EXIT; + }else{ + fm->chip_id = RDAFM_CHIP_ID; + } + + // disable the FM chip for power saving + ret = rda_fm_power_off(); + if(ret < 0){ + err = -ENOMEM; + goto ERR_EXIT; + } + }else{ + fm->chip_id = RDAFM_CHIP_ID; + } + + +#endif + + + if ((err = fm_setup_cdev(fm))) + { + goto ERR_EXIT; + } + + g_fm_struct = fm; + fm->i2c_client = client; + i2c_set_clientdata(client, fm); + + + /***********Add porc file system*************/ + + g_fm_proc = create_proc_entry(FM_PROC_FILE, 0444, NULL); + if (g_fm_proc == NULL) { + FM_ALERT("create_proc_entry failed\n"); + err = -ENOMEM; + goto ERR_EXIT; + } else { + g_fm_proc->read_proc = fm_proc_read; + g_fm_proc->write_proc = NULL; + //g_fm_proc->owner = THIS_MODULE; + FM_ALERT("create_proc_entry success\n"); + } + + /********************************************/ + + FM_DEBUG("fm_init is ok!\n"); + + return 0; + +ERR_EXIT: + kfree(fm); +#ifdef RDA599X_FM_SUPPORT + rda_fm_power_off(); +#endif + + return err; +} + +static int fm_proc_read(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + int cnt= 0; + struct fm *fm = g_fm_struct; + FM_ALERT("Enter fm_proc_read.\n"); + if(off != 0) + return 0; + if (fm != NULL && fm->powerup) { + cnt = sprintf(page, "1\n"); + } else { + cnt = sprintf(page, "0\n"); + } + *eof = 1; + FM_ALERT("Leave fm_proc_read. cnt = %d\n", cnt); + return cnt; +} + + +static int fm_destroy(struct fm *fm) +{ + int err = 0; + + FM_DEBUG("%s\n", __func__); + + device_destroy(fm->cls, fm->dev_t); + class_destroy(fm->cls); + + cdev_del(&fm->cdev); + unregister_chrdev_region(fm->dev_t, 1); + + fm_powerdown(fm); + + /***********************************/ + remove_proc_entry(FM_PROC_FILE, NULL); + + /**********************************/ + + // FIXME: any other hardware configuration ? + + // free all memory + kfree(fm); + + return err; +} + +/* + * fm_powerup + */ +static int fm_powerup(struct fm *fm, struct fm_tune_parm *parm) +{ + int i; + uint16_t tRegValue = 0x0002; + int ret = -1; + + struct i2c_client *client = fm->i2c_client; + + if (fm->powerup) + { + parm->err = FM_BADSTATUS; + return -EPERM; + } + + // if chip_id is ID_RDA5820NS, enable the FM chip in combo +#ifdef RDA599X_FM_SUPPORT + ret = rda_fm_power_on(); + if(ret < 0){ + return -EPERM; + } + msleep(100); +#endif + + + //Reset RDA FM + tRegValue = 0x0002; + RDAFM_write(client, 0x02, tRegValue); + msleep(100); + + if ((ID_RDA5802N == RDAFM_CHIP_ID) || (ID_RDA5802H == RDAFM_CHIP_ID)){ + //if (ID_RDA5802N == RDAFM_CHIP_ID){ + + for (i=0; i<((sizeof(RDA5802N_initialization_reg)) / (sizeof(uint16_t))); i++) + { + ret = RDAFM_write(client, i+2, RDA5802N_initialization_reg[i]); + + if (ret < 0) + { + FM_DEBUG("fm_powerup init failed!\n"); + FM_ALERT("fm_powerup init failed!\n"); + parm->err = FM_FAILED; + + return -EPERM; + } + } + + }else if (ID_RDA5820NS == RDAFM_CHIP_ID){ + if(RDA_RADIO_WorkType == FM_RECEIVER){ + for (i = 0; i < ((sizeof(RDA5820NS_RX_initialization_reg)) / (sizeof(RDA_FM_REG_T))); i++) + { + if(RDA5820NS_RX_initialization_reg[i].address == 0xFF){ + msleep(RDA5820NS_RX_initialization_reg[i].value); + }else{ + ret = RDAFM_write(client, RDA5820NS_RX_initialization_reg[i].address, RDA5820NS_RX_initialization_reg[i].value); + if (ret < 0) + { + FM_DEBUG("fm_powerup init failed!\n"); + parm->err = FM_FAILED; + return -EPERM; + } + } + } + }else{ + for (i = 0; i < ((sizeof(RDA5820NS_TX_initialization_reg)) / (sizeof(RDA_FM_REG_T))); i++) + { + if(RDA5820NS_TX_initialization_reg[i].address == 0xFF){ + msleep(RDA5820NS_TX_initialization_reg[i].value); + }else{ + ret = RDAFM_write(client, RDA5820NS_TX_initialization_reg[i].address, RDA5820NS_TX_initialization_reg[i].value); + if (ret < 0) + { + FM_DEBUG("fm_powerup init failed!\n"); + parm->err = FM_FAILED; + return -EPERM; + } + } + } + } + + } + + + FM_DEBUG("pwron ok\n"); + fm->powerup = true; + + if (fm_tune(fm, parm) < 0) + { + return -EPERM; + } + fm_tune_data.byPowerUp = true; + memcpy(&fm_tune_data.parm, parm, sizeof(fm_tune_data.parm)); + + parm->err = FM_SUCCESS; + + return 0; + +} + +/* + * fm_powerdown + */ +static int fm_powerdown(struct fm *fm) +{ + uint16_t tRegValue = 0; + int ret = -1; + struct i2c_client *client = fm->i2c_client; + + RDAFM_read(client, 0x02, &tRegValue); + tRegValue &= (~(1 << 0)); + RDAFM_write(client, 0x02, tRegValue); +/* + if((fm->chip_id == ID_RDA5820NS) || (fm->chip_id == ID_RDA5991_FM){ + ret = rda_fm_power_off(); + if(ret < 0){ + return -EPERM; + } + } +*/ + +#ifdef RDA599X_FM_SUPPORT + ret = rda_fm_power_off(); + if(ret < 0){ + return -EPERM; + } +#endif + + + fm->powerup = false; + FM_ALERT("pwrdown ok\n"); + + return 0; +} + +/* + * fm_seek + */ +static int fm_seek(struct fm *fm, struct fm_seek_parm *parm) +{ + int ret = 0; + uint16_t val = 0; + uint8_t spaec = 1; + uint16_t tFreq = 875; + uint16_t tRegValue = 0; + uint16_t bottomOfBand = 875; + int falseStation = -1; + + + struct i2c_client *client = fm->i2c_client; + + if (!fm->powerup) + { + parm->err = FM_BADSTATUS; + return -EPERM; + } + + if (parm->space == FM_SPACE_100K) + { + spaec = 1; + val &= (~((1<<0) | (1<<1))); + } + else if (parm->space == FM_SPACE_200K) + { + spaec = 2; + val &= (~(1<<1)); + val |= (1<<0); + } + else + { + parm->err = FM_EPARM; + return -EPERM; + } + + if (parm->band == FM_BAND_UE) + { + val &= (~((1<<2) | (1<<3))); + bottomOfBand = 875; + fm->min_freq = 875; + fm->max_freq = 1080; + } + else if (parm->band == FM_BAND_JAPAN) + { + val &= (~(1<<3)); + val |= (1 << 2); + bottomOfBand = 760; + fm->min_freq = 760; + fm->max_freq = 910; + } + else if (parm->band == FM_BAND_JAPANW) { + val &= (~(1<<2)); + val |= (1 << 3); + bottomOfBand = 760; + fm->min_freq = 760; + fm->max_freq = 1080; + } + else + { + FM_ALERT("band:%d out of range\n", parm->band); + parm->err = FM_EPARM; + return -EPERM; + } + + if (parm->freq < fm->min_freq || parm->freq > fm->max_freq) { + FM_ALERT("freq:%d out of range\n", parm->freq); + parm->err = FM_EPARM; + return -EPERM; + } + + if (parm->seekth > 0x0B) { + FM_ALERT("seekth:%d out of range\n", parm->seekth); + parm->err = FM_EPARM; + return -EPERM; + } +#if 0 + RDAFM_read(client, 0x05, &tRegValue); + tRegValue &= (~(0x7f<<8)); + //tRegValue |= ((parm->seekth & 0x7f) << 8); + tRegValue |= ((0x8 & 0x7f) << 8); + RDAFM_write(client, 0x05, tRegValue); +#endif + +#ifdef FMDEBUG + if (parm->seekdir == FM_SEEK_UP) + FM_DEBUG("seek %d up\n", parm->freq); + else + FM_DEBUG("seek %d down\n", parm->freq); +#endif + + // (1) set hmute bit + RDAFM_enable_hmute(client); + + tFreq = parm->freq; + + do { + if (parm->seekdir == FM_SEEK_UP) + tFreq += spaec; + else + tFreq -= spaec; + + if (tFreq > fm->max_freq) + tFreq = fm->min_freq; + if (tFreq < fm->min_freq) + tFreq = fm->max_freq; + + val = (((tFreq - bottomOfBand+5) << 6) | (1 << 4) | (val & 0x0f)); + RDAFM_write(client, 0x03, val); + msleep(40); + ret = RDAFM_read(client, 0x0B, &tRegValue); + if (ret < 0) + { + FM_DEBUG("fm_seek: read register failed tunning freq = %4X\n", tFreq); + falseStation = -1; + } + else + { + if ((tRegValue & 0x0100) == 0x0100) + falseStation = 0; + else + falseStation = -1; + } + + if(falseStation == 0) + break; + }while(tFreq != parm->freq); + + + //clear hmute + RDAFM_clear_hmute(client); + + if (falseStation == 0) // seek successfully + { + parm->freq = tFreq; + FM_ALERT("fm_seek success, freq:%d\n", parm->freq); + parm->err = FM_SUCCESS; + } + else + { + FM_ALERT("fm_seek failed, invalid freq\n"); + parm->err = FM_SEEK_FAILED; + ret = -1; + } + + return ret; +} +static int fm_scan(struct fm *fm, struct fm_scan_parm *parm) +{ + int ret = 0; + uint16_t tRegValue = 0; + uint16_t scandir = RDA599X_FM_SCAN_UP; //scandir 搜索方向 + uint8_t space = 1; + struct i2c_client *client = fm->i2c_client; + + if (!fm->powerup){ + parm->err = FM_BADSTATUS; + return -EPERM; + } + + RDAFM_read(client, 0x03, &tRegValue); + + if (parm->space == FM_SPACE_100K){ + space = 1; + tRegValue &= (~((1<<0) | (1<<1))); //set 03H's bit[1:0] to 00 + }else if (parm->space == FM_SPACE_200K) { + space = 2; + tRegValue &= (~(1<<1)); //clear bit[1] + tRegValue |= (1<<0); //set bit[0] + }else{ + //default + space = 1; + tRegValue &= (~((1<<0) | (1<<1))); //set 03H's bit[1:0] to 00 + } + + if(parm->band == FM_BAND_UE){ + tRegValue &= (~((1<<2) | (1<<3))); + fm->min_freq = 875; + fm->max_freq = 1080; + }else if(parm->band == FM_BAND_JAPAN){ + tRegValue &= (~(1<<3)); + tRegValue |= (1 << 2); + fm->min_freq = 760; + fm->max_freq = 900; + }else if(parm->band == FM_BAND_JAPANW){ + tRegValue &= (~(1<<2)); + tRegValue |= (1 << 3); + fm->min_freq = 760; + fm->max_freq = 1080; + }else{ + parm->err = FM_EPARM; + return -EPERM; + } + + //set space and band + RDAFM_write(client, 0x03, tRegValue); + msleep(40); + + + if(RDAFM_Scan(client, fm->min_freq, fm->max_freq, &(parm->freq), parm->ScanTBL, &(parm->ScanTBLSize), scandir, space)){ + parm->err = FM_SUCCESS; + }else{ + parm->err = FM_SEEK_FAILED; + } + + return ret; +} + + +static int fm_setvol(struct fm *fm, uint32_t vol) +{ + int ret = 0; + uint16_t tRegValue = 0; + struct i2c_client *client = fm->i2c_client; + + if (vol > 15) + vol = 15; + + FM_DEBUG("fm_setvol:%d\n", vol); + + ret = RDAFM_read(client, 0x05, &tRegValue); + if (ret) + return -EPERM; + tRegValue &= ~(0x000f); + tRegValue |= vol; + + ret = RDAFM_write(client, 0x05, tRegValue); + if (ret) + return -EPERM; + + return 0; +} + +static int fm_getvol(struct fm *fm, uint32_t *vol) +{ + int ret = 0; + uint16_t tRegValue; + struct i2c_client *client = fm->i2c_client; + + ret = RDAFM_read(client, 0x05, &tRegValue); + if (ret) + return -EPERM; + + + *vol = (tRegValue & 0x000F); + + return 0; +} + +static int fm_getrssi(struct fm *fm, uint32_t *rssi) +{ + int ret = 0; + uint16_t tRegValue; + struct i2c_client *client = fm->i2c_client; + + ret = RDAFM_read(client, 0x0B, &tRegValue); + if (ret) + return -EPERM; + + + *rssi = (uint32_t)((tRegValue >> 9) & RDAFM_MASK_RSSI); + + FM_DEBUG("rssi value:%d\n", *rssi); + + return 0; +} + +/* + * fm_tune + */ +static int fm_tune(struct fm *fm, struct fm_tune_parm *parm) +{ + int ret; + uint16_t val = 0; + uint8_t space = 1; + uint16_t bottomOfBand = 875; + + struct i2c_client *client = fm->i2c_client; + + FM_DEBUG("%s\n", __func__); + + if (!fm->powerup) + { + parm->err = FM_BADSTATUS; + return -EPERM; + } + + if (parm->space == FM_SPACE_100K) + { + space = 1; + val &= (~((1<<0) | (1<<1))); + } + else if (parm->space == FM_SPACE_200K) + { + space = 2; + val |= (1<<0); + val &= (~(1<<1)); + } + else + { + parm->err = FM_EPARM; + return -EPERM; + } + + if (parm->band == FM_BAND_UE) + { + val &= (~((1<<2) | (1<<3))); + bottomOfBand = 875; + fm->min_freq = 875; + fm->max_freq = 1080; + } + else if (parm->band == FM_BAND_JAPAN) + { + val &= (~(1<<3)); + val |= (1 << 2); + bottomOfBand = 760; + fm->min_freq = 760; + fm->max_freq = 910; + } + else if (parm->band == FM_BAND_JAPANW) { + val &= (~(1<<2)); + val |= (1 << 3); + bottomOfBand = 760; + fm->min_freq = 760; + fm->max_freq = 1080; + } + else + { + FM_ALERT("band:%d out of range\n", parm->band); + parm->err = FM_EPARM; + return -EPERM; + } + + if (parm->freq < fm->min_freq || parm->freq > fm->max_freq) { + FM_ALERT("freq:%d out of range\n", parm->freq); + parm->err = FM_EPARM; + return -EPERM; + } + + FM_DEBUG("fm_tune, freq:%d\n", parm->freq); + + //RDAFM_enable_hmute(client); + + val = (((parm->freq - bottomOfBand + 5) << 6) | (1 << 4) | (val & 0x0f)); + + ret = RDAFM_write(client, 0x03, val); + if (ret < 0) + { + FM_ALERT("fm_tune write freq failed\n"); + parm->err = FM_SEEK_FAILED; + return ret; + } + msleep(40); + +#ifdef FM_DEBUG + RDAFM_read(client, 0x0A, &val); + FM_DEBUG("%s() read freq reg value = 0x%04x\n", __func__, val); +#endif + + return ret; +} + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31)) +/* + * fm_i2c_attach_adapter + */ +static int fm_i2c_attach_adapter(struct i2c_adapter *adapter) +{ + int err = 0; + + if (adapter->id == RDAFM_I2C_PORT) + { + return i2c_probe(adapter, &RDAFM_addr_data, fm_i2c_detect); + } + + return err; +} + +/* + * fm_i2c_detect + * This function is called by i2c_detect + */ +static int fm_i2c_detect(struct i2c_adapter *adapter, int addr, int kind) +{ + int err; + struct i2c_client *client = NULL; + + /* skip this since MT6516 shall support all the needed functionalities + if (!i2c_check_functionality(adapter, xxx)) + { + FM_DEBUG("i2c_check_functionality failed\n"); + return -ENOTSUPP; + } + */ + + /* initial i2c client */ + if (!(client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL))) + { + FM_ALERT("kzalloc failed\n"); + err = -ENOMEM; + goto ERR_EXIT; + } + + client->addr = addr; + client->adapter = adapter; + client->driver = &RDAFM_driver; + client->flags = 0; + strncpy(client->name, "RDA FM RADIO", I2C_NAME_SIZE); + + if ((err = fm_init(client))) + { + FM_ALERT("fm_init ERR:%d\n", err); + goto ERR_EXIT; + } + + if (err = i2c_attach_client(client)) + { + FM_ALERT("i2c_attach_client ERR:%d\n", err); + goto ERR_EXIT; + } + + return 0; + +ERR_EXIT: + kfree(client); + + return err; +} +static int fm_i2c_detach_client(struct i2c_client *client) +{ + int err = 0; + struct fm *fm = i2c_get_clientdata(client); + + FM_DEBUG("fm_i2c_detach_client\n"); + + err = i2c_detach_client(client); + if (err) + { + dev_err(&client->dev, "fm_i2c_detach_client failed\n"); + return err; + } + + fm_destroy(fm); + kfree(client); + + return err; +} +#else +static int fm_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + int err = -1; + FM_DEBUG("fm_i2c_probe\n"); + //client->timing = 50; + //client->timing = 200; + if ((err = fm_init(client))) + { + FM_ALERT("fm_init ERR:%d\n", err); + goto ERR_EXIT; + } + + return 0; + +ERR_EXIT: + return err; +} +/* +static int fm_for_read_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + client_for_read = client; + return 0; +} +*/ + +static int fm_i2c_detect(struct i2c_client *client, struct i2c_board_info *info) +{ + struct i2c_adapter *adapter = client->adapter; + if(adapter->nr == 1) + { + FM_DEBUG("fm_i2c_detect\n"); + strcpy(info->type, RDAFM_DEV); + return 0; + } + else + { + return -ENODEV; + } +} +/* +static int fm_for_read_i2c_detect(struct i2c_client *client, int kind, struct i2c_board_info *info) +{ + FM_DEBUG("fm_wifi_i2c_detect\n"); + printk(KERN_DEBUG "####[%s(): %d]\n", __func__, __LINE__); + strcpy(info->type, RDAFM_READ_DEV); + return 0; +} +*/ + +static int fm_i2c_remove(struct i2c_client *client) +{ + int err = 0; + struct fm *fm = i2c_get_clientdata(client); + + FM_DEBUG("fm_i2c_remove\n"); + if(fm) + { + fm_destroy(fm); + fm = NULL; + } + + return err; +} +/* +static int fm_for_read_i2c_remove(struct i2c_client *client) +{ + return 0; +} +*/ +#endif + +static int mt_fm_probe(struct platform_device *pdev) +{ + int err = -1; + FM_ALERT("mt_fm_probe\n"); + + /* + printk(KERN_DEBUG "####[%s(): %d]\n", __func__, __LINE__); + err = i2c_add_driver(&RDAFM_for_read_driver); + if (err) + { + FM_ALERT("i2c err\n"); + } + */ + + // Open I2C driver + err = i2c_add_driver(&RDAFM_driver); + if (err) + { + FM_ALERT("i2c err\n"); + } + + return err; +} + +static int mt_fm_remove(struct platform_device *pdev) +{ + FM_ALERT("mt_fm_remove\n"); + i2c_del_driver(&RDAFM_driver); + + return 0; +} + + +static struct platform_driver mt_fm_dev_drv = +{ + .probe = mt_fm_probe, + .remove = mt_fm_remove, +#if 0//def CONFIG_PM //Not need now + .suspend = mt_fm_suspend, + .resume = mt_fm_resume, +#endif + .driver = { + .name = FM_NAME, + .owner = THIS_MODULE, + } +}; + + + +#if defined(MTK_MT6515) +static void fm_release(struct device * dev) {} + +static struct platform_device mt_fm_device = { + .name = FM_NAME, + .id = 0, + .dev = { + .release = fm_release, + }, + +}; +#endif + +static void fm_test_tune() +{ + struct fm *fm; + struct fm_tune_parm parm; + + fm_powerup(fm, &parm); +} + +static struct i2c_client *rda_fm=NULL; + +#define RDA_FM_ADDR (0x11) +#define RDA_FM_I2C_DEVNAME "RDA_FM" +struct i2c_board_info rda_fm_i2c_board_info = { + .type = RDA_FM_I2C_DEVNAME, + .flags = 0x00, + .addr = RDA_FM_ADDR, + .platform_data = NULL, + .archdata = NULL, + .irq = -1, +}; + +static int rda_i2c_register_device (struct i2c_board_info *ts_i2c_bi,struct i2c_client **l_client) +{ + struct i2c_adapter *adapter = NULL; + + adapter = i2c_get_adapter(4); + + if (NULL == adapter) { + printk("can not get i2c adapter, client address error\n"); + return -1; + } + *l_client = i2c_new_device(adapter, ts_i2c_bi); + if (*l_client == NULL) { + printk("allocate i2c client failed\n"); + return -1; + } + i2c_put_adapter(adapter); + return 0; +} + +static void rda_i2c_unregister_device(struct i2c_client *l_client) +{ + if (l_client != NULL) + { + i2c_unregister_device(l_client); + l_client = NULL; + } +} + + + +/* + * mt_fm_init + */ +static int __init mt_fm_init(void) +{ + int err = 0; + rda_i2c_register_device(&rda_fm_i2c_board_info,&rda_fm); + + FM_ALERT("mt_fm_init\n"); +#if defined(MTK_MT6515) + err = platform_device_register(&mt_fm_device); + if(err){ + FM_ALERT("platform_device_register fail\n"); + return err; + }else{ + FM_ALERT("platform_device_register success\n"); + } +#endif + err = platform_driver_register(&mt_fm_dev_drv); + if (err) + { + FM_ALERT("platform_driver_register failed\n"); + }else{ + FM_ALERT("platform_driver_register success\n"); + } + + return err; +} + +/* + * mt_fm_exit + */ +static void __exit mt_fm_exit(void) +{ + FM_ALERT("mt_fm_exit\n"); + platform_driver_unregister(&mt_fm_dev_drv); +#if defined(MTK_MT6515) + platform_device_unregister(&mt_fm_device); +#endif + + rda_i2c_unregister_device(rda_fm); + +} + +module_init(mt_fm_init); +module_exit(mt_fm_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("MediaTek FM Driver"); +MODULE_AUTHOR("William Chung "); + + diff --git a/drivers/net/wireless/rda/rda_wlan/Makefile b/drivers/net/wireless/rda/rda_wlan/Makefile new file mode 100755 index 00000000..1be8914f --- /dev/null +++ b/drivers/net/wireless/rda/rda_wlan/Makefile @@ -0,0 +1,17 @@ +obj-m := rda_wlan.o +rda_wlan-objs := \ + wlan_module.o \ + wlan_init.o \ + wlan_rxtx.o \ + wlan_wid.o \ + wlan_wext.o \ + wlan_sdio_patch.o \ + wlan_nvram.o \ + wlan_scan.o \ + wlan_assoc.o \ + wlan_sdio.o \ + wlan_event.o\ + wlan_debugfs.o\ + wlan_aver_rssi.o + +subdir-ccflags-y := -Werror diff --git a/drivers/net/wireless/rda/rda_wlan/wlan_assoc.c b/drivers/net/wireless/rda/rda_wlan/wlan_assoc.c new file mode 100755 index 00000000..714c6c31 --- /dev/null +++ b/drivers/net/wireless/rda/rda_wlan/wlan_assoc.c @@ -0,0 +1,228 @@ +#include "wlan_includes.h" + + +//imode +/* BIT0: 1 -> Security ON 0 -> OFF */ +/* BIT1: 1 -> WEP40 cypher supported 0 -> Not supported */ +/* BIT2: 1 -> WEP104 cypher supported 0 -> Not supported */ +/* BIT3: 1 -> WPA mode supported 0 -> Not supported */ +/* BIT4: 1 -> WPA2 (RSN) supported 0 -> Not supported */ +/* BIT5: 1 -> AES-CCMP cphr supported 0 -> Not supported */ +/* BIT6: 1 -> TKIP cypher supported 0 -> Not supported */ +/* BIT7: 1 -> TSN supported 0 -> Not supported */ + +//authtype +/* BIT0: 1 -> OPEN SYSTEM */ +/* BIT1: 1 -> SHARED KEY */ +/* BIT3: 1 -> WAPI */ +static int assoc_helper_secinfo(wlan_private *priv, + struct bss_descriptor *assoc_bss) +{ + int ret = 0; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + + /* set imode and key */ + if ( !priv->secinfo.wep_enabled + && !priv->secinfo.WPAenabled && !priv->secinfo.WPA2enabled) { + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "%s, NO SEC\n", __func__); + priv->imode = 0; + } else { + u16 key_len = 0; + + if ( priv->secinfo.wep_enabled + && !priv->secinfo.WPAenabled + && !priv->secinfo.WPA2enabled) { + /* WEP */ + key_len = priv->wep_keys[0].len; + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "%s, WEP, len = %d\n", __func__, key_len * 8); + if (key_len == KEY_LEN_WEP_40) { + priv->imode = BIT0 | BIT1; + } else if (key_len == KEY_LEN_WEP_104) { + priv->imode = BIT0 | BIT2; + } else { + WLAN_ERRP("Invalide WEP Key length %d\n", key_len); + ret = -EINVAL; + goto out; + } + } else if ( !priv->secinfo.wep_enabled + && (priv->secinfo.WPAenabled || + priv->secinfo.WPA2enabled)) { + /* WPA */ + struct enc_key * pkey = NULL; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "%s, WPA cp:%x wpa:%d wpa2:%d \n", __func__, priv->secinfo.cipther_type, priv->secinfo.WPAenabled, priv->secinfo.WPA2enabled); + + if ( priv->wpa_mcast_key.len + && (priv->wpa_mcast_key.flags & KEY_INFO_WPA_ENABLED)) + pkey = &priv->wpa_mcast_key; + else if ( priv->wpa_unicast_key.len + && (priv->wpa_unicast_key.flags & KEY_INFO_WPA_ENABLED)) + pkey = &priv->wpa_unicast_key; + + priv->imode = 0; + /* turn on security */ + priv->imode |= (BIT0); + priv->imode &= ~(BIT3 | BIT4); + if (priv->secinfo.WPA2enabled) + priv->imode |= (BIT4); + else if (priv->secinfo.WPAenabled) + priv->imode |= (BIT3); + /* + * we don't know the cipher type by now + * use dot11i_info to decide + * and use CCMP if possible + */ + priv->imode &= ~(BIT5 | BIT6); + if (priv->secinfo.cipther_type & IW_AUTH_CIPHER_CCMP) + priv->imode |= BIT5; + else if (priv->secinfo.cipther_type & IW_AUTH_CIPHER_TKIP) + priv->imode |= BIT6; + } else { + WLAN_ERRP("WEP and WPA/WPA2 enabled simutanously\n"); + ret = -EINVAL; + goto out; + } + } + + /* set authtype */ + if (priv->secinfo.auth_mode & IW_AUTH_ALG_OPEN_SYSTEM + || priv->secinfo.auth_mode & IW_AUTH_ALG_SHARED_KEY){ + + if (priv->secinfo.auth_mode & IW_AUTH_ALG_OPEN_SYSTEM){ + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "%s, Open Auth, KEY_MGMT = %d, AUTH_ALG mode:%x\n", __func__, priv->secinfo.key_mgmt, priv->secinfo.auth_mode); + if (priv->secinfo.key_mgmt == 0x01) + priv->authtype = BIT2; + else + priv->authtype = BIT0; + }else if(priv->secinfo.auth_mode & IW_AUTH_ALG_SHARED_KEY){ + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "%s, Shared-Key Auth AUTH_ALG mode:%x \n", __func__, priv->secinfo.auth_mode); + priv->authtype = BIT1; + } + + if (priv->secinfo.key_mgmt == WAPI_KEY_MGMT_PSK + || priv->secinfo.key_mgmt == WAPI_KEY_MGMT_CERT) + priv->authtype = BIT3; + + }else if (priv->secinfo.auth_mode == IW_AUTH_ALG_WAPI) { + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "%s, Shared-Key Auth\n", __func__); + priv->authtype = IW_AUTH_ALG_WAPI; + }else if (priv->secinfo.auth_mode == IW_AUTH_ALG_LEAP) { + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "%s, LEAP Auth, not supported\n", __func__); + ret = -EINVAL; + goto out; + }else { + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "%s, Unknown Auth\n", __func__); + ret = -EINVAL; + goto out; + } + +out: + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>> \n", __func__); + return ret; +} + + +void wlan_assocication(wlan_private* priv) +{ + int ret = 0; + struct bss_descriptor *assoc_bss; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + assoc_bss = get_bss_desc_from_scanlist(priv, priv->assoc_bssid); + if (assoc_bss == NULL) { + WLAN_ERRP("****fail to find bss in the scan list\n"); + ret = -EINVAL; + goto out; + } + + priv->curbssparams.channel = assoc_bss->channel; + memcpy(priv->curbssparams.bssid, assoc_bss->bssid, ETH_ALEN); + memcpy(priv->curbssparams.ssid, assoc_bss->ssid,IW_ESSID_MAX_SIZE + 1); + + ret = assoc_helper_secinfo(priv, assoc_bss); + if (ret) { + WLAN_ERRP("assoc_helper_secinfo fail, ret = %d\n", ret); + goto out; + } + + //wep so we need retry association + if (priv->imode & 0x06) { + priv->ToggalAssociation = TRUE; + } + + ret = wlan_start_join(priv); + if (ret) { + WLAN_ERRP("wlan_set_ssid fail, ret = %d\n", ret); + wlan_cancel_timer(&priv->AssociationTimeOut); + priv->assoc_ongoing = FALSE; + goto out; + } + + //25S for association + wlan_mod_timer(&priv->AssociationTimeOut, 25000); + + //reassociation + wlan_mod_timer(&priv->ReAssociationTimeOut, 3000); +out: + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<< \n", __func__); +} + +void wlan_re_assocication(wlan_private* priv) +{ + int ret = 0; + + ENTER(); +#ifdef WLAN_FORCE_SUSPEND_SUPPORT + if (priv->CardInSuspend == TRUE) { + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s ingnored in ap deep sleep mode.\n", __func__); + return; + } +#endif + if(priv->connect_status == MAC_CONNECTED) + return; + if(priv->reassoc_count++ > 4) + return; + //wep shared key & open turn arount + if (priv->imode & 0x06) { + if (priv->authtype == 0x01) + priv->authtype = 0x02; + else + priv->authtype = 0x01; + } + + ret = wlan_start_join(priv); + if (ret) { + WLAN_ERRP("wlan_set_ssid fail, ret = %d\n", ret); + return; + } + + wlan_mod_timer(&priv->ReAssociationTimeOut, 3000); + LEAVE(); +} + +void wlan_assocication_timeout(wlan_private* priv) +{ + + ENTER(); + + + wlan_cancel_timer(&priv->ReAssociationTimeOut); + + priv->assoc_ongoing = FALSE; + wlan_assoc_power_save(priv); + //restore tx rate + wlan_set_txrate(priv, 0); + + LEAVE(); +} + diff --git a/drivers/net/wireless/rda/rda_wlan/wlan_aver_rssi.c b/drivers/net/wireless/rda/rda_wlan/wlan_aver_rssi.c new file mode 100755 index 00000000..c4518238 --- /dev/null +++ b/drivers/net/wireless/rda/rda_wlan/wlan_aver_rssi.c @@ -0,0 +1,152 @@ +#include "wlan_includes.h" + +DEFINE_SPINLOCK(rssi_buf_lock); + +void wlan_add_new_aver_rssi(wlan_private * priv, u8 * bssid, u8 rssi) +{ + t_aver_bssid_rssi * list = (t_aver_bssid_rssi *)kmalloc(sizeof(t_aver_bssid_rssi), GFP_KERNEL); + + if(!list) + return; + + list->dirty = 0; + memset(list->rssi, 0, sizeof(list->rssi)); + + if(((s8)rssi) > 0) + rssi -= 0x100; + else if(((s8)rssi) > -20) + rssi = ((s8)rssi) - 20; + + list->rssi[0] = rssi; + list->index = 1; + list->count = 1; + memcpy(list->bssid, bssid, 6); + + spin_lock(&rssi_buf_lock); + list_add_tail(&list->list, &priv->AverRssiQ); + spin_unlock(&rssi_buf_lock); +} + +t_aver_bssid_rssi* wlan_find_bssid_in_aver_rssi(wlan_private * priv, u8 * bssid) +{ + t_aver_bssid_rssi * rssi_list = NULL; + + spin_lock(&rssi_buf_lock); + + if(list_empty(&priv->AverRssiQ)){ + spin_unlock(&rssi_buf_lock); + return NULL; + } + + list_for_each_entry(rssi_list, &priv->AverRssiQ, list){ + if(memcmp(bssid, rssi_list->bssid, 6) == 0){ + spin_unlock(&rssi_buf_lock); + return rssi_list; + } + } + + spin_unlock(&rssi_buf_lock); + return NULL; +} + +void wlan_set_aver_rssi(t_aver_bssid_rssi* aver_rssi, u8 rssi) +{ + u8 index = 0; + + u8 *ch = 0; + ch = aver_rssi->bssid; + + if(((s8)rssi) > 0) + rssi -= 0x100; + else if(((s8)rssi) > -20) + rssi = ((s8)rssi) - 20; + + index = aver_rssi->index; + aver_rssi->rssi[index] = rssi; + index = (index + 1)%MAX_RSSI_RECORD; + aver_rssi->index = index; + + if(aver_rssi->count < MAX_RSSI_RECORD) + aver_rssi->count ++; + + if(aver_rssi->dirty > 0) + aver_rssi->dirty --; +} + +void wlan_update_aver_rssi(wlan_private * priv, u8 * bssid, u8 rssi) +{ + t_aver_bssid_rssi* aver_rssi = NULL; + + aver_rssi = wlan_find_bssid_in_aver_rssi(priv, bssid); + if(aver_rssi) + wlan_set_aver_rssi(aver_rssi, rssi); + else + wlan_add_new_aver_rssi(priv, bssid, rssi); +} + +s8 wlan_cal_aver_rssi(t_aver_bssid_rssi* aver_rssi) +{ + s32 rssi = 0; + u8 i = 0, count = 0; + + count = aver_rssi->count; + + for(i = 0; i < count; i ++){ + rssi += (s8)aver_rssi->rssi[i]; + } + //-15 was hardware diff + return ((s8)(rssi/count)) - 15; +} + +s8 wlan_get_aver_rssi(wlan_private * priv, u8 * bssid) +{ + t_aver_bssid_rssi * rssi_list = NULL; + + rssi_list = wlan_find_bssid_in_aver_rssi(priv, bssid); + if(rssi_list) + return wlan_cal_aver_rssi(rssi_list); + else{ + return INVALID_RSSI; + } +} + +void wlan_set_rssi_dirty(wlan_private * priv) +{ + t_aver_bssid_rssi * rssi_list = NULL, *next = NULL; + + spin_lock(&rssi_buf_lock); + if(list_empty(&priv->AverRssiQ)){ + spin_unlock(&rssi_buf_lock); + return; + } + + list_for_each_entry_safe(rssi_list, next, &priv->AverRssiQ, list){ + rssi_list->dirty ++; + + if(rssi_list->dirty >= MAX_RSSI_RECORD){ + if(memcmp(rssi_list->bssid, priv->curbssparams.bssid, 6) != 0){ + list_del(&rssi_list->list); + kfree(rssi_list); + } + } + } + spin_unlock(&rssi_buf_lock); +} + +void wlan_free_aver_rssi(wlan_private * priv) +{ + t_aver_bssid_rssi * rssi_list = NULL, *next = NULL; + + spin_lock(&rssi_buf_lock); + if(list_empty(&priv->AverRssiQ)){ + spin_unlock(&rssi_buf_lock); + return; + } + + list_for_each_entry_safe(rssi_list, next, &priv->AverRssiQ, list){ + list_del(&rssi_list->list); + kfree(rssi_list); + } + spin_unlock(&rssi_buf_lock); +} + diff --git a/drivers/net/wireless/rda/rda_wlan/wlan_aver_rssi.h b/drivers/net/wireless/rda/rda_wlan/wlan_aver_rssi.h new file mode 100755 index 00000000..4fa5d260 --- /dev/null +++ b/drivers/net/wireless/rda/rda_wlan/wlan_aver_rssi.h @@ -0,0 +1,25 @@ +#ifndef __WLAN_AVER_RSSI_H__ +#define __WLAN_AVER_RSSI_H__ + +#define MAX_RSSI_RECORD (8) +#define INVALID_RSSI (-110) +typedef struct _t_aver_bssid_rssi{ + struct list_head list; + u8 bssid[6]; + s8 dirty; + u8 count; + u8 index; + u8 rssi[8]; +}t_aver_bssid_rssi; + + +void wlan_add_new_aver_rssi(wlan_private * priv, u8 * bssid, u8 rssi); +t_aver_bssid_rssi* wlan_find_bssid_in_aver_rssi(wlan_private * priv, u8 * bssid); +void wlan_update_aver_rssi(wlan_private * priv, u8 * bssid, u8 rssi); +void wlan_set_rssi_dirty(wlan_private * priv); +s8 wlan_cal_aver_rssi(t_aver_bssid_rssi* aver_rssi); +s8 wlan_get_aver_rssi(wlan_private * priv, u8 * bssid); +void wlan_free_aver_rssi(wlan_private * priv); + +#endif + diff --git a/drivers/net/wireless/rda/rda_wlan/wlan_debugfs.c b/drivers/net/wireless/rda/rda_wlan/wlan_debugfs.c new file mode 100755 index 00000000..c40edc36 --- /dev/null +++ b/drivers/net/wireless/rda/rda_wlan/wlan_debugfs.c @@ -0,0 +1,225 @@ +#include "wlan_includes.h" + +static int open_file_generic(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +#define FOPS(fread, fwrite) { \ + .owner = THIS_MODULE, \ + .open = open_file_generic, \ + .read = (fread), \ + .write = (fwrite), \ +} + +struct wlan_debugfs_files { + char *name; + int perm; + struct file_operations fops; +}; + +extern int wlan_dbg_level; +extern int wlan_dbg_area; +static struct dentry *wlan_dbg_dir = NULL; + +static ssize_t wlan_debugarea_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + size_t pos = 0; + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *)addr; + ssize_t res; + + WLAN_DBGLAP(WLAN_DA_SDIO, WLAN_DL_TRACE, + "%s\n", __func__); + + WLAN_DBGLAP(WLAN_DA_SDIO, WLAN_DL_TRACE, + "get debug_area = 0x%x\n",wlan_dbg_area); + + pos += snprintf(buf+pos, PAGE_SIZE - pos, "%x\n", + wlan_dbg_area); + + res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); + + free_page(addr); + return res; +} + +static ssize_t wlan_debugarea_write(struct file *file, + const char __user *user_buf, size_t count, + loff_t *ppos) +{ + ssize_t ret; + int debug_area; + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *)addr; + + WLAN_DBGLAP(WLAN_DA_SDIO, WLAN_DL_TRACE, + "%s count:%d \n", __func__, count); + + if (copy_from_user(buf, user_buf, count)) { + ret = -EFAULT; + goto out_unlock; + } + ret = sscanf(buf, "%x", &debug_area); + if (ret != 1) { + ret = -EINVAL; + goto out_unlock; + } + + wlan_dbg_area = debug_area; + WLAN_DBGLAP(WLAN_DA_SDIO, WLAN_DL_TRACE, + "set debug_area = 0x%x\n",wlan_dbg_area); + + ret = count; +out_unlock: + free_page(addr); + return ret; +} + +static ssize_t wlan_debuglevel_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + size_t pos = 0; + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *)addr; + ssize_t res; + + WLAN_DBGLAP(WLAN_DA_SDIO, WLAN_DL_TRACE, + "%s\n", __func__); + + WLAN_DBGLAP(WLAN_DA_SDIO, WLAN_DL_TRACE, + "get debug_level = 0x%x\n",wlan_dbg_level); + + pos += snprintf(buf+pos, PAGE_SIZE - pos, "%x\n", + wlan_dbg_level); + + res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); + + free_page(addr); + return res; +} + +static ssize_t wlan_debuglevel_write(struct file *file, + const char __user *user_buf, size_t count, + loff_t *ppos) +{ + ssize_t ret; + int debug_level; + unsigned long addr = get_zeroed_page(GFP_KERNEL); + char *buf = (char *)addr; + + WLAN_DBGLAP(WLAN_DA_SDIO, WLAN_DL_TRACE, + "%s\n", __func__); + + if (copy_from_user(buf, user_buf, count)) { + ret = -EFAULT; + goto out_unlock; + } + ret = sscanf(buf, "%x", &debug_level); + if (ret != 1) { + ret = -EINVAL; + goto out_unlock; + } + + wlan_dbg_level = debug_level; + + WLAN_DBGLAP(WLAN_DA_SDIO, WLAN_DL_TRACE, + "set debug_level = 0x%x\n",wlan_dbg_level); + + ret = count; +out_unlock: + free_page(addr); + return ret; +} + +#if 0 +static ssize_t wlan_loopback_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + ssize_t ret; + ret = 0; + return ret; +} + +static ssize_t wlan_loopback_write(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + ssize_t ret; + ret = 0; + return ret; +} +#endif + +static struct wlan_debugfs_files debugfs_files[] = { + { "debugarea", 0444, FOPS(wlan_debugarea_read, wlan_debugarea_write), }, + { "debuglevel", 0444, FOPS(wlan_debuglevel_read, wlan_debuglevel_write), }, + //{ "loopback", 0444, FOPS(wlan_loopback_read, wlan_loopback_write), }, +}; + + +void wlan_debugfs_init(void) +{ + WLAN_DBGLAP(WLAN_DA_SDIO, WLAN_DL_DEBUG, + "%s\n", __func__); + + if (!wlan_dbg_dir) + wlan_dbg_dir = debugfs_create_dir("rdawlan", NULL); + + return; +} + +void wlan_debugfs_remove(void) +{ + WLAN_DBGLAP(WLAN_DA_SDIO, WLAN_DL_DEBUG, + "%s\n", __func__); + + if (wlan_dbg_dir) + debugfs_remove(wlan_dbg_dir); + + wlan_dbg_dir = NULL; + + return; +} + +void wlan_debugfs_init_all(wlan_private *priv) +{ + int i; + struct wlan_debugfs_files *files; + if (!wlan_dbg_dir) + goto exit; + + WLAN_DBGLAP(WLAN_DA_SDIO, WLAN_DL_DEBUG, + "%s\n", __func__); + + priv->debugfs_dir = debugfs_create_dir("rdawlan_dev", wlan_dbg_dir); + if (!priv->debugfs_dir) + goto exit; + + for (i=0; idebugfs_files[i] = debugfs_create_file(files->name, + files->perm, + priv->debugfs_dir, + priv, + &files->fops); + } + +exit: + return; +} + +void wlan_debugfs_remove_all(wlan_private *priv) +{ + int i; + + WLAN_DBGLAP(WLAN_DA_SDIO, WLAN_DL_DEBUG, + "%s\n", __func__); + + for(i=0; idebugfs_files[i]); + debugfs_remove(priv->debugfs_dir); +} + + diff --git a/drivers/net/wireless/rda/rda_wlan/wlan_defs.h b/drivers/net/wireless/rda/rda_wlan/wlan_defs.h new file mode 100755 index 00000000..00059422 --- /dev/null +++ b/drivers/net/wireless/rda/rda_wlan/wlan_defs.h @@ -0,0 +1,168 @@ +#ifndef _WLAN_DEFS_H_ +#define _WLAN_DEFS_H_ + +#ifndef __KERNEL__ +/** Character, 1 byte */ +typedef char s8; +/** Unsigned character, 1 byte */ +typedef unsigned char u8; + +/** Short integer */ +typedef signed short s16; +/** Unsigned short integer */ +typedef unsigned short u16; + +/** Long integer */ +typedef signed long s32; +/** Unsigned long integer */ +typedef unsigned long u32; + +/** Long long integer */ +typedef signed long long s64; +/** Unsigned long long integer */ +typedef unsigned long long u64; +#endif + +//#define NORMAL_FIXED +//#define WLAN_FLOW_CTRL_90E +#define WLAN_BIG_CURRENT_90E +//driver version +#define WLAN_SDIOWIFI_VER_MAJ 0 +#define WLAN_SDIOWIFI_VER_MIN 3 +#define WLAN_SDIOWIFI_VER_BLD 1 +//for not RDA PLATFORM,for example,Allwinner platform, don't define this +//#define RDA_ANDROID_PLATFORM 1 + +#define WLAN_VERSION_90_D (1) +#define WLAN_VERSION_90_E (2) +#define WLAN_VERSION_91 (3) +#define WLAN_VERSION_91_E (4) +#define WLAN_VERSION_91_F (5) + +//power manager +#define WLAN_SYS_SUSPEND +#define WLAN_POWER_MANAGER (1) +#define WLAN_UNLOCK_SYSTEM (1) +#define CARD_ENTER_SLEEP_TIMER (1000) +#define FLOW_CTRL_INT_SLEEP_RETRY_COUNT_91 25 +#define FLOW_CTRL_INT_SLEEP_RETRY_COUNT_90 30 +#define FLOW_CTRL_RXCMPL_RETRY_COUNT_91 30 +#define FLOW_CTRL_RXCMPL_RETRY_COUNT_90 2000 +#define SCAN_TIME_AT_EACH_CHANNEL 102 + +//#define WLAN_FORCE_SUSPEND_SUPPORT (1) +#define WIFI_SLEEP_LISTEN_INTERVAL 0xF0 +#define WIFI_SLEEP_LINK_LOSS_THRESHOLD_90 0x0A +#define WIFI_SLEEP_LINK_LOSS_THRESHOLD_91 0x0A +#define DEFAULT_MAX_SCAN_AGE (25*HZ) +#define GET_SCAN_FROM_NETWORK_INFO (1) +#define USE_MAC_DYNAMIC_ONCE (1) +//#define USE_MAC_FROM_RDA_NVRAM +#define WIFI_MAC_ACTIVATED_FLAG 0x5990 + +#define DEFAULT_WATCHDOG_TIMEOUT (5 * HZ) +#define WID_HEADER_LEN (2) +#define CHECK_SDIO_STAUTS (1) +#define WLAN_SDIO_MAX_ERR (3) +#define WLAN_EVENT_MAX_ERR (3) + +//queue number form wid cmd & sdio received queue +#define WLAN_CMD_QUEUE_NUM (10) +#define WLAN_RX_QUEUE_NUM (10) +#define WLAN_TX_QUEUE_NUM_90 (10) +#define WLAN_TX_QUEUE_NUM_91 (100) +#define SDIO_MAX_BUFSZ 2048 /* Maximum size of a sdio dma buffer */ + +#ifndef TRUE +#define TRUE (1) +#endif + +#ifndef FALSE +#define FALSE (0) +#endif + +#ifndef NULL +#define NULL ((void*)0) +#endif + +#define BIT7 (1 << 7) +#define BIT6 (1 << 6) +#define BIT5 (1 << 5) +#define BIT4 (1 << 4) +#define BIT3 (1 << 3) +#define BIT2 (1 << 2) +#define BIT1 (1 << 1) +#define BIT0 (1 << 0) + +#define CLEAR_BIT(X , Y) (X) &= (~(Y)) +#define SET_BIT(X , Y) (X) |= (Y) + +#define RDA_SLEEP_ENABLE BIT0 +#define RDA_SLEEP_PREASSO BIT1 +#define WIFI_LISTEN_INTERVAL 0x06 +/* link_loss_threshold */ +#define WIFI_LINK_LOSS_THRESHOLD_90 0x20 +#define WIFI_LINK_LOSS_THRESHOLD_91 0x20 +/* Link Sleep Threashold,old Value: 0x00A00080 */ +#define WIFI_PREASSO_SLEEP 0x000500FF + +extern int wlan_dbg_level; +extern int wlan_dbg_area; + +typedef enum { + WLAN_DL_ALL = 0, + WLAN_DL_CRIT = 1, + WLAN_DL_TRACE = 2, + WLAN_DL_NORM = 3, + WLAN_DL_DEBUG = 4, + WLAN_DL_VERB = 5, +} WLAN_DBG_LEVEL; + +#define WLAN_DA_MAIN (1 << 0) +#define WLAN_DA_SDIO (1 << 1) +#define WLAN_DA_ETHER (1 << 2) +#define WLAN_DA_WID (1 << 3) +#define WLAN_DA_WEXT (1 << 4) +#define WLAN_DA_TXRX (1 << 5) +#define WLAN_DA_PM (1 << 6) +#define WLAN_DA_ALL 0x0000007f + +#define WLAN_LOG "WLAN: " + +//#define DEBUG +//#define WLAN_RAW_DATA_DEBUG +#ifdef DEBUG +#define WLAN_DBGLA(area, lvl) \ + (((lvl) <= wlan_dbg_level) && ((area) & wlan_dbg_area)) +#define WLAN_DBGLAP(area,lvl, x...) \ + do{ \ + if (((lvl) <= wlan_dbg_level) && ((area) & wlan_dbg_area)) \ + printk(KERN_ERR WLAN_LOG x ); \ + }while(0) +#define WLAN_DBGP(x...) \ + do{ \ + printk(KERN_ERR WLAN_LOG x ); \ + }while(0) +#else +#define WLAN_DBGLA(area, lvl) 0 +#define WLAN_DBGLAP(area,lvl, x...) do {} while (0) +#define WLAN_DBGP(x...) do {} while (0) +#endif + +#define WLAN_ERRP(fmt, args...) \ + do{ \ + printk(KERN_ERR WLAN_LOG "%s: "fmt, __func__, ## args ); \ + }while(0) + +/** Log entry point for debugging */ +#define ENTER() WLAN_DBGLAP(WLAN_DA_MAIN, WLAN_DL_DEBUG, "Enter: %s :%i\n", __FUNCTION__, \ + __LINE__) +/** Log exit point for debugging */ +#define LEAVE() WLAN_DBGLAP(WLAN_DA_MAIN, WLAN_DL_DEBUG, "Leave: %s :%i\n", __FUNCTION__, \ + __LINE__) + +#define WLAN_STATUS_FAILED (-1) +#define WLAN_STATUS_SUCCESS (0) +#endif + + diff --git a/drivers/net/wireless/rda/rda_wlan/wlan_dev.h b/drivers/net/wireless/rda/rda_wlan/wlan_dev.h new file mode 100755 index 00000000..5af1985c --- /dev/null +++ b/drivers/net/wireless/rda/rda_wlan/wlan_dev.h @@ -0,0 +1,418 @@ +#ifndef __WLAN_DEV_H__ +#define __WLAN_DEV_H__ + +#ifndef MAX_WPA_IE_LEN +#define MAX_WPA_IE_LEN 100 +#endif + +#ifndef MAX_WPS_IE_LEN +#define MAX_WPS_IE_LEN (512) +#endif +#ifndef MAX_RATES +#define MAX_RATES 14 +#endif + +#define WLAN_MAX_NETWORK_NUM 64 + +#define KEY_LEN_WPA_AES 16 +#define KEY_LEN_WPA_TKIP 32 +#define KEY_LEN_WEP_104 13 +#define KEY_LEN_WEP_40 5 + +#define ASSOC_FLAG_SSID 1 +#define ASSOC_FLAG_CHANNEL 2 +#define ASSOC_FLAG_BAND 3 +#define ASSOC_FLAG_MODE 4 +#define ASSOC_FLAG_BSSID 5 +#define ASSOC_FLAG_WEP_KEYS 6 +#define ASSOC_FLAG_WEP_TX_KEYIDX 7 +#define ASSOC_FLAG_WPA_MCAST_KEY 8 +#define ASSOC_FLAG_WPA_UCAST_KEY 9 +#define ASSOC_FLAG_SECINFO 10 +#define ASSOC_FLAG_WPA_IE 11 +#define ASSOC_FLAG_ASSOC_RETRY 12 +#define ASSOC_FLAG_ASSOC_START 13 +#define ASSOC_FLAG_WLAN_CONNECTING 14 + +#define WLAN_NF_DEFAULT_SCAN_VALUE (-96) +#define PERFECT_RSSI ((u8)50) +#define WORST_RSSI ((u8)0) +#define RSSI_DIFF ((u8)(PERFECT_RSSI - WORST_RSSI)) + +#define WLAN_RTS_MIN_VALUE 0 +#define WLAN_RTS_MAX_VALUE 2347 +#define WLAN_FRAG_MIN_VALUE 256 +#define WLAN_FRAG_MAX_VALUE 2346 + + +#define WLAN_AUTH_OPEN 0 +#define WLAN_AUTH_SHARED_KEY 1 +#define WLAN_AUTH_FT 2 +#define WLAN_AUTH_LEAP 128 + +#define WLAN_AUTH_CHALLENGE_LEN 128 + +#define WLAN_CAPABILITY_ESS (1<<0) +#define WLAN_CAPABILITY_IBSS (1<<1) +#define WLAN_CAPABILITY_CF_POLLABLE (1<<2) +#define WLAN_CAPABILITY_CF_POLL_REQUEST (1<<3) +#define WLAN_CAPABILITY_PRIVACY (1<<4) +#define WLAN_CAPABILITY_SHORT_PREAMBLE (1<<5) +#define WLAN_CAPABILITY_PBCC (1<<6) +#define WLAN_CAPABILITY_CHANNEL_AGILITY (1<<7) +#define IW_AUTH_ALG_WAPI 0x08 +#define IW_ENCODE_ALG_WAPI 0x80 +#define IW_AUTH_WAPI_ENABLED 0x20 + +#define WAPI_KEY_MGMT_NONE 0 +#define WAPI_KEY_MGMT_CERT BIT2 +#define WAPI_KEY_MGMT_PSK BIT3 + +#define IW_ENCODE_ALG_SM4 0x20 + +enum WLAN_SCAN_STATUS{ + WLAN_SCAN_IDLE = 0, + WLAN_SCAN_RUNNING = 1, + WLAN_SCAN_COMPLET = 2 +}; + +enum WLAN_PACKET_TYPE{ + WLAN_CMD = 1, + WLAN_DATA = 2 +}; + +/** KEY_TYPE_ID */ +enum KEY_TYPE_ID { + KEY_TYPE_ID_WEP = 0, + KEY_TYPE_ID_TKIP, + KEY_TYPE_ID_AES +}; + +enum PACKET_TYPE{ + WID_REQUEST_PACKET, + WID_REQUEST_POLLING_PACKET, + DATA_REQUEST_PACKET +}; + +/** KEY_INFO_WPA (applies to both TKIP and AES/CCMP) */ +enum KEY_INFO_WPA { + KEY_INFO_WPA_MCAST = 0x01, + KEY_INFO_WPA_UNICAST = 0x02, + KEY_INFO_WPA_ENABLED = 0x04 +}; + +typedef struct _wlan_bss_descriptor { + u8 ssid[IW_ESSID_MAX_SIZE + 1]; + u8 bss_type; + u8 channel; + u8 dot11i_info; + u8 bssid[ETH_ALEN]; + u8 rssi; + u8 auth_info; + u8 rsn_cap[2]; +}wlan_bss_descriptor; + +/** + * @brief Structure used to store information for each beacon/probe response + */ +struct bss_descriptor { + u8 bssid[ETH_ALEN]; + u8 ssid[IW_ESSID_MAX_SIZE + 1]; + u8 ssid_len; + + u16 capability; + u32 rssi; + u32 channel; + u16 beaconperiod; + + /* IW_MODE_AUTO, IW_MODE_ADHOC, IW_MODE_INFRA */ + u8 mode; + + /* zero-terminated array of supported data rates */ + u8 rates[MAX_RATES + 1]; + u8* wpa_ie; + size_t wpa_ie_len; + u8* rsn_ie; + size_t rsn_ie_len; + + u8* wapi_ie; + size_t wapi_ie_len; //wapi valid payload length + + //huanglei add wps + u8 *wps_ie;//added in probe req + int wps_ie_len; + + unsigned long last_scanned; + struct list_head list; +}; + +struct wlan_802_11_security { + u8 WPAenabled; + u8 WPA2enabled; + u8 wep_enabled; + u8 auth_mode; + u32 key_mgmt; + u32 cipther_type; +}; + +typedef struct _wlan_rx_packet_node{ + struct list_head List; + struct sk_buff *Skb; +}wlan_rx_packet_node; + +typedef struct _wlan_wid_packet_node{ + struct list_head List; + wait_queue_head_t WidDone; + u8 WidWaitOption; + u16 WidCmd; + u8 WidMsgId; + u8 BufType;//use this to record the rsp type. in case we need use it to determine system big or little end + u32 BufLen; + u8 *Buf; + u32 RspLen; + u8 *RspBuf; +}wlan_wid_packet_node; + +typedef struct _wlan_tx_packet_node{ + struct list_head List; + struct sk_buff *Skb; + u8 type; + wlan_wid_packet_node * wid_node; +}wlan_tx_packet_node; + +/* Generic structure to hold all key types. */ +struct enc_key { + u16 len; + u16 flags; /* KEY_INFO_* from defs.h */ + u16 type; /* KEY_TYPE_* from defs.h */ + u8 key[32]; +}; + +typedef struct _wlan_private{ + struct mmc_card* MmcCard; + u8 CardRemoved; + int Open; + int version; +#ifdef WLAN_SDIO_RESET_DEBUG + int debug_count; +#endif + + u32 gpio_2_irq; + u32 external_irq; + + struct dentry *debugfs_dir; + struct dentry *debugfs_files[6]; + u8 wlan_pm_enable; + + struct net_device *netDev; + u8 netDevRegistered; + atomic_t netifQuStop; + struct mmc_card * mmcCard; + void *card; + u32 SdioErrorCount; + u8 sdio_need_reset; + u8 sdio_irq_enable; + u8 IgnoreFisrtDisconnect; + u8 Suspend; + atomic_t CardNeedSleep; + u8 CardInSleep; + WLAN_DRV_TIMER CardToSleepTimer; + + struct notifier_block pm_nb; + u8 CardInSuspend; + u8 earlysuspend_enabled; + + struct net_device_stats stats; + spinlock_t TxLock; + spinlock_t RxLock; + spinlock_t WidLock; + spinlock_t EventLock; + u8 CardSleepWakeLockOn; + struct wake_lock CardSleepTimerLock; + struct wake_lock MacStatusLock; + struct wake_lock ExtIrqTimerLock; + + struct list_head AverRssiQ; + u8 wid_msg_id; + + struct completion widComp; + /** Free command buffers */ + struct list_head WidFreeQ; + /** Pending command buffers */ + struct list_head WidPendingQ; + + /**rx packet queue*/ + u32 RxQuNum; + struct list_head RxQueue; + + /**tx packet queue*/ + atomic_t TxQuNum; + struct list_head TxQueue; + + /**tx packet queue*/ + u32 EventQuNum; + struct list_head EventQueue; + u32 EventErrorCount; + + /** thread to rx thread */ + wlan_thread RxThread; + + /** thread to event thread */ + wlan_thread EventThread; + + /** thread to tx thread */ + wlan_thread TxThread; + + struct iw_statistics wstats; + wlan_bss_descriptor curbssparams; + int connect_status; + int ToggalAssociation; + u8 reassoc_count; + u8 assoc_ongoing; + u8 assoc_bssid[6]; + u8 assoc_ssid[IW_ESSID_MAX_SIZE + 1]; + u8 assoc_ssid_len; + WLAN_DRV_TIMER StartAssociationTimeOut; + WLAN_DRV_TIMER AssociationTimeOut; + WLAN_DRV_TIMER ReAssociationTimeOut; + /** Encryption parameter */ + u8 imode; + u8 authtype; + struct wlan_802_11_security secinfo; + + /** WEP keys */ + struct enc_key wep_keys[4]; + u16 wep_tx_keyidx; + + /** WPA keys */ + struct enc_key wpa_mcast_key; + struct enc_key wpa_unicast_key; + + /** WPA Information Elements*/ + u8 wpa_ie[MAX_WPA_IE_LEN]; + u8 wpa_ie_len; + + u8 is_wapi; + u8 wps_ie[MAX_WPS_IE_LEN];//added in probe req + int wps_ie_len; + + /** Scan results list */ + int scan_running; + WLAN_DRV_TIMER ScanResultsTimeout; + spinlock_t ScanListLock; + struct list_head network_list; + struct list_head network_free_list; + struct bss_descriptor *networks; + int scan_ssid_len; + u8 scan_ssid[IW_ESSID_MAX_SIZE + 1]; +}wlan_private; + +typedef struct _wlan_sdio_card +{ + spinlock_t cardLock; + struct sdio_func * func; + wlan_private * priv; +}wlan_sdio_card; + +/*get mac from rda nvram*/ +struct wlan_mac_info { + u16 activated; + u8 mac_addr[ETH_ALEN]; +}; +static inline int is_same_network(struct bss_descriptor *src, + struct bss_descriptor *dst) +{ + /* A network is only a duplicate if the channel, BSSID, and ESSID + * all match. We treat all with the same BSSID and channel + * as one network */ + return ((src->channel == dst->channel) && + !compare_ether_addr(src->bssid, dst->bssid) && + !memcmp(src->ssid, dst->ssid, IW_ESSID_MAX_SIZE)); +} + +static inline unsigned char is_zero_eth_addr(unsigned char *addr) +{ + return !(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5]); +} + +static inline void clear_bss_descriptor(struct bss_descriptor *bss) +{ + /* Don't blow away ->list, just BSS data */ + if(bss->wpa_ie) + kfree(bss->wpa_ie); + + if(bss->rsn_ie) + kfree(bss->wapi_ie); + + if(bss->wapi_ie) + kfree(bss->wapi_ie); + + if(bss->wps_ie) + kfree(bss->wapi_ie); + + memset(bss, 0, offsetof(struct bss_descriptor, list)); +} + +static inline int is_ap_support_11b(u8* rates) +{ + int i = 0; + for(i = 0; i <= MAX_RATES; i ++){ + if(rates[i] == 0x96) + return TRUE; + } + return FALSE; +} + +static inline void skb_align(struct sk_buff *skb, int align) +{ + int off = ((unsigned long)skb->data) & (align - 1); + + if (off) + skb_reserve(skb, align - off); +} + +void if_sdio_interrupt(struct sdio_func *func); +struct bss_descriptor *get_bss_desc_from_scanlist( + wlan_private *priv, unsigned char *bssid); +void wlan_network_information(wlan_private *priv, + unsigned char *info, unsigned short info_len); +void wlan_assocication(wlan_private* priv); +void wlan_re_assocication(wlan_private* priv); +void wlan_assocication_timeout(wlan_private* priv); +int wlan_card_control_init(wlan_private *priv); +void wlan_report_scan_result(wlan_private * priv); +int wlan_read_mac_from_file(char* buf); +int wlan_write_mac_to_file(char * buf); +int wlan_read_mac_from_nvram(char *buf); +int wlan_write_mac_to_nvram(const char *buf); +void wlan_indicate_disconnected(wlan_private *priv); +void wlan_set_scan_by_driver(wlan_private *priv); +//wlan_init +unsigned int wlan_extern_irq_handle(int irq, void *para); +int wlan_register_host_wake_irq(wlan_private* priv); +void wlan_unregister_host_wake_irq(wlan_private* priv); + +int wlan_init(wlan_private* priv); +int wlan_add_card(wlan_sdio_card * card); +int wlan_start_card(wlan_sdio_card * card); +int wlan_reset_card(wlan_private *priv); +void wlan_release_dev(wlan_sdio_card * card); +void wlan_remove_tx_data_queue(wlan_private * priv); +void wlan_remove_rx_queue(wlan_private * priv); +void wlan_remove_event_queue(wlan_private * priv); +void wlan_unit(wlan_private * priv); +//wlan_rxtx +void wlan_process_event(wlan_private * priv); +void wlan_process_rx(wlan_private *priv); +int wlan_tx_thread(void *data); +int wlan_rx_thread(void *data); + +//extern void rda_mmc_set_sdio_irq(u32 host_id, u8 enable); +extern struct iw_handler_def wlan_wext_handler_def; +extern unsigned char rda_combo_wifi_in_test_mode(void); +void wlan_debugfs_init(void); +void wlan_debugfs_remove(void); +void wlan_debugfs_init_all(wlan_private *priv); +void wlan_debugfs_remove_all(wlan_private *priv); +#endif + diff --git a/drivers/net/wireless/rda/rda_wlan/wlan_event.c b/drivers/net/wireless/rda/rda_wlan/wlan_event.c new file mode 100755 index 00000000..2bda586b --- /dev/null +++ b/drivers/net/wireless/rda/rda_wlan/wlan_event.c @@ -0,0 +1,227 @@ +#include "wlan_includes.h" + +void wlan_push_event(wlan_private * priv, wlan_event_type type, void* para, u8 front) +{ + wlan_event *event = NULL; + ENTER(); + + event = kzalloc(sizeof(wlan_event), GFP_KERNEL); + if (event) + event->EventType = type; + else { + WLAN_ERRP("kzalloc wlan_event memory failed\n"); + return; + } + + event->Para = para; + + spin_lock(&priv->EventLock); + if(front) + list_add(&event->list, &priv->EventQueue); + else + list_add_tail(&event->list, &priv->EventQueue); + priv->EventQuNum ++; + spin_unlock(&priv->EventLock); + + complete(&priv->EventThread.comp); + + LEAVE(); +} + +wlan_event* wlan_pull_event(wlan_private * priv) +{ + wlan_event* event; + + ENTER(); + spin_lock(&priv->EventLock); + if (list_empty(&priv->EventQueue)) { + spin_unlock(&priv->EventLock); + return NULL; + } + event = (wlan_event*)priv->EventQueue.next; + list_del(&event->list); + priv->EventQuNum --; + spin_unlock(&priv->EventLock); + LEAVE(); + return event; +} + +void wlan_timer_handler(unsigned long fcontext) +{ + PWLAN_DRV_TIMER timer = (PWLAN_DRV_TIMER) fcontext; + + if(timer->timer_function) + timer->timer_function(timer->function_context); + else { + wlan_push_event((wlan_private *) timer->function_context, timer->EventType, timer->function_context, TRUE); + } + + if (timer->timer_is_periodic == TRUE) { + mod_timer(&timer->tl, jiffies + ((timer->time_period * HZ) / 1000)); + } else + timer->timer_is_canceled = TRUE; +} + + +void wlan_mac_status(wlan_private *priv, + char *wid_status, unsigned short wid_status_len) +{ + char mac_status; + + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_DEBUG, "%s >>>\n", __func__); + +#ifdef WLAN_FORCE_SUSPEND_SUPPORT + if (priv->CardInSuspend == TRUE) { + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_TRACE, "%s ingnored in ap deep sleep mode.\n", __func__); + return; + } +#endif + mac_status = wid_status[7]; + + if (mac_status == MAC_CONNECTED) { + + + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_CRIT, "MAC CONNECTED\n"); + + priv->connect_status = MAC_CONNECTED; + netif_carrier_on(priv->netDev); + netif_wake_queue(priv->netDev); + + wlan_cancel_timer(&priv->ReAssociationTimeOut); + //report connect to supper layer + wlan_indicate_connected(priv); + { + wlan_push_event(priv, WLAN_EVENT_SET_PHY_ERR_INT, priv, FALSE); + } + wake_lock_timeout(&priv->MacStatusLock, 6 * HZ); + } else if (mac_status == MAC_DISCONNECTED) { + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_CRIT, "MAC_DISCONNECTED\n"); + + wlan_cancel_timer(&priv->ReAssociationTimeOut); + //for wep we should toggler from open to shared if auth failed + if(priv->ToggalAssociation){ + wlan_re_assocication(priv); + }else{ + wlan_cancel_timer(&priv->AssociationTimeOut); + + priv->connect_status = MAC_DISCONNECTED; + priv->assoc_ongoing = FALSE; + netif_stop_queue(priv->netDev); + netif_carrier_off(priv->netDev); + + //report disconnect to supper layer + if(!priv->IgnoreFisrtDisconnect){ + wlan_indicate_disconnected(priv); + + wake_lock_timeout(&priv->MacStatusLock, 6*HZ); + }else{ + priv->IgnoreFisrtDisconnect = FALSE; + } + } + } else { + WLAN_ERRP("Invalid MAC Status 0x%02x\n", mac_status); + } + + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_DEBUG, "%s <<<\n", __func__); +} + +void wlan_start_netif(wlan_private* priv) +{ + netif_wake_queue(priv->netDev); +} +void wlan_process_event(wlan_private * priv) +{ + int ret=0; + wlan_event *event = NULL; + + event = wlan_pull_event(priv); + if (!event) + return; + + WLAN_DBGLAP(WLAN_DA_MAIN, WLAN_DL_TRACE, "type :%d \n", event->EventType); + + switch(event->EventType){ + case WLAN_EVENT_SCAN_RESULT_TIMEOUT: + wlan_report_scan_result(priv); + break; + + case WLAN_EVENT_START_ASSOC: + wlan_assocication(priv); + break; + + case WLAN_EVENT_ASSOC_TIMEOUT: + wlan_assocication_timeout(priv); + break; + + case WLAN_EVENT_REASSOC_TIMEOUT: + wlan_re_assocication(priv); + break; + + case WLAN_EVENT_CARD_TO_SLEEP: + handle_card_to_sleep_cmd(priv); + break; + + case WLAN_EVENT_CARD_CONTROL_INIT: + ret=wlan_card_control_init(priv); + if (ret) { + WLAN_ERRP("Wlan Card Control Init Failed! \n"); + } else { + WLAN_DBGLAP(WLAN_DA_MAIN, WLAN_DL_CRIT, "Wlan Card Control Init Success, Chip Version:%d \n", priv->version); + } + + break; + case WLAN_EVENT_CHECK_SDIO: + wlan_card_check_sdio(priv); + break; + + case WLAN_EVENT_START_NETIF: + wlan_start_netif(priv); + break; + + case WLAN_EVENT_SET_PHY_ERR_INT: + wlan_set_phy_timeout(priv); + break; + + case WLAN_EVENT_START_SCAN: + wlan_set_scan_by_driver(priv); + break; + default: + break; + } + + kfree(event); +} + + +int wlan_event_thread(void *data) +{ + wlan_thread *thread = (wlan_thread *)data; + wlan_private *priv = thread->priv; + + ENTER(); + + wlan_activate_thread(thread); + + current->flags |= PF_NOFREEZE; + + while(1){ + + wait_for_completion_interruptible(&thread->comp); + + if (kthread_should_stop()){ + WLAN_DBGLAP(WLAN_DA_MAIN, WLAN_DL_CRIT,"wlan_event_thread: break from main thread \n"); + break; + } + + if(priv->CardRemoved){ + break; + } + + wlan_process_event(priv); + } + wlan_deactivate_thread(thread); + + LEAVE(); + return 0; +} + diff --git a/drivers/net/wireless/rda/rda_wlan/wlan_event.h b/drivers/net/wireless/rda/rda_wlan/wlan_event.h new file mode 100755 index 00000000..65af5908 --- /dev/null +++ b/drivers/net/wireless/rda/rda_wlan/wlan_event.h @@ -0,0 +1,33 @@ +#ifndef __WLAN_EVENT_H__ +#define __WLAN_EVENT_H__ + +typedef enum _wlan_event_type +{ + WLAN_EVENT_SCAN_RESULT_TIMEOUT = 0, + WLAN_EVENT_START_ASSOC = 1, + WLAN_EVENT_ASSOC_TIMEOUT = 2, + WLAN_EVENT_REASSOC_TIMEOUT = 3, + WLAN_EVENT_CARD_TO_SLEEP = 4, + WLAN_EVENT_CARD_CONTROL_INIT = 5, + WLAN_EVENT_CHECK_SDIO = 6, + WLAN_EVENT_START_NETIF = 7, + WLAN_EVENT_SET_PHY_ERR_INT = 8, + WLAN_EVENT_START_SCAN = 9, +}wlan_event_type; + +typedef struct _wlan_event +{ + struct list_head list; + wlan_event_type EventType; + void * Para; +}wlan_event; + +void wlan_push_event(wlan_private * priv, wlan_event_type type, void* para, u8 front); +wlan_event* wlan_pull_event(wlan_private *priv); +void wlan_mac_status(wlan_private *priv, + char *wid_status, unsigned short wid_status_len); +int wlan_event_thread(void *data); +void wlan_timer_handler(unsigned long fcontext); +void wlan_indicate_connected(wlan_private *priv); +void wlan_indicate_disconnected(wlan_private *priv); +#endif diff --git a/drivers/net/wireless/rda/rda_wlan/wlan_includes.h b/drivers/net/wireless/rda/rda_wlan/wlan_includes.h new file mode 100755 index 00000000..54c246c8 --- /dev/null +++ b/drivers/net/wireless/rda/rda_wlan/wlan_includes.h @@ -0,0 +1,115 @@ +/** @file wlan_headers.h + * + * @brief This file contains all the necessary include file. + * + * Copyright (C) 2003-2008, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available along with the File in the gpl.txt file or by writing to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ +/******************************************************** +Change log: + 05/30/07: Initial creation +********************************************************/ + +#ifndef _WLAN_HEADERS_H +#define _WLAN_HEADERS_H + +#ifndef __ATTRIB_ALIGN__ +#define __ATTRIB_ALIGN__ __attribute__((aligned(4))) +#endif + +#ifndef __ATTRIB_PACK__ +#define __ATTRIB_PACK__ __attribute__ ((packed)) +#endif + +/* Linux header files */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) +#include +#endif + +#include + +/* ASM files */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) +#include +#else +#include +#endif +#include +#include +#include +#include +#include + +/* Net header files */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Wireless header */ +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +/*drv header*/ +#include "wlan_defs.h" +#include "wlan_os.h" +#include "wlan_dev.h" +#include "wlan_event.h" +#include "wlan_wid.h" +#include "wlan_sdio.h" +#include "wlan_sdio_patch.h" +#include "wlan_aver_rssi.h" +#endif /* _WLAN_HEADERS_H */ + diff --git a/drivers/net/wireless/rda/rda_wlan/wlan_init.c b/drivers/net/wireless/rda/rda_wlan/wlan_init.c new file mode 100755 index 00000000..5e978502 --- /dev/null +++ b/drivers/net/wireless/rda/rda_wlan/wlan_init.c @@ -0,0 +1,736 @@ +#include "wlan_includes.h" +#include +#include +#include +#include +//#include +extern void rda_mci_enable_sdio_irq(struct mmc_host *mmc, int enable); + +int wlan_register_host_wake_irq(wlan_private* priv) +{ + int ret = 0; +#ifdef ALL_WINNER + script_item_u val; + script_item_value_type_e type; + + type = script_get_item("wifi_para", "rda5990_wl_host_wake", &val); + if (SCIRPT_ITEM_VALUE_TYPE_PIO != type){ + printk("get RDA rda5990_wl_host_wake gpio failed\n"); + priv->gpio_2_irq = 0; + } + else + priv->gpio_2_irq = val.gpio.gpio; +#endif + printk("\n\n\n\n\n\n\n%s %d return\n\n\n\n\n\n\n\n\n",__func__,__LINE__); + return 0; + + + if(priv->external_irq) + wlan_unregister_host_wake_irq(priv); + + priv->external_irq = gpio_to_irq(priv->gpio_2_irq); + if (IS_ERR_VALUE(priv->external_irq)) { + printk("map gpio [%d] to virq failed, errno = %d\n", + priv->gpio_2_irq, priv->external_irq); + return -1; + } + ret= devm_request_irq(&priv->MmcCard->dev, priv->external_irq, wlan_extern_irq_handle, + IRQF_TRIGGER_LOW, "rda_combo_wifi", priv); + if (IS_ERR_VALUE(ret)) { + printk("request virq %d failed, errno = %d\n", + priv->external_irq, ret); + return -1; + } + return 0; +} + +void wlan_unregister_host_wake_irq(wlan_private* priv) +{ + if(!priv || !priv->MmcCard) + return; + + if(priv->external_irq) + devm_free_irq(&priv->MmcCard->dev, priv->external_irq, priv); + + priv->external_irq = 0; + +} + +int wlan_init(wlan_private* priv) +{ + int ret, i, bufsize; + wlan_sdio_card* card = (wlan_sdio_card*)priv->card; + + spin_lock_init(&priv->WidLock); + spin_lock_init(&priv->RxLock); + spin_lock_init(&priv->TxLock); + spin_lock_init(&priv->EventLock); + spin_lock_init(&priv->ScanListLock); + spin_lock_init(&card->cardLock); + + INIT_LIST_HEAD(&priv->AverRssiQ); + INIT_LIST_HEAD(&priv->WidFreeQ); + INIT_LIST_HEAD(&priv->WidPendingQ); + INIT_LIST_HEAD(&priv->RxQueue); + INIT_LIST_HEAD(&priv->TxQueue); + INIT_LIST_HEAD(&priv->EventQueue); + + /* Initialize scan result lists */ + INIT_LIST_HEAD(&priv->network_free_list); + INIT_LIST_HEAD(&priv->network_list); + /* Allocate buffer to store the BSSID list */ + bufsize = WLAN_MAX_NETWORK_NUM * (sizeof(struct bss_descriptor) + 4); + priv->networks = kzalloc(bufsize, GFP_KERNEL); + if (priv->networks == NULL) { + WLAN_ERRP("kzalloc bss_descriptor memory failed!\n"); + return WLAN_STATUS_FAILED; + } + for (i = 0; i < WLAN_MAX_NETWORK_NUM; i++){ + list_add_tail(&priv->networks[i].list, &priv->network_list); + } + + priv->netDevRegistered = FALSE; + atomic_set(&(priv->TxQuNum), 0); + priv->RxQuNum = 0; + atomic_set(&(priv->netifQuStop), 0); + priv->reassoc_count = 0; + priv->CardRemoved = FALSE; + priv->IgnoreFisrtDisconnect = FALSE; + priv->assoc_ongoing = FALSE; + priv->scan_running = WLAN_SCAN_IDLE; + priv->SdioErrorCount =0; + priv->sdio_irq_enable = FALSE; + priv->CardInSleep = FALSE; + priv->CardSleepWakeLockOn = FALSE; + priv->CardInSuspend = FALSE; + priv->earlysuspend_enabled=0; + priv->sdio_need_reset = 0; +#ifdef WLAN_SDIO_RESET_DEBUG + priv->debug_count = 0; +#endif + priv->EventErrorCount=0; + + ret = wlan_alloc_wid_queue(priv); + if(ret) + return WLAN_STATUS_FAILED; + + wlan_initialize_timer(&priv->StartAssociationTimeOut, NULL, priv, WLAN_EVENT_START_ASSOC); + wlan_initialize_timer(&priv->ScanResultsTimeout, NULL, priv, WLAN_EVENT_SCAN_RESULT_TIMEOUT); + wlan_initialize_timer(&priv->AssociationTimeOut, NULL, priv, WLAN_EVENT_ASSOC_TIMEOUT); + wlan_initialize_timer(&priv->ReAssociationTimeOut, NULL, priv, WLAN_EVENT_REASSOC_TIMEOUT); + wlan_initialize_timer(&priv->CardToSleepTimer, NULL, priv, WLAN_EVENT_CARD_TO_SLEEP); + + wake_lock_init(&priv->CardSleepTimerLock, WAKE_LOCK_SUSPEND, "CardSleepTimerLock"); + wake_lock_init(&priv->MacStatusLock, WAKE_LOCK_SUSPEND, "MacStatusLock"); + wake_lock_init(&priv->ExtIrqTimerLock, WAKE_LOCK_SUSPEND, "ExtIrqTimerLock"); + + return WLAN_STATUS_SUCCESS; +} + +int wlan_add_card(wlan_sdio_card * card) +{ + struct net_device *dev = NULL; + wlan_private *priv = NULL; + int ret = -1; + + /* Allocate an Ethernet device and register it */ + dev = alloc_netdev_mq(sizeof(wlan_private), "wlan%d", ether_setup, 1); + ENTER(); + + if(!dev) + return ret; + + priv = netdev_priv(dev); + card->priv = priv; + priv->card = card; + priv->netDev = dev; + + dev->hard_header_len += WID_HEADER_LEN; + dev->watchdog_timeo = DEFAULT_WATCHDOG_TIMEOUT; + dev->trans_start = jiffies; + +#ifdef WIRELESS_EXT + dev->wireless_handlers = (struct iw_handler_def *)&wlan_wext_handler_def; +#endif + dev->flags |= IFF_BROADCAST | IFF_MULTICAST; + + + wlan_init(priv); + + priv->RxThread.priv = priv; + wlan_create_thread(wlan_rx_thread, + &priv->RxThread, "wlan_rx_thread"); + + priv->EventThread.priv = priv; + wlan_create_thread(wlan_event_thread, + &priv->EventThread, "EventThread"); + + priv->TxThread.priv = priv; + wlan_create_thread(wlan_tx_thread, + &priv->TxThread, "wlan_tx_thread"); + + while(priv->RxThread.pid == 0 || + priv->EventThread.pid == 0 || + priv->TxThread.pid == 0) + schedule(); + + return 0; +} + +void wlan_release_dev(wlan_sdio_card * card) +{ + wlan_private * priv = (wlan_private*) card->priv; + + ENTER(); + if(!priv) + return; + + netif_stop_queue(priv->netDev); + netif_carrier_off(priv->netDev); + + //first remove event queue , we shold keep this befrore set CardRmoved + //because the event has para should be free in it event handler. + wlan_remove_event_queue(priv); + + //release wid pending queue + wlan_release_wid_pending_queue(priv); + + if(!(priv->CardToSleepTimer).timer_is_canceled) + wlan_cancel_timer(&priv->CardToSleepTimer); + wlan_cancel_timer(&priv->StartAssociationTimeOut); + wlan_cancel_timer(&priv->AssociationTimeOut); + wlan_cancel_timer(&priv->ReAssociationTimeOut); + wlan_cancel_timer(&priv->ScanResultsTimeout); + + if(priv->netDev && priv->netDevRegistered) + unregister_netdev(priv->netDev); + + priv->CardRemoved = 1; + //waiting rx thread terminate + while(priv->RxThread.pid){ + complete(&priv->RxThread.comp); + wlan_sched_timeout(2); + } + //waiting event thread timeout + while(priv->EventThread.pid){ + complete(&priv->EventThread.comp); + wlan_sched_timeout(2); + } + + //waiting tx thread timeout + while(priv->TxThread.pid){ + complete(&priv->TxThread.comp); + wlan_sched_timeout(2); + } + + wlan_unit(priv); + + if(priv->netDev) + free_netdev(priv->netDev); +#ifdef WLAN_FORCE_SUSPEND_SUPPORT + unregister_pm_notifier(&priv->pm_nb); +#endif + + LEAVE(); +} + +void wlan_remove_tx_data_queue(wlan_private * priv) +{ + struct list_head *qe = NULL, *qen = NULL; + wlan_tx_packet_node *txNode = NULL; + ENTER(); + spin_lock(&priv->TxLock); + if(!list_empty(&priv->TxQueue)){ + list_for_each_safe(qe, qen, &priv->TxQueue){ + txNode= (wlan_tx_packet_node*)qe; + if(txNode->Skb && (txNode->type == WLAN_DATA)) + dev_kfree_skb(txNode->Skb); + + list_del(&txNode->List); + kfree(txNode); + } + } + spin_unlock(&priv->TxLock); + LEAVE(); +} + +void wlan_remove_rx_queue(wlan_private * priv) +{ + struct list_head *qe = NULL, *qen = NULL; + wlan_rx_packet_node* rxNode = NULL; + + ENTER(); + spin_lock(&priv->RxLock); + if(!list_empty(&priv->RxQueue)){ + list_for_each_safe(qe, qen, &priv->RxQueue){ + rxNode= (wlan_rx_packet_node*)qe; + + if(rxNode->Skb) + dev_kfree_skb(rxNode->Skb); + + list_del(&rxNode->List); + kfree(rxNode); + } + } + spin_unlock(&priv->RxLock); + LEAVE(); +} + +void wlan_remove_event_queue(wlan_private * priv) +{ + while(1){ + if(!list_empty(&priv->EventQueue)){ + complete(&priv->EventThread.comp); + }else + break; + wlan_sched_timeout(2); + } +} + +void wlan_unit(wlan_private * priv) +{ + struct bss_descriptor *iter_bss; + wlan_free_wid_queue(priv); + wlan_remove_tx_data_queue(priv); + wlan_remove_rx_queue(priv); + + if(priv->networks){ + list_for_each_entry(iter_bss, &priv->network_list, list) { + clear_bss_descriptor(iter_bss); + } + kfree(priv->networks); + } + + priv->networks = NULL; + + wlan_free_aver_rssi(priv); + + wake_lock_destroy(&priv->CardSleepTimerLock); + wake_lock_destroy(&priv->MacStatusLock); + wake_lock_destroy(&priv->ExtIrqTimerLock); +} + +int wlan_sleep_flags = RDA_SLEEP_ENABLE | RDA_SLEEP_PREASSO; +int wlan_init_pm(wlan_private *priv) +{ + int ret = 0; +#ifdef WLAN_POWER_MANAGER + wlan_sdio_card *card = (wlan_sdio_card *)priv->card; +#endif + + if(rda_combo_wifi_in_test_mode()) + return 0; + +#ifdef WLAN_POWER_MANAGER + if (wlan_sleep_flags & RDA_SLEEP_ENABLE){ + ret = wlan_set_pm_mode(priv, 2); + if(ret < 0) + goto err; + } + if (wlan_sleep_flags & RDA_SLEEP_PREASSO){ + ret = wlan_set_preasso_sleep(priv, WIFI_PREASSO_SLEEP); + if(ret < 0) + goto err; + } + + sdio_claim_host(card->func); + ret = wlan_write_byte(priv, IF_SDIO_FUN1_INT_TO_DEV, 1); + if (ret) { + WLAN_ERRP("write FUN1_INT_TO_DEV reg fail\n"); + } + sdio_release_host(card->func); + priv->wlan_pm_enable = 1; +err: + return ret; +#else + return ret; +#endif +} + +int wlan_disable_self_cts(wlan_private *priv) +{ + int ret = 0; + + ENTER(); + ret = wlan_generic_set_uchar(priv, WID_PTA_MODE, 0); + + if(ret < 0){ + WLAN_ERRP("failed \n"); + goto err; + } + + return 0; + +err: + return ret; +} + +int wlan_disable_block_bt(wlan_private *priv) +{ + int ret = 0; + + ENTER(); + + ret = wlan_generic_set_uchar(priv, WID_PTA_BLOCK_BT, 0); + if(ret < 0){ + WLAN_ERRP("failed \n"); + goto err; + } + + return 0; + +err: + return ret; +} + +int wlan_card_control_init(wlan_private *priv) +{ + int ret = -1; + + ENTER(); + if(!rda_combo_wifi_in_test_mode()){ + ret=wlan_sdio_init(priv); + if(ret<0){ + WLAN_ERRP("wlan_sdio_init failed! \n"); + goto err; + } + + ret = wlan_start_card((wlan_sdio_card *)priv->card); + if(ret<0){ + WLAN_ERRP("wlan_start_card failed! \n"); + goto err; + } + + ret = wlan_disable_self_cts(priv); + if(ret){ + WLAN_ERRP("wlan_disable_self_cts failed! \n"); + goto err; + } + + ret = wlan_disable_block_bt(priv); + if(ret){ + WLAN_ERRP("wlan_disable_block_bt failed! \n"); + goto err; + } + + ret = wlan_set_scan_timeout(priv); + if (ret) { + WLAN_ERRP("wlan_set_scan_timeout failed! \n"); + goto err; + } + + ret= wlan_set_listen_interval(priv, WIFI_LISTEN_INTERVAL); + if(ret){ + WLAN_ERRP("wlan_set_listen_interval failed! \n"); + goto err; + } + + if (priv->version == WLAN_VERSION_90_D || priv->version == WLAN_VERSION_90_E){ + ret = wlan_set_link_loss_threshold(priv, WIFI_LINK_LOSS_THRESHOLD_90); + if(ret){ + WLAN_ERRP("wlan_set_link_loss_threshold failed! \n"); + goto err; + } + }else if(priv->version == WLAN_VERSION_91){ + ret = wlan_set_link_loss_threshold(priv, WIFI_LINK_LOSS_THRESHOLD_91); + if(ret){ + WLAN_ERRP("wlan_set_link_loss_threshold failed! \n"); + goto err; + } + ret = wlan_set_power_save(priv); + if(ret){ + WLAN_ERRP("wlan_set_power_save failed! \n"); + goto err; + } + }else if(priv->version == WLAN_VERSION_91_E){ + ret = wlan_set_link_loss_threshold(priv, WIFI_LINK_LOSS_THRESHOLD_91); + if(ret){ + WLAN_ERRP("wlan_set_link_loss_threshold failed! \n"); + goto err; + } + ret = wlan_set_power_save(priv); + if(ret){ + WLAN_ERRP("wlan_set_power_save failed! \n"); + goto err; + } + + }else if(priv->version == WLAN_VERSION_91_F){ + ret = wlan_set_link_loss_threshold(priv, WIFI_LINK_LOSS_THRESHOLD_91); + if(ret){ + WLAN_ERRP("wlan_set_link_loss_threshold failed! \n"); + goto err; + } + ret = wlan_set_power_save(priv); + if(ret){ + WLAN_ERRP("wlan_set_power_save failed! \n"); + goto err; + } + } + + // ret = wlan_generic_set_ushort(priv, WID_JOIN_TIMEOUT, 3000); + // if(ret) + // goto err; + + ret = wlan_init_pm(priv); + if(ret){ + WLAN_ERRP("wlan_init_pm failed! \n"); + goto err; + } + }else{ + ret = wlan_set_test_mode(priv); + + if (register_netdev(priv->netDev)) { + WLAN_ERRP("register_netdev failed\n"); + priv->netDevRegistered = FALSE; + goto err; + }else + priv->netDevRegistered = TRUE; + + wlan_indicate_disconnected(priv); + } + + return 0; /*success*/ +err: + LEAVE(); + return -1; /*fail*/ +} + + +int wlan_start_card(wlan_sdio_card * card) +{ + u8 mac_addr[ETH_ALEN]; + int ret = 0; + + wlan_private * priv = (wlan_private*) card->priv; + + if(!priv) + return -1; + + ENTER(); + +#ifdef USE_MAC_DYNAMIC_ONCE + if(wlan_read_mac_from_file(mac_addr) != ETH_ALEN){ +#ifdef USE_MAC_FROM_RDA_NVRAM + ret = wlan_read_mac_from_nvram(mac_addr); + if (ret) { + WLAN_ERRP("nvram:get wifi mac addr form nvram failed, make a random mac addr instead\n"); + random_ether_addr(mac_addr); + wlan_write_mac_to_nvram(mac_addr); + } else { + if (!is_valid_ether_addr(mac_addr)) { + mac_addr[0] &= 0xfe; /* clear multicast bit */ + mac_addr[0] |= 0x02; /* set local assignment bit (IEEE802) */ + } + } +#else + random_ether_addr(mac_addr); +#endif /*USE_MAC_FROM_RDA_NVRAM*/ + ret = wlan_write_mac_to_file(mac_addr); + } + +#else + mac_addr[0] = 0x00; + mac_addr[1] = 0xc0; + mac_addr[2] = 0x52; + + mac_addr[3] = 0x00; + mac_addr[4] = 0xc0; + mac_addr[5] = 0x53; +#endif + + ret = wlan_set_mac_addr(priv, mac_addr); + if (ret){ + goto done; + } + + ret = wlan_get_mac_addr(priv, mac_addr); + if (ret) { + goto done; + } + memcpy(priv->netDev->dev_addr, mac_addr, ETH_ALEN); + + rda5890_set_preamble(priv, G_AUTO_PREAMBLE); + + if (register_netdev(priv->netDev)) { + WLAN_ERRP("register_netdev failed\n"); + ret = -1; + priv->netDevRegistered = FALSE; + goto done; + }else + priv->netDevRegistered = TRUE; + + wlan_indicate_disconnected(priv); + +done: + LEAVE(); + + return ret; +} + +extern int rda_wifi_power_off(void); +extern int rda_wifi_power_on(void); +extern int sdio_reset_comm(struct mmc_card *card); +extern void rda_mmc_reset_host(u32 host_id); + +int wlan_reset_card(wlan_private *priv) +{ + int ret = 0; + wlan_sdio_card * card = NULL; + struct mmc_host * host = NULL; + card = (wlan_sdio_card *) priv->card; + host = priv->mmcCard->host; + ENTER(); + wlan_cancel_timer(&priv->CardToSleepTimer); + wlan_remove_tx_data_queue(priv); + wlan_release_wid_pending_queue(priv); + sdio_claim_host(card->func); + ret = sdio_release_irq(card->func); + if(ret){ + WLAN_ERRP("reset_card sdio_release_irq fail, ret = %d\n", ret); + } + sdio_release_host(card->func); + ret = rda_wifi_power_off(); + if(ret) + WLAN_ERRP("reset card power off sdio failed \n"); + + ret = rda_wifi_power_on(); + if(ret){ + WLAN_ERRP("reset card power off sdio failed \n"); + //kevin add, otherwise ,call sdio_reset_comm will cause kernel crash + goto err; + } + + //mmc_power_restore_host(host); +rda_mci_enable_sdio_irq(priv->MmcCard->host, 0); + + //rda_mmc_set_sdio_irq(1, false); + printk("\n\n\n\n\n\n\nkevin delete %s %d\n\n\n\n\n\n\n",__func__,__LINE__); + priv->sdio_irq_enable = FALSE; + priv->wlan_pm_enable = 0; + + sdio_reset_comm(priv->mmcCard); + + sdio_claim_host(card->func); + ret = sdio_enable_func(card->func); + if (ret){ + WLAN_ERRP("reset_card sdio_enable_func fail, ret = %d\n", ret); + sdio_release_host(card->func); + goto err; + } + + ret = sdio_claim_irq(card->func, if_sdio_interrupt); + if (ret){ + WLAN_ERRP("reset_card sdio_claim_irq fail, ret = %d\n", ret); + sdio_release_host(card->func); + goto err; + } + + //enable interrupt + if(wlan_write_byte(priv, IF_SDIO_FUN1_INT_MASK, 0x07)){ + WLAN_ERRP("err_enable_int \n"); + sdio_release_host(card->func); + goto err; + } + + //re-set sdio block size + sdio_set_block_size(card->func, 512); + sdio_release_host(card->func); + + ret = wlan_sdio_init(priv); + if(ret < 0){ + WLAN_ERRP("wlan_sdio_init failed! \n"); + goto err; + } + + priv->sdio_need_reset = 2; + + ret = wlan_set_mac_addr(priv, priv->netDev->dev_addr); + if (ret){ + goto err; + } + + ret = rda5890_set_preamble(priv, G_AUTO_PREAMBLE); + if (ret){ + goto err; + } + + ret = wlan_disable_self_cts(priv); + if(ret){ + WLAN_ERRP("wlan_disable_self_cts failed! \n"); + goto err; + } + + ret = wlan_disable_block_bt(priv); + if(ret){ + WLAN_ERRP("wlan_disable_block_bt failed! \n"); + goto err; + } + + ret = wlan_set_scan_timeout(priv); + if (ret) { + WLAN_ERRP("wlan_set_scan_timeout failed! \n"); + goto err; + } + + ret= wlan_set_listen_interval(priv, WIFI_LISTEN_INTERVAL); + if(ret){ + WLAN_ERRP("wlan_set_listen_interval failed! \n"); + goto err; + } + + if (priv->version == WLAN_VERSION_90_D || priv->version == WLAN_VERSION_90_E){ + ret = wlan_set_link_loss_threshold(priv, WIFI_LINK_LOSS_THRESHOLD_90); + if(ret){ + WLAN_ERRP("wlan_set_link_loss_threshold failed! \n"); + goto err; + } + }else if(priv->version == WLAN_VERSION_91){ + ret = wlan_set_link_loss_threshold(priv, WIFI_LINK_LOSS_THRESHOLD_91); + if(ret){ + WLAN_ERRP("wlan_set_link_loss_threshold failed! \n"); + goto err; + } + ret = wlan_set_power_save(priv); + if(ret){ + WLAN_ERRP("wlan_set_power_save failed! \n"); + goto err; + } + }else if(priv->version == WLAN_VERSION_91_E){ + ret = wlan_set_link_loss_threshold(priv, WIFI_LINK_LOSS_THRESHOLD_91); + if(ret){ + WLAN_ERRP("wlan_set_link_loss_threshold failed! \n"); + goto err; + } + ret = wlan_set_power_save(priv); + if(ret){ + WLAN_ERRP("wlan_set_power_save failed! \n"); + goto err; + } + + }else if(priv->version == WLAN_VERSION_91_F){ + ret = wlan_set_link_loss_threshold(priv, WIFI_LINK_LOSS_THRESHOLD_91); + if(ret){ + WLAN_ERRP("wlan_set_link_loss_threshold failed! \n"); + goto err; + } + ret = wlan_set_power_save(priv); + if(ret){ + WLAN_ERRP("wlan_set_power_save failed! \n"); + goto err; + } + } + + ret = wlan_init_pm(priv); + if(ret){ + WLAN_ERRP("wlan_init_pm failed! \n"); + goto err; + } + + //send a scan event after reset + wlan_push_event(priv, WLAN_EVENT_START_SCAN, priv, FALSE); + + return 0; +err: + LEAVE(); + return -1; /*fail*/ +} diff --git a/drivers/net/wireless/rda/rda_wlan/wlan_module.c b/drivers/net/wireless/rda/rda_wlan/wlan_module.c new file mode 100755 index 00000000..7857564b --- /dev/null +++ b/drivers/net/wireless/rda/rda_wlan/wlan_module.c @@ -0,0 +1,992 @@ +#include "wlan_includes.h" +#include +//#include +#include +/// +#include +#include +#include +/// +#include +#include +#include +#include +#if 1 +#define SDIO_VENDOR_ID_RDA 0x5449 +#define SDIO_DEVICE_ID_RDA 0x0145 + + +int wmt_mtk6620_intr=0xf; //gpio 15 + +extern void rda_mci_enable_sdio_irq(struct mmc_host *mmc, int enable); +int wlan_dbg_level = WLAN_DL_DEBUG; + +int wlan_dbg_area = WLAN_DA_MAIN + | WLAN_DA_SDIO + | WLAN_DA_ETHER + | WLAN_DA_WID + | WLAN_DA_WEXT + | WLAN_DA_TXRX + | WLAN_DA_PM + ; +/* Module parameters */ +//module_param_named(debug_level, wlan_dbg_level, int, 0644); +//module_param_named(debug_area, wlan_dbg_area, int, 0644); + +static const struct sdio_device_id if_sdio_ids[] = { + { SDIO_DEVICE(SDIO_VENDOR_ID_RDA, SDIO_DEVICE_ID_RDA) }, + { /* end: all zeroes */ }, +}; +MODULE_DEVICE_TABLE(sdio, if_sdio_ids); + +static int wlan_dev_open (struct net_device *dev) +{ + int ret = 0; + wlan_private *priv = NULL; + + priv = (wlan_private *)netdev_priv(dev); + + if(!priv) + return -EPERM; + + priv->Open = TRUE; + + netif_carrier_on(priv->netDev); + netif_wake_queue(priv->netDev); + + return ret; +} + +static int wlan_eth_stop(struct net_device *dev) +{ + int ret = 0; + wlan_private *priv = NULL; + + priv = (wlan_private *)netdev_priv(dev); + + if(!priv) + return -EPERM; + + ENTER(); + + if (!netif_queue_stopped(priv->netDev)){ + netif_stop_queue(priv->netDev); + } + + if (netif_carrier_ok(priv->netDev)){ + netif_carrier_off(priv->netDev); + } + + LEAVE(); + return ret; +} + +static int wlan_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + int ret = 0; + wlan_private *priv = NULL; + wlan_tx_packet_node * txNode = NULL; + unsigned long flags = 0; +#ifdef WLAN_RAW_DATA_DEBUG + u8 *printStr = NULL; +#endif + int tx_queue_max_num =0; + + ENTER(); + + if(rda_combo_wifi_in_test_mode()){ + dev_kfree_skb(skb); + return 0; + } + + priv = (wlan_private *)netdev_priv(dev); + if(!priv || !is_sdio_init_complete()){ + WLAN_ERRP("device is not opened \n"); + return -EPERM; + } + + if (priv->version == WLAN_VERSION_90_D || priv->version == WLAN_VERSION_90_E){ + tx_queue_max_num = WLAN_TX_QUEUE_NUM_90; + } else if (priv->version == WLAN_VERSION_91 || priv->version == WLAN_VERSION_91_E + || priv->version == WLAN_VERSION_91_F) { + tx_queue_max_num = WLAN_TX_QUEUE_NUM_91; + } else { + tx_queue_max_num = WLAN_TX_QUEUE_NUM_90; + WLAN_ERRP("WLAN_TX_QUEUE_NUM doesn't set for this version\n"); + } + + if(atomic_read(&(priv->TxQuNum)) >= tx_queue_max_num || priv->CardRemoved){ + WLAN_ERRP("queue is full, priv->TxQuNum=%d \n", atomic_read(&(priv->TxQuNum))); + return -ENOMEM; + } + + txNode = (wlan_tx_packet_node*)kzalloc(sizeof(wlan_tx_packet_node), GFP_ATOMIC); + if(!txNode){ + WLAN_ERRP("no memory \n"); + return -ENOMEM; + } + + WLAN_DBGLAP(WLAN_DA_MAIN, WLAN_DL_DEBUG,"skb headroom: %d %d len;%d \n", skb_headroom(skb), atomic_read(&priv->netifQuStop), skb->len); + +#ifdef WLAN_RAW_DATA_DEBUG + printStr = skb->data; + WLAN_ERRP("%x %x %x %x %x %x %x %x\n", printStr[0], printStr[1],printStr[2],printStr[3],printStr[4],printStr[5],printStr[6],printStr[7]); + printStr += 8; + WLAN_ERRP("%x %x %x %x %x %x %x %x\n", printStr[0], printStr[1],printStr[2],printStr[3],printStr[4],printStr[5],printStr[6],printStr[7]); + printStr += 8; + WLAN_ERRP("%x %x %x %x %x %x %x %x\n", printStr[0], printStr[1],printStr[2],printStr[3],printStr[4],printStr[5],printStr[6],printStr[7]); +#endif + + txNode->type = WLAN_DATA; + if(IS_ALIGNED((int)skb->data - WID_HEADER_LEN, 4)) + txNode->Skb = skb; + else{ + txNode->Skb = dev_alloc_skb(skb->len + 4 + WID_HEADER_LEN); + if(txNode->Skb){ + skb_align(txNode->Skb, 4); + skb_reserve(txNode->Skb , WID_HEADER_LEN); + memcpy(txNode->Skb->data, skb->data, skb->len); + skb_put(txNode->Skb, skb->len); + } + dev_kfree_skb(skb); + + if(!txNode->Skb){ + return -ENOMEM; + } + } + + spin_lock_irqsave(&priv->TxLock, flags); + list_add_tail(&txNode->List, &priv->TxQueue); + spin_unlock_irqrestore(&priv->TxLock, flags); + atomic_add(1, &(priv->TxQuNum)); + + if(atomic_read(&(priv->TxQuNum)) >= tx_queue_max_num){ + netif_stop_queue(dev); + atomic_set(&(priv->netifQuStop), 1); + } + + dev->trans_start = jiffies; + + complete(&priv->TxThread.comp); + + LEAVE(); + return ret; +} + +static int wlan_set_mac_address(struct net_device *dev, void *addr) +{ + int ret = 0; + return ret; +} + +static void wlan_tx_timeout (struct net_device *dev) +{ + ENTER(); + + dev->trans_start = jiffies; /* prevent tx timeout */ + netif_wake_queue(dev); + dev->stats.tx_errors++; + + LEAVE(); +} + +static struct net_device_stats *wlan_get_stats(struct net_device *dev) +{ + wlan_private *priv = (wlan_private *) netdev_priv(dev); + + return &priv->stats; +} + +#define BT_COEXIST SIOCIWFIRSTPRIV + 2 +#define BT_STATE_SCO_ON 0x01 +#define BT_STATE_SCO_OFF 0x02 +#define BT_STATE_SCO_ONGOING 0x04 +#define BT_STATE_A2DP_PLAYING 0x08 +#define BT_STATE_A2DP_NO_PLAYING 0x10 +#define BT_STATE_CONNECTION_ON 0x20 +#define BT_STATE_CONNECTION_OFF 0x40 +static int wlan_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + int ret = -EOPNOTSUPP; + static int bt_state = 0; + int state = 0, old_state = 0; + struct pta_param_s pta_param; + wlan_private *priv = (wlan_private *) netdev_priv(dev); + + ENTER(); + + if(priv->version < WLAN_VERSION_91_E) + goto out; + + if(cmd == BT_COEXIST){ + state = rq->ifr_metric; + ret = 0; + + pta_param.prot_mode = PTA_NONE_PROTECT; + pta_param.mac_rate = 0x0; + pta_param.hw_retry = 0x7; + pta_param.sw_retry = 0x3; + pta_param.cca_bypass = TRUE; + pta_param.active_time = 500; /* Unit is 100us */ + pta_param.thresh_time = 20; /* Unit is 100us */ + pta_param.auto_prot_thresh_time = 200; /* Unit is 100us */ + pta_param.flags = BIT0 | BIT1 | BIT5; + + if(state == BT_STATE_SCO_ONGOING){ + state = BT_STATE_SCO_ON; + } + old_state = bt_state; + + if(state &(BT_STATE_SCO_ON | BT_STATE_SCO_ONGOING)){ + bt_state |= BT_STATE_SCO_ON; + } + if(state & BT_STATE_A2DP_PLAYING){ + bt_state |= BT_STATE_A2DP_PLAYING; + } + if(state & BT_STATE_CONNECTION_ON) + bt_state |= BT_STATE_CONNECTION_ON; + + if(state == BT_STATE_SCO_OFF){ + bt_state &= ~BT_STATE_SCO_ON; + }else if(state == BT_STATE_A2DP_NO_PLAYING){ + bt_state &= ~BT_STATE_A2DP_PLAYING; + }else if(state == BT_STATE_CONNECTION_OFF) + bt_state &= ~BT_STATE_CONNECTION_ON; + + if(old_state == bt_state) + goto out; + + if(bt_state){ + if(bt_state & BT_STATE_SCO_ON){ + if(old_state) //should clear pta proc before to set a new pta protec + ret = wlan_set_pta(priv, &pta_param); + pta_param.prot_mode = PTA_PS_POLL_PROTECT; + pta_param.mac_rate = 0x4; + pta_param.hw_retry = 0x1; + pta_param.sw_retry = 0x1; + pta_param.active_time = 25; + pta_param.thresh_time = 5; + pta_param.auto_prot_thresh_time = 15; + pta_param.flags = BIT0 | BIT1; + }else if(bt_state & BT_STATE_A2DP_PLAYING){ + if(old_state) + ret = wlan_set_pta(priv, &pta_param); + pta_param.prot_mode = PTA_NULL_DATA_PROTECT; + pta_param.active_time = 600; + pta_param.thresh_time = 20; + pta_param.auto_prot_thresh_time = 200; + }else if(bt_state & BT_STATE_CONNECTION_ON){ + if(old_state) + ret = wlan_set_pta(priv, &pta_param); + pta_param.prot_mode = PTA_NULL_DATA_PROTECT; + pta_param.active_time = 600; + pta_param.thresh_time = 20; + pta_param.auto_prot_thresh_time = 200; + } + }else + pta_param.prot_mode = PTA_NONE_PROTECT; + + ret = wlan_set_pta(priv, &pta_param); + //log for debug now do not delete + printk("***BT_COEXIST state:%x \n", bt_state); + } + +out: + LEAVE(); + + return ret; +} + +static const struct net_device_ops rda_netdev_ops = { + .ndo_open = wlan_dev_open, + .ndo_stop = wlan_eth_stop, + .ndo_start_xmit = wlan_hard_start_xmit, + .ndo_set_mac_address = wlan_set_mac_address, + .ndo_tx_timeout = wlan_tx_timeout, + .ndo_get_stats = wlan_get_stats, + .ndo_do_ioctl = wlan_ioctl +}; + +#ifdef WLAN_FORCE_SUSPEND_SUPPORT +static int rda_wlan_set_suspend(wlan_private * priv) +{ + int ret; + + ENTER(); + + if (!priv) { + ret = -1; + return ret; + } + + ret= wlan_set_listen_interval(priv, WIFI_SLEEP_LISTEN_INTERVAL); + if(ret){ + WLAN_ERRP("wlan_set_listen_interval failed! \n"); + } + + if (priv->version == WLAN_VERSION_90_D || priv->version == WLAN_VERSION_90_E){ + ret = wlan_set_link_loss_threshold(priv, WIFI_SLEEP_LINK_LOSS_THRESHOLD_90); + if(ret){ + WLAN_ERRP("wlan_set_link_loss_threshold failed! \n"); + } + }else if(priv->version == WLAN_VERSION_91){ + ret = wlan_set_link_loss_threshold(priv, WIFI_SLEEP_LINK_LOSS_THRESHOLD_91); + if(ret){ + WLAN_ERRP("wlan_set_link_loss_threshold failed! \n"); + } + }else if(priv->version == WLAN_VERSION_91_E){ + ret = wlan_set_link_loss_threshold(priv, WIFI_SLEEP_LINK_LOSS_THRESHOLD_91); + if(ret){ + WLAN_ERRP("wlan_set_link_loss_threshold failed! \n"); + } + }else if(priv->version == WLAN_VERSION_91_F){ + ret = wlan_set_link_loss_threshold(priv, WIFI_SLEEP_LINK_LOSS_THRESHOLD_91); + if(ret){ + WLAN_ERRP("wlan_set_link_loss_threshold failed! \n"); + } + } + + LEAVE(); + + return ret; +} + +static int rda_wlan_set_resume(wlan_private * priv) +{ + int ret; + + ENTER(); + + if (!priv) { + ret = -1; + return ret; + } + + ret= wlan_set_listen_interval(priv, WIFI_LISTEN_INTERVAL); + if(ret){ + WLAN_ERRP("wlan_set_listen_interval failed! \n"); + } + + if (priv->version == WLAN_VERSION_90_D || priv->version == WLAN_VERSION_90_E){ + ret = wlan_set_link_loss_threshold(priv, WIFI_LINK_LOSS_THRESHOLD_90); + if(ret){ + WLAN_ERRP("wlan_set_link_loss_threshold failed! \n"); + } + }else if(priv->version == WLAN_VERSION_91){ + ret = wlan_set_link_loss_threshold(priv, WIFI_LINK_LOSS_THRESHOLD_91); + if(ret){ + WLAN_ERRP("wlan_set_link_loss_threshold failed! \n"); + } + }else if(priv->version == WLAN_VERSION_91_E){ + ret = wlan_set_link_loss_threshold(priv, WIFI_LINK_LOSS_THRESHOLD_91); + if(ret){ + WLAN_ERRP("wlan_set_link_loss_threshold failed! \n"); + } + }else if(priv->version == WLAN_VERSION_91_F){ + ret = wlan_set_link_loss_threshold(priv, WIFI_LINK_LOSS_THRESHOLD_91); + if(ret){ + WLAN_ERRP("wlan_set_link_loss_threshold failed! \n"); + } + } + + LEAVE(); + return ret; +} + +static int rda_wlan_early_suspend(struct device *dev) +{ + ENTER(); + LEAVE(); + return 0; +} + +static int rda_wlan_late_resume(struct device *dev) +{ + int ret; + wlan_private* priv = (wlan_private*)dev_get_drvdata(dev); + + ENTER(); + + if (priv->CardInSuspend == TRUE) { + priv->CardInSuspend = FALSE; + ret = rda_wlan_set_resume(priv); + if (ret) { + WLAN_ERRP("rda_wlan_set_resume failed! \n"); + } + } + + LEAVE(); + return 0; +} + +static int rda_wlan_notify(struct notifier_block *nb, + unsigned long mode, void *_unused) +{ + int ret; + wlan_private * priv = NULL; + priv = container_of(nb, wlan_private, pm_nb); + + ENTER(); + + switch (mode) { + case PM_SUSPEND_PREPARE: + if (priv->CardInSuspend == FALSE) { + ret = rda_wlan_set_suspend(priv); + if (ret) { + WLAN_ERRP("rda_wlan_set_suspend failed! \n"); + } + priv->CardInSuspend = TRUE; + } + break; + } + + LEAVE(); + + return 0; +} +#endif /*WLAN_FORCE_SUSPEND_SUPPORT*/ +#ifdef WLAN_SYS_SUSPEND + +static int rda_sdio_suspend(struct device *dev) +{ + mmc_pm_flag_t sdio_flags; + wlan_private * priv = NULL; + wlan_sdio_card * card = NULL; + struct sdio_func *func = dev_to_sdio_func(dev); + int ret = 0, ret1 = 0; + ENTER(); + + card = (wlan_sdio_card*)sdio_get_drvdata(func); + if(card) + priv = card->priv; + else + return 0; + + printk("rda_sdio_suspend ***** \n"); + netif_stop_queue(priv->netDev); + priv->Suspend = TRUE; + + wlan_cancel_timer(&priv->StartAssociationTimeOut); + wlan_remove_tx_data_queue(priv); + wlan_release_wid_pending_queue(priv); + + while(1){ + if(!priv->CardInSleep){ + wlan_push_event(priv, WLAN_EVENT_CARD_TO_SLEEP, priv, FALSE); + wlan_sched_timeout(50); + }else + break; + } + sdio_flags = sdio_get_host_pm_caps(func); + if (!(sdio_flags & MMC_PM_KEEP_POWER)) { + printk("Host can't keep power while suspended \n"); + ret1 = 0; + } + + ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); + if (ret) { + printk("set host pm flags failed \n"); + ret1 = 0; + } + //enable wifi eint for waking up system when suspend + wlan_register_host_wake_irq(priv); + LEAVE(); + return ret1; +} + + +static int rda_sdio_resume(struct device *dev) +{ + //add by LA + wlan_private * priv = NULL; + wlan_sdio_card * card = NULL; + struct sdio_func *func = dev_to_sdio_func(dev); + ENTER(); + + card = (wlan_sdio_card*)sdio_get_drvdata(func); + if(card) + priv = (wlan_private*)card->priv; + else + return 0; + + printk("rda_sdio_resume \n"); + netif_wake_queue(priv->netDev); + priv->Suspend = FALSE; + //disable wifi eint when system resume + wlan_unregister_host_wake_irq(priv); + LEAVE(); + return 0; +} + +static struct dev_pm_ops rda_sdio_pm_ops = { + .suspend = rda_sdio_suspend, + .resume = rda_sdio_resume, +}; + +#endif + +extern int wlan_set_rssi_91(wlan_private * priv, u8 rssi); + +unsigned int wlan_extern_irq_handle(int irq, void *para) +{ + wlan_private* priv = (wlan_private* )para; + disable_irq_nosync(priv->external_irq); + wake_lock_timeout(&priv->ExtIrqTimerLock, HZ/5); + return 0; +} + +void if_sdio_interrupt(struct sdio_func *func) +{ + int ret = 0; + wlan_sdio_card *card = NULL; + wlan_private* priv = NULL; + u8 status; + unsigned long flags = 0; + u8 size_l = 0, size_h = 0; + u16 size = 0, payload_len = 0; + struct sk_buff *skb = NULL; + wlan_rx_packet_node * rx_node = NULL; + + ENTER(); + card = (wlan_sdio_card*)sdio_get_drvdata(func); + if(!card || !is_sdio_init_complete()) + { + WLAN_ERRP("card is NULL or sdio init is not completed!\n"); + return; + } + + priv = card->priv; + + sdio_claim_host(card->func); + + ret = wlan_read_byte(priv, IF_SDIO_FUN1_INT_STAT, &status); + sdio_release_host(card->func); + if (ret){ + WLAN_ERRP("SDIO read IF_SDIO_FUN1_INT_STAT status failed!\n"); + goto out; + } + + WLAN_DBGLAP(WLAN_DA_SDIO, WLAN_DL_VERB,"if_sdio_interrupt, status = 0x%02x\n", status); + + if (status & IF_SDIO_INT_AHB2SDIO){ + + sdio_claim_host(card->func); + if(wlan_read_byte(priv, IF_SDIO_AHB2SDIO_PKTLEN_L, &size_l)){ + WLAN_ERRP("SDIO read IF_SDIO_AHB2SDIO_PKTLEN_L failed!\n"); + sdio_release_host(card->func); + goto out; + } + + if(wlan_read_byte(priv, IF_SDIO_AHB2SDIO_PKTLEN_H, &size_h)){ + WLAN_ERRP("SDIO read IF_SDIO_AHB2SDIO_PKTLEN_H failed!\n"); + sdio_release_host(card->func); + goto out; + } + + size = (size_l | ((size_h & 0x7f) << 8)) * 4; + if(size > SDIO_MAX_BUFSZ){ + WLAN_ERRP("if_sdio_interrupt received buffer is too larger size %d \n", size); + goto out; + }else if(size < 4){ + WLAN_ERRP("invalid size %d \n", size); + goto out; + } + + skb = dev_alloc_skb(size + NET_IP_ALIGN + WID_HEADER_LEN + 3); + if(!skb){ + WLAN_ERRP("if_sdio_interrupt alloc skb failed \n"); + goto out; + } + + rx_node = kzalloc(sizeof(wlan_rx_packet_node), GFP_ATOMIC); + if(!rx_node){ + WLAN_ERRP("kzalloc wlan_rx_packet_node failed \n"); + dev_kfree_skb(skb); + goto out; + } + + skb_reserve(skb, NET_IP_ALIGN); + //4byte align + skb_align(skb, 4); + rx_node->Skb = skb; + if(wlan_read_bytes(priv, IF_SDIO_FUN1_FIFO_RD, skb->data, size) + || priv->CardRemoved){ + WLAN_ERRP("SDIO read IF_SDIO_FUN1_FIFO_RD failed! \n"); + sdio_release_host(card->func); + kfree(rx_node); + dev_kfree_skb(skb); + goto out; + } + sdio_release_host(card->func); + + //put payload length in skb + payload_len = (u16)(skb->data[0] + ((skb->data[1]&0x0f) << 8)); + if(payload_len > size){ + WLAN_ERRP("SDIO read payload_len invalid! \n"); + kfree(rx_node); + dev_kfree_skb(skb); + goto out; + } + skb_put(skb, payload_len); + + spin_lock_irqsave(&priv->RxLock, flags); + list_add_tail(&rx_node->List, &priv->RxQueue); + priv->RxQuNum++; + spin_unlock_irqrestore(&priv->RxLock, flags); + complete(&priv->RxThread.comp); + + }else if (status & IF_SDIO_INT_ERROR){ + sdio_claim_host(card->func); + ret = wlan_write_byte(priv, IF_SDIO_FUN1_INT_PEND, IF_SDIO_INT_ERROR); + sdio_release_host(card->func); + if (ret){ + WLAN_ERRP("write FUN1_INT_STAT reg fail \n"); + goto out; + } + WLAN_DBGLAP(WLAN_DA_SDIO, WLAN_DL_TRACE,"%s, INT_ERROR \n", __func__); + } + +out: + LEAVE(); +} + +extern unsigned int rda_wlan_version(void); + +static struct platform_device *platform_device = NULL; + + +static ssize_t show_dbgl(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n",wlan_dbg_level); +} + +static ssize_t store_dbgl(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + unsigned long dbgl; + + if (strict_strtoul(buf, 0, &dbgl)) + return -EINVAL; + + wlan_dbg_level = dbgl; + + return count; +} + +static ssize_t show_dbga(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n",wlan_dbg_area); +} + +static ssize_t store_dbga(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + unsigned long dbga; + + if (strict_strtoul(buf, 0, &dbga)) + return -EINVAL; + + wlan_dbg_area = dbga; + + return count; +} + +static ssize_t show_wlanpm(struct device *dev, + struct device_attribute *attr, char *buf) +{ + wlan_private* priv = (wlan_private*)dev_get_drvdata(dev); + return sprintf(buf, "%d \n",priv?(u32)priv->wlan_pm_enable:0); +} + +static ssize_t store_wlanpm(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + unsigned long wlanpm; + wlan_private* priv = (wlan_private*)dev_get_drvdata(dev); + + if (strict_strtoul(buf, 0, &wlanpm)) + return -EINVAL; + + if(priv) + priv->wlan_pm_enable = wlanpm; + + return count; +} + +static ssize_t show_wlanirq(struct device *dev, + struct device_attribute *attr, char *buf) +{ + wlan_private* priv = (wlan_private*)dev_get_drvdata(dev); + return sprintf(buf, "%d \n",priv?(u32)priv->sdio_irq_enable:0); +} +static ssize_t store_wlanirq(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + unsigned long wlanirq; + wlan_private* priv = (wlan_private*)dev_get_drvdata(dev); + if (strict_strtoul(buf, 0, &wlanirq)) + return -EINVAL; + if (wlanirq) { + rda_mci_enable_sdio_irq(priv->MmcCard->host, 1); + priv->sdio_irq_enable = TRUE; + } else { + //rda_mmc_set_sdio_irq(1, false); + rda_mci_enable_sdio_irq(priv->MmcCard->host, 0); + priv->sdio_irq_enable = FALSE; + } + return count; +} +static ssize_t show_wlan_earlysuspend_enabled(struct device *dev, + struct device_attribute *attr, char *buf) +{ + wlan_private* priv = (wlan_private*)dev_get_drvdata(dev); + return sprintf(buf, "%d\n",priv?(u32)priv->earlysuspend_enabled:0); +} + +static ssize_t store_wlan_earlysuspend_enabled(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + int ret; + int set; + wlan_private* priv = (wlan_private*)dev_get_drvdata(dev); + + ret = kstrtoint(buf, 0, &set); + if (ret < 0) { + return ret; + } + + set = !!set; + + if (priv->earlysuspend_enabled == set) { + return count; + } + +#ifdef WLAN_FORCE_SUSPEND_SUPPORT + if (set) { + ret = rda_wlan_late_resume(dev); + } else { + ret = rda_wlan_early_suspend(dev); + } +#endif + + priv->earlysuspend_enabled = set; + + return count; +} +static DEVICE_ATTR(dbgl, S_IWUSR | S_IRUGO , show_dbgl, store_dbgl); +static DEVICE_ATTR(dbga, S_IWUSR | S_IRUGO, show_dbga, store_dbga); +static DEVICE_ATTR(wlanpm, S_IWUSR | S_IRUGO, show_wlanpm, store_wlanpm); +static DEVICE_ATTR(wlanirq, S_IWUSR | S_IRUGO, show_wlanirq, store_wlanirq); +static DEVICE_ATTR(enabled, S_IWUSR | S_IWGRP | S_IRUGO, show_wlan_earlysuspend_enabled, store_wlan_earlysuspend_enabled); + +static struct attribute *wlan_dbg_sysfs_entries[] = { + &dev_attr_dbgl.attr, + &dev_attr_dbga.attr, + &dev_attr_wlanpm.attr, + &dev_attr_wlanirq.attr, + &dev_attr_enabled.attr, + NULL, +}; + +static struct attribute_group wlan_dbg_attr_group = { + .attrs = wlan_dbg_sysfs_entries, +}; + +static int if_sdio_probe(struct sdio_func *func, + const struct sdio_device_id *id) +{ + wlan_sdio_card * card = NULL; + wlan_private * priv = NULL; + int ret = -1; + + ENTER(); + + if(func) { + printk("bcmsdh_sdmmc: %s Enter\n", __FUNCTION__); + printk("sdio_bcmsdh: func->class=%x\n", func->class); + printk("sdio_vendor: 0x%04x\n", func->vendor); + printk("sdio_device: 0x%04x\n", func->device); + printk("Function#: 0x%04x\n", func->num); + } else { + printk("func is null\n"); + } + + if(id->vendor != SDIO_VENDOR_ID_RDA){ + WLAN_ERRP("rda5890 sdio not corrent vendor:%x \n", id->vendor); + return -1; + } + + card = (wlan_sdio_card*)kzalloc(sizeof(wlan_sdio_card), GFP_KERNEL); + if (!card){ + ret = -ENOMEM; + goto err_alloc_card; + } + + card->func = func; + sdio_set_drvdata(func, card); + + if(wlan_add_card(card)) + goto err_add_card; + + priv = card->priv; + priv->MmcCard = func->card; + wlan_debugfs_init_all(priv); + + platform_device = platform_device_alloc("rda-wlan", -1); + if (platform_device){ + platform_set_drvdata(platform_device, priv); + if(!platform_device_add(platform_device)){ + ret = sysfs_create_group(&platform_device->dev.kobj, + &wlan_dbg_attr_group); + }else{ + platform_device_put(platform_device); + } + } + + priv->netDev->netdev_ops = &rda_netdev_ops; + sdio_claim_host(func); + ret = sdio_enable_func(func); + if (ret){ + WLAN_ERRP("sdio_enable_func fail, ret = %d\n", ret); + sdio_release_host(func); + goto err_enable_func; + } + + + rda_mci_enable_sdio_irq(priv->MmcCard->host, 0); + priv->version = rda_wlan_version(); + + ret = sdio_claim_irq(func, if_sdio_interrupt); + if (ret){ + WLAN_ERRP("sdio_claim_irq fail, ret = %d\n", ret); + sdio_release_host(func); + goto err_claim_irq; + } + + ret = -1; + + //enable interrupt + if(wlan_write_byte(priv, IF_SDIO_FUN1_INT_MASK, 0x07)){ + WLAN_ERRP("err_enable_int \n"); + sdio_release_host(func); + goto err_enable_int; + } + sdio_release_host(func); + + wlan_push_event(priv, WLAN_EVENT_CARD_CONTROL_INIT, priv, FALSE); + +#ifdef WLAN_FORCE_SUSPEND_SUPPORT + priv->pm_nb.notifier_call = rda_wlan_notify; + register_pm_notifier(&priv->pm_nb); +#endif + LEAVE(); + + return 0; + +err_enable_int: +err_claim_irq: +err_enable_func: + wlan_release_dev(card); + +err_add_card: + kfree(card); + +err_alloc_card: + + return ret; +} + + +static void if_sdio_remove(struct sdio_func *func) +{ + wlan_sdio_card * card = NULL; + wlan_private * priv = NULL; + ENTER(); + + card = (wlan_sdio_card *)sdio_get_drvdata(func); + if(!card) + return; + + priv = (wlan_private*)card->priv; + if(!priv){ + kfree(card); + return; + } + + if(platform_device){ + sysfs_remove_group(&platform_device->dev.kobj, &wlan_dbg_attr_group); + platform_device_unregister(platform_device); + platform_device = NULL; + } + wlan_debugfs_remove_all(priv); + + sdio_claim_host(func); + sdio_release_irq(func); + sdio_disable_func(func); + sdio_release_host(func); + + rda_mci_enable_sdio_irq(priv->MmcCard->host, 0); + priv->sdio_irq_enable = FALSE; + + wlan_unregister_host_wake_irq(priv); + wlan_release_dev(card); + kfree(card); + priv->MmcCard = NULL; + LEAVE(); +} + +static struct sdio_driver if_sdio_driver = { + .name = "rda_wlan_sdio", + .id_table = if_sdio_ids, + .probe = if_sdio_probe, + .remove = if_sdio_remove, +#ifdef WLAN_SYS_SUSPEND + .drv.pm = &rda_sdio_pm_ops, +#endif +}; + +extern void wmt_detect_sdio2(void); +extern void force_remove_sdio2(void); + +static int __init wlan_init_module(void) +{ + int ret = 0; + + printk(KERN_INFO "\nRDA5890 SDIO WIFI Driver for st_linux \n"); + printk(KERN_INFO "Ver: %d.%d.%d\n\n", + WLAN_SDIOWIFI_VER_MAJ, + WLAN_SDIOWIFI_VER_MIN, + WLAN_SDIOWIFI_VER_BLD); + wlan_debugfs_init(); + ret = sdio_register_driver(&if_sdio_driver); + wmt_detect_sdio2(); + printk("wlan_init_module2014022801 %d \n", ret); + return ret; +} + +static void __exit wlan_exit_module(void) +{ + sdio_unregister_driver(&if_sdio_driver); + wlan_debugfs_remove(); + printk("wlan_exit_module \n"); + + force_remove_sdio2(); + + +} + +module_init(wlan_init_module); +module_exit(wlan_exit_module); +MODULE_DESCRIPTION("RDA SDIO WLAN Driver"); +MODULE_AUTHOR("albert"); +MODULE_LICENSE("GPL"); + +#endif + diff --git a/drivers/net/wireless/rda/rda_wlan/wlan_nvram.c b/drivers/net/wireless/rda/rda_wlan/wlan_nvram.c new file mode 100755 index 00000000..a48ba72b --- /dev/null +++ b/drivers/net/wireless/rda/rda_wlan/wlan_nvram.c @@ -0,0 +1,209 @@ +#include +#include +#include "wlan_includes.h" + +#ifdef USE_MAC_FROM_RDA_NVRAM +#include +#endif + +#define WIFI_NVRAM_FILE_NAME "/data/misc/wifi/WLANMAC" + +static int nvram_read(char *filename, char *buf, ssize_t len, int offset) +{ + struct file *fd; + int retLen = -1; + + mm_segment_t old_fs = get_fs(); + set_fs(KERNEL_DS); + fd = filp_open(filename, O_WRONLY|O_CREAT, 0644); + + if(IS_ERR(fd)){ + printk("[wlan][nvram_read] : failed to open!!\n"); + return -1; + } + + do{ + if ((fd->f_op == NULL) || (fd->f_op->read == NULL)){ + printk("[wlan][nvram_read] : file can not be read!!\n"); + break; + } + + if (fd->f_pos != offset){ + if (fd->f_op->llseek){ + if(fd->f_op->llseek(fd, offset, 0) != offset){ + printk("[wlan][nvram_read] : failed to seek!!\n"); + break; + } + }else{ + fd->f_pos = offset; + } + } + + retLen = fd->f_op->read(fd, buf, len, &fd->f_pos); + }while(false); + + filp_close(fd, NULL); + set_fs(old_fs); + + return retLen; +} + +static int nvram_write(char *filename, char *buf, ssize_t len, int offset) +{ + struct file *fd; + int retLen = -1; + + mm_segment_t old_fs = get_fs(); + set_fs(KERNEL_DS); + + fd = filp_open(filename, O_WRONLY|O_CREAT, 0644); + + if(IS_ERR(fd)){ + printk("[wlan][nvram_write] : failed to open!!\n"); + return -1; + } + + do{ + if ((fd->f_op == NULL) || (fd->f_op->write == NULL)){ + printk("[wlan][nvram_write] : file can not be write!!\n"); + break; + } + + if (fd->f_pos != offset){ + if (fd->f_op->llseek){ + if(fd->f_op->llseek(fd, offset, 0) != offset){ + printk("[wlan][nvram_write] : failed to seek!!\n"); + break; + } + }else{ + fd->f_pos = offset; + } + } + + retLen = fd->f_op->write(fd, buf, len, &fd->f_pos); + + }while(false); + + filp_close(fd, NULL); + set_fs(old_fs); + + return retLen; +} + +int wlan_read_mac_from_file(char* buf) +{ + return nvram_read(WIFI_NVRAM_FILE_NAME, buf, 6, 0); +} + +int wlan_write_mac_to_file(char * buf) +{ + return nvram_write(WIFI_NVRAM_FILE_NAME, buf, 6, 0); +} + +#ifdef USE_MAC_FROM_RDA_NVRAM +int wlan_read_mac_from_nvram(char *buf) +{ + int ret; + struct msys_device *wlan_msys = NULL; + struct wlan_mac_info wlan_info; + struct client_cmd cmd_set; + + wlan_msys = rda_msys_alloc_device(); + if (!wlan_msys) { + WLAN_ERRP("nvram: can not allocate wlan_msys device\n"); + ret = -ENOMEM; + goto err_handle_sys; + } + + wlan_msys->module = SYS_GEN_MOD; + wlan_msys->name = "rda-wlan"; + rda_msys_register_device(wlan_msys); + + memset(&wlan_info, sizeof(wlan_info), 0); + cmd_set.pmsys_dev = wlan_msys; + cmd_set.mod_id = SYS_GEN_MOD; + cmd_set.mesg_id = SYS_GEN_CMD_GET_WIFI_INFO; + cmd_set.pdata = NULL; + cmd_set.data_size = 0; + cmd_set.pout_data = &wlan_info; + cmd_set.out_size = sizeof(wlan_info); + + ret = rda_msys_send_cmd(&cmd_set); + if (ret) { + WLAN_ERRP("nvram:can not get wifi mac from nvram \n"); + ret = -EBUSY; + goto err_handle_cmd; + } + + if (wlan_info.activated != WIFI_MAC_ACTIVATED_FLAG) { + WLAN_ERRP("nvram:get invalid wifi mac address from nvram\n"); + ret = -EINVAL; + goto err_invalid_mac; + } + + memcpy(buf, wlan_info.mac_addr, ETH_ALEN); + WLAN_DBGLAP(WLAN_DA_MAIN, WLAN_DL_CRIT, + "nvram:get wifi mac address [%02x:%02x:%02x:%02x:%02x:%02x] from nvram success.\n", + buf[0], buf[1], buf[2], + buf[3], buf[4], buf[5]); + ret = 0; /* success*/ + +err_invalid_mac: +err_handle_cmd: + rda_msys_unregister_device(wlan_msys); + rda_msys_free_device(wlan_msys); +err_handle_sys: + return ret; +} + +int wlan_write_mac_to_nvram(const char *buf) +{ + int ret; + struct msys_device *wlan_msys = NULL; + struct wlan_mac_info wlan_info; + struct client_cmd cmd_set; + + wlan_msys = rda_msys_alloc_device(); + if (!wlan_msys) { + WLAN_ERRP("nvram: can not allocate wlan_msys device\n"); + ret = -ENOMEM; + goto err_handle_sys; + } + + wlan_msys->module = SYS_GEN_MOD; + wlan_msys->name = "rda-wlan"; + rda_msys_register_device(wlan_msys); + + memset(&wlan_info, sizeof(wlan_info), 0); + wlan_info.activated = WIFI_MAC_ACTIVATED_FLAG; + memcpy(wlan_info.mac_addr, buf, ETH_ALEN); + + cmd_set.pmsys_dev = wlan_msys; + cmd_set.mod_id = SYS_GEN_MOD; + cmd_set.mesg_id = SYS_GEN_CMD_SET_WIFI_INFO; + cmd_set.pdata = &wlan_info; + cmd_set.data_size = sizeof(wlan_info); + cmd_set.pout_data = NULL; + cmd_set.out_size = 0; + + ret = rda_msys_send_cmd(&cmd_set); + if (ret) { + WLAN_ERRP("nvram:can not set wifi mac to nvram \n"); + ret = -EBUSY; + goto err_handle_cmd; + } + + WLAN_DBGLAP(WLAN_DA_MAIN, WLAN_DL_CRIT, + "nvram:set wifi mac address [%02x:%02x:%02x:%02x:%02x:%02x] to nvram success.\n", + buf[0], buf[1], buf[2], + buf[3], buf[4], buf[5]); + ret = 0; /* success*/ + +err_handle_cmd: + rda_msys_unregister_device(wlan_msys); + rda_msys_free_device(wlan_msys); +err_handle_sys: + return ret; +} +#endif /*USE_MAC_FROM_RDA_NVRAM*/ + diff --git a/drivers/net/wireless/rda/rda_wlan/wlan_os.h b/drivers/net/wireless/rda/rda_wlan/wlan_os.h new file mode 100755 index 00000000..72457746 --- /dev/null +++ b/drivers/net/wireless/rda/rda_wlan/wlan_os.h @@ -0,0 +1,145 @@ +#ifndef __WLAN_TIMER_H_ +#define __WLAN_TIMER_H_ + +typedef struct __WLAN_DRV_TIMER +{ + struct timer_list tl; + void (*timer_function) (void *context); + void *function_context; + u32 time_period; + u8 timer_is_periodic; + u8 timer_is_canceled; + u8 EventType; +} WLAN_DRV_TIMER, *PWLAN_DRV_TIMER; + +extern void wlan_timer_handler(unsigned long fcontext); +static inline void +wlan_initialize_timer(PWLAN_DRV_TIMER timer, + void (*TimerFunction) (void *context), + void *FunctionContext, u8 eventType) +{ + /* first, setup the timer to trigger the wlan_timer_handler proxy */ + init_timer(&timer->tl); + timer->tl.function = wlan_timer_handler; + timer->tl.data = (u32) timer; + + /* then tell the proxy which function to call and what to pass it */ + timer->timer_function = TimerFunction; + timer->function_context = FunctionContext; + timer->EventType = eventType; + timer->timer_is_canceled = TRUE; + timer->timer_is_periodic = FALSE; +} + +static inline void +wlan_set_timer(PWLAN_DRV_TIMER timer, u32 MillisecondPeriod) +{ + timer->time_period = MillisecondPeriod; + timer->timer_is_periodic = FALSE; + timer->tl.expires = jiffies + (MillisecondPeriod * HZ) / 1000; + add_timer(&timer->tl); + timer->timer_is_canceled = FALSE; +} + +static inline void +wlan_mod_timer(PWLAN_DRV_TIMER timer, u32 MillisecondPeriod) +{ + timer->time_period = MillisecondPeriod; + timer->timer_is_periodic = FALSE; + mod_timer(&timer->tl, jiffies + (MillisecondPeriod * HZ) / 1000); + timer->timer_is_canceled = FALSE; +} + +static inline void +wlan_set_periodic_timer(PWLAN_DRV_TIMER timer, u32 MillisecondPeriod) +{ + timer->time_period = MillisecondPeriod; + timer->timer_is_periodic = TRUE; + timer->tl.expires = jiffies + (MillisecondPeriod * HZ) / 1000; + add_timer(&timer->tl); + timer->timer_is_canceled = FALSE; +} + +#define FreeTimer(x) do {} while (0) + +static inline void +wlan_cancel_timer(WLAN_DRV_TIMER * timer) +{ + if(!timer->timer_is_canceled){ + del_timer(&timer->tl); + timer->timer_is_canceled = TRUE; + } +} + +static inline void wlan_sched_timeout(u32 millisec) +{ + unsigned long timeout = 0, expires = 0; + expires = jiffies + msecs_to_jiffies(millisec); + timeout = millisec; + + while(timeout) + { + timeout = schedule_timeout(timeout); + + if(time_after(jiffies, expires)) + break; + } +} + +/* + * OS Thread Specific + */ + +#include + +typedef struct +{ + struct task_struct *task; + struct completion comp; + pid_t pid; + void *priv; +} wlan_thread; + +static inline void +wlan_activate_thread(wlan_thread * thr) +{ + /** Record the thread pid */ + thr->pid = current->pid; + init_completion(&thr->comp); +} + +static inline void +wlan_deactivate_thread(wlan_thread * thr) +{ + ENTER(); + + /* Reset the pid */ + thr->pid = 0; + + LEAVE(); +} + +static inline void +wlan_create_thread(int (*wlanfunc) (void *), wlan_thread * thr, char *name) +{ + thr->task = kthread_run(wlanfunc, thr, "%s", name); +} + +static inline int +wlan_terminate_thread(wlan_thread * thr) +{ + ENTER(); + + /* Check if the thread is active or not */ + if (!thr->pid) { + printk(KERN_INFO "Thread does not exist\n"); + return -1; + } + kthread_stop(thr->task); + + LEAVE(); + return 0; +} + +#endif + diff --git a/drivers/net/wireless/rda/rda_wlan/wlan_rxtx.c b/drivers/net/wireless/rda/rda_wlan/wlan_rxtx.c new file mode 100755 index 00000000..c9f13365 --- /dev/null +++ b/drivers/net/wireless/rda/rda_wlan/wlan_rxtx.c @@ -0,0 +1,289 @@ +#include "wlan_includes.h" + +void wlan_process_rx(wlan_private *priv) +{ + wlan_rx_packet_node * rxNode = NULL; + u8 *payload = NULL, rx_type = 0, msg_type = 0; + u16 rx_len = 0; + struct sk_buff *skb = NULL; + unsigned long flags; + + ENTER(); + + spin_lock_irqsave(&priv->RxLock, flags); + if (list_empty(&priv->RxQueue)) { + priv->RxQuNum=0; + spin_unlock_irqrestore(&priv->RxLock, flags); + return; + } + rxNode = list_first_entry(&priv->RxQueue, struct _wlan_rx_packet_node, List); + list_del(&rxNode->List); + if (priv->RxQuNum > 0) + priv->RxQuNum--; + spin_unlock_irqrestore(&priv->RxLock, flags); + + skb = rxNode->Skb; + payload = skb->data; + + rx_type = payload[1] & 0xf0; + rx_len = skb->len; + + WLAN_DBGLAP(WLAN_DA_TXRX, WLAN_DL_TRACE,"payload len: %d type: %d \n", rx_len, rx_type); + + switch(rx_type){ + case HOST_MSG_CONFIGRSP: + { + msg_type = payload[2]; + + switch (msg_type) { + case 'I': + wlan_mac_status(priv, payload + 2, rx_len - 2); + break; + + case 'R': + wlan_wid_response(priv, payload + 2, rx_len - 2); + break; + + case 'N': + wlan_network_information(priv, payload + 2, rx_len - 2); + break; + + default: + break; + } + } + break; + + case HOST_MSG_DATAIN: + { + skb_pull(skb, WID_HEADER_LEN); + skb->dev = priv->netDev; + skb->protocol = eth_type_trans(skb, priv->netDev); + skb->ip_summed = CHECKSUM_UNNECESSARY; + + { + struct ethhdr *eth; + eth = eth_hdr(skb); + //for wapi should verify packet length + if (ntohs(eth->h_proto) == 0x88b4){ + rx_len = ((skb->data[6]) << 8) | skb->data[7]; + skb->len = rx_len; + } + } + + priv->stats.rx_packets++; + priv->stats.rx_bytes += skb->len; + + WLAN_DBGLAP(WLAN_DA_TXRX, WLAN_DL_TRACE, + "DATA: %02x %02x %02x %02x ... ... %02x %02x %02x %02x\n", + skb->data[0], skb->data[1], skb->data[2], + skb->data[3], skb->data[4], skb->data[5], + skb->data[6], skb->data[7]); + + netif_rx_ni(skb); + goto out_keep_skb; + } + break; + + default: + break; + } + +#ifdef WLAN_RAW_DATA_DEBUG + WLAN_ERRP("%x %x %x %x %x %x %x %x\n", payload[0], payload[1],payload[2],payload[3],payload[4],payload[5],payload[6],payload[7]); + payload += 8; + WLAN_ERRP("%x %x %x %x %x %x %x %x rx_len:%d\n", payload[0], payload[1],payload[2],payload[3],payload[4],payload[5],payload[6],payload[7], rx_len); +#endif + + dev_kfree_skb(skb); + +out_keep_skb: + kfree(rxNode); + LEAVE(); + return; +} + + +int wlan_rx_thread(void *data) +{ + wlan_thread *thread = (wlan_thread *)data; + wlan_private *priv = thread->priv; + + ENTER(); + + wlan_activate_thread(thread); + + current->flags |= PF_NOFREEZE; + + while(1){ + wait_for_completion_interruptible(&thread->comp); + + if (kthread_should_stop()){ + WLAN_DBGLAP(WLAN_DA_TXRX, WLAN_DL_CRIT,"wlan_rx_thread: break from main thread \n"); + break; + } + + if(priv->CardRemoved) + break; + while (priv->RxQuNum) + wlan_process_rx(priv); + } + + wlan_deactivate_thread(thread); + + LEAVE(); + return 0; +} + +int wlan_tx_thread(void *data) +{ + u32 payloadLen = 0; + u8* payload = 0; + wlan_wid_packet_node * widNode = NULL; + wlan_tx_packet_node * txNode = NULL; + wlan_thread *thread = data; + wlan_private *priv = thread->priv; + unsigned long flags = 0; + int tx_queue_max_num =0; + +#ifdef WLAN_RAW_DATA_DEBUG + u8* printStr = NULL, +#endif + ENTER(); + + if (priv->version == WLAN_VERSION_90_D || priv->version == WLAN_VERSION_90_E){ + tx_queue_max_num = WLAN_TX_QUEUE_NUM_90; + } else if (priv->version == WLAN_VERSION_91 || priv->version == WLAN_VERSION_91_E|| priv->version == WLAN_VERSION_91_F) { + tx_queue_max_num = WLAN_TX_QUEUE_NUM_91; + } else { + tx_queue_max_num = WLAN_TX_QUEUE_NUM_90; + } + + wlan_activate_thread(thread); + + current->flags |= PF_NOFREEZE; + + while(1) { + + wait_for_completion_interruptible(&thread->comp); + + if (kthread_should_stop() || priv->CardRemoved) { + WLAN_DBGLAP(WLAN_DA_TXRX, WLAN_DL_CRIT,"wlan_tx_thread: break from main thread \n"); + break; + } + + WLAN_DBGLAP(WLAN_DA_SDIO, WLAN_DL_DEBUG, "Tx Thread wakeup \n"); + + //wid_header_len ---data +++ data_len: whole buf_len= wid_header_len + skb->len + //send data + while(1){ + spin_lock_irqsave(&priv->TxLock, flags); + if(list_empty(&priv->TxQueue)){ + spin_unlock_irqrestore(&priv->TxLock, flags); + wlan_card_enter_sleep(priv); + break; + } + txNode = (wlan_tx_packet_node*)priv->TxQueue.next; + if(txNode){ + list_del(&txNode->List); + spin_unlock_irqrestore(&priv->TxLock, flags); + }else{ + WLAN_ERRP("should not happend!! \n"); + spin_unlock_irqrestore(&priv->TxLock, flags); + break; + } + + if(txNode->type == WLAN_DATA){ + payloadLen = txNode->Skb->len + WID_HEADER_LEN; + payload = txNode->Skb->data - WID_HEADER_LEN; + //the first 2 byte was reserved from hard_header_len + payload[0] = (char)((payloadLen)&0xFF); + payload[1] = (char)(((payloadLen)>>8)&0x0F); + payload[1] |= 0x10; // for DataOut 0x1 + }else if(txNode->type == WLAN_CMD){ + widNode = txNode->wid_node; + if(!widNode->BufLen || !widNode->Buf){ + WLAN_ERRP("WLAN_CMD widNode->BufLen is 0 or widNode->Buf is NULL! \n"); + kfree(txNode); + break; + } + payloadLen = widNode->BufLen + WID_HEADER_LEN; + payload = widNode->Buf; + payload[0] = (char)((payloadLen)&0xFF); + payload[1] = (char)(((payloadLen)>>8)&0x0F); + payload[1] |= 0x40; // for WidRequest 0x40 + if (is_sdio_init_complete()) + init_completion(&priv->widComp); + } else + break; + +#ifdef WLAN_RAW_DATA_DEBUG + printStr = payload; + WLAN_ERRP("&&&send a data Packet to chip length:%d \n", payloadLen); + WLAN_ERRP("%x %x %x %x %x %x %x %x\n", printStr[0], printStr[1], printStr[2], printStr[3], printStr[4], printStr[5], printStr[6], printStr[7]); + printStr += 8; + WLAN_ERRP("%x %x %x %x %x %x %x %x\n", printStr[0], printStr[1], printStr[2], printStr[3], printStr[4], printStr[5], printStr[6], printStr[7]); + printStr += 8; + WLAN_ERRP("%x %x %x %x %x %x %x %x\n", printStr[0], printStr[1], printStr[2], printStr[3], printStr[4], printStr[5], printStr[6], printStr[7]); +#endif + + //for sdio must 4 bytes align + payloadLen = ((payloadLen + 3)/4)*4; // 4 byte align + + if(wlan_write_sdio_2_ahb(priv, IF_SDIO_FUN1_FIFO_WR, payload, payloadLen)){ + if(txNode->type == WLAN_DATA){ + priv->stats.tx_dropped++; + priv->stats.tx_errors++; + } + WLAN_ERRP("wlan_write_bytes: Tx thread write data failed payload:%d \n", payloadLen); + }else{ + WLAN_DBGLAP(WLAN_DA_TXRX, WLAN_DL_DEBUG,"&&& send payload:%d type:%d \n", payloadLen, txNode->type); + + if(txNode->type == WLAN_DATA){ + priv->stats.tx_packets++; + priv->stats.tx_bytes += txNode->Skb->len; + }else{ + int left = 0; + if (!is_sdio_init_complete()) { + if (wlan_read_wid_rsp_polling(priv)) { + } + }else{ + left = wait_for_completion_timeout(&priv->widComp, 5*HZ); + if(!left) + WLAN_ERRP("&&& wait wid cmd time out \n"); + } + } + } + + if(txNode->type == WLAN_DATA){ + if(atomic_read(&(priv->TxQuNum)) > 0){ + atomic_sub(1, &(priv->TxQuNum)); + } + if ((atomic_read(&(priv->netifQuStop)) == 1) + && (atomic_read(&(priv->TxQuNum)) < tx_queue_max_num)) { + atomic_set(&(priv->netifQuStop), 0); + wlan_push_event(priv, WLAN_EVENT_START_NETIF, priv, FALSE); + } + + } + + //no matter it's send success or not we should free the skb buffer + if(txNode->Skb) + dev_kfree_skb(txNode->Skb); + kfree(txNode); + //do not send multi packet in one complete event + break; + } + if(priv->CardInSleep == false) + wlan_mod_timer(&priv->CardToSleepTimer, CARD_ENTER_SLEEP_TIMER); + + + WLAN_DBGLAP(WLAN_DA_SDIO, WLAN_DL_DEBUG, "Tx Thread sleep \n"); + } + + wlan_deactivate_thread(thread); + + LEAVE(); + return 0; +} + diff --git a/drivers/net/wireless/rda/rda_wlan/wlan_scan.c b/drivers/net/wireless/rda/rda_wlan/wlan_scan.c new file mode 100755 index 00000000..1a76dbff --- /dev/null +++ b/drivers/net/wireless/rda/rda_wlan/wlan_scan.c @@ -0,0 +1,429 @@ +#include "wlan_includes.h" + +//#define SCAN_RESULT_DEBUG + +#ifndef FCS_LEN +#define FCS_LEN 4 +#endif + +/* Element ID of various Information Elements */ +typedef enum { + ISSID = 0, /* Service Set Identifier */ + ISUPRATES = 1, /* Supported Rates */ + IFHPARMS = 2, /* FH parameter set */ + IDSPARMS = 3, /* DS parameter set */ + ICFPARMS = 4, /* CF parameter set */ + ITIM = 5, /* Traffic Information Map */ + IIBPARMS = 6, /* IBSS parameter set */ + ICTEXT = 16, /* Challenge Text */ + IERPINFO = 42, /* ERP Information */ + IEXSUPRATES = 50, /* Extended Supported Rates */ + IWAPI =68 +} ELEMENTID_T; + +/* Capability Information field bit assignments */ +typedef enum { + ESS = 0x01, /* ESS capability */ + IBSS = 0x02, /* IBSS mode */ + POLLABLE = 0x04, /* CF Pollable */ + POLLREQ = 0x08, /* Request to be polled */ + PRIVACY = 0x10, /* WEP encryption supported */ + SHORTPREAMBLE = 0x20, /* Short Preamble is supported */ + SHORTSLOT = 0x400, /* Short Slot is supported */ + PBCC = 0x40, /* PBCC */ + CHANNELAGILITY = 0x80, /* Channel Agility */ + SPECTRUM_MGMT = 0x100, /* Spectrum Management */ + DSSS_OFDM = 0x2000 /* DSSS-OFDM */ +} CAPABILITY_T; + +/* BSS type */ +typedef enum { + INFRASTRUCTURE = 1, + INDEPENDENT = 2, + ANY_BSS = 3 +} BSSTYPE_T; + +u8 *get_ie_elem(u8 * msa, ELEMENTID_T elm_id, u16 rx_len, u16 tag_param_offset) +{ + u16 index = 0; + + /*************************************************************************/ + /* Beacon Frame - Frame Body */ + /* --------------------------------------------------------------------- */ + /* |Timestamp |BeaconInt |CapInfo |SSID |SupRates |DSParSet |TIM elm | */ + /* --------------------------------------------------------------------- */ + /* |8 |2 |2 |2-34 |3-10 |3 |4-256 | */ + /* --------------------------------------------------------------------- */ + /* */ + /*************************************************************************/ + + index = tag_param_offset; + + /* Search for the TIM Element Field and return if the element is found */ + while(index < (rx_len - FCS_LEN)) { + if(msa[index] == elm_id){ + return(&msa[index]); + }else{ + index += (2 + msa[index + 1]); + } + } + + return(0); +} + +/* This function extracts the 'from ds' bit from the MAC header of the input */ +/* frame. */ +/* Returns the value in the LSB of the returned value. */ +u8 get_from_ds(u8* header) +{ + return ((header[1] & 0x02) >> 1); +} + +/* This function extracts the 'to ds' bit from the MAC header of the input */ +/* frame. */ +/* Returns the value in the LSB of the returned value. */ +u8 get_to_ds(u8* header) +{ + return (header[1] & 0x01); +} + +/* This function extracts the MAC Address in 'address1' field of the MAC */ +/* header and updates the MAC Address in the allocated 'addr' variable. */ +void get_address1(u8* msa, u8* addr) +{ + memcpy(addr, msa + 4, 6); +} + +/* This function extracts the MAC Address in 'address2' field of the MAC */ +/* header and updates the MAC Address in the allocated 'addr' variable. */ +void get_address2(u8* msa, u8* addr) +{ + memcpy(addr, msa + 10, 6); +} + +/* This function extracts the MAC Address in 'address3' field of the MAC */ +/* header and updates the MAC Address in the allocated 'addr' variable. */ +void get_address3(u8* msa, u8* addr) +{ + memcpy(addr, msa + 16, 6); +} + +/* This function extracts the BSSID from the incoming WLAN packet based on */ +/* the 'from ds' bit, and updates the MAC Address in the allocated 'addr' */ +/* variable. */ +void get_BSSID(u8* data, u8* bssid) +{ + if(get_from_ds(data) == 1) + get_address2(data, bssid); + else if(get_to_ds(data) == 1) + get_address1(data, bssid); + else + get_address3(data, bssid); +} + +void wlan_network_information(wlan_private * priv, u8 * info, u16 info_len) +{ + struct bss_descriptor *iter_bss; + struct bss_descriptor *bss = NULL; + unsigned char *pos, *end, *p; + unsigned char n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0; + struct ieee_ie_country_info_set *pcountryinfo; + + unsigned char* msa = &info[9]; + unsigned short msa_len = info[6] | (info[7] << 8); + +#if 0 + if(priv->scan_running == WLAN_SCAN_IDLE){ + WLAN_ERRP("is not in scan process \n"); + goto done; + } +#endif + + if((msa_len - 1 + 9 ) != info_len){ + WLAN_ERRP("rda5890_network_information verify lengh feild failed \n"); + } + + bss = kzalloc(sizeof(struct bss_descriptor), GFP_KERNEL); + if (bss == NULL) { + WLAN_ERRP("alloc bss_descriptor memory failed \n"); + return; + } + memset(bss, 0, sizeof (struct bss_descriptor)); + bss->rssi = info[8]; + msa_len -= 1; // has rssi + + get_BSSID(msa, bss->bssid); + + end = msa + msa_len; + + //mac head + pos = msa + 24; + //time stamp + pos += 8; + //beacon + bss->beaconperiod = *(pos) | (*(pos + 1) << 8); + pos += 2 ; + //capability + bss->capability = *(pos) | (*(pos + 1) << 8); + pos += 2; + + if (bss->capability & WLAN_CAPABILITY_IBSS) + bss->mode = IW_MODE_ADHOC; + else + bss->mode = IW_MODE_INFRA; + + /* process variable IE */ + while (pos + 2 <= end) { + + if (pos + pos[1] > end) { +#ifdef SCAN_RESULT_DEBUG + WLAN_DBGP("process_bss: error in processing IE, " + "bytes left < IE length\n"); +#endif + kfree(bss); + return; + } + + switch (pos[0]) { + case WLAN_EID_SSID: + bss->ssid_len = min_t(int, IEEE80211_MAX_SSID_LEN, pos[1]); + memcpy(bss->ssid, pos + 2, bss->ssid_len); + + if (priv->scan_ssid_len > 0) { + if (bss->ssid_len != priv->scan_ssid_len) { + kfree(bss); + return; + } + + if (memcmp(bss->ssid, priv->scan_ssid, priv->scan_ssid_len)) { + kfree(bss); + return; + } + } +#ifdef SCAN_RESULT_DEBUG + WLAN_DBGP("got SSID IE: '%s', len %u %d\n", + bss->ssid, bss->ssid_len, pos[1]); +#endif + break; + + case WLAN_EID_SUPP_RATES: + n_basic_rates = min_t(uint8_t, MAX_RATES, pos[1]); + memcpy(bss->rates, pos + 2, n_basic_rates); + got_basic_rates = 1; +#ifdef SCAN_RESULT_DEBUG + WLAN_DBGP("got RATES IE\n"); +#endif + break; + + case WLAN_EID_FH_PARAMS: +#ifdef SCAN_RESULT_DEBUG + WLAN_DBGP("got FH IE\n"); +#endif + break; + + case WLAN_EID_DS_PARAMS: +#ifdef SCAN_RESULT_DEBUG + WLAN_DBGP("got DS IE\n"); +#endif + bss->channel = pos[2]; + break; + + case WLAN_EID_CF_PARAMS: +#ifdef SCAN_RESULT_DEBUG + WLAN_DBGP("got CF IE\n"); +#endif + break; + + case WLAN_EID_IBSS_PARAMS: +#ifdef SCAN_RESULT_DEBUG + WLAN_DBGP("got IBSS IE\n"); +#endif + break; + + case WLAN_EID_COUNTRY: + pcountryinfo = (struct ieee_ie_country_info_set *) pos; +#ifdef SCAN_RESULT_DEBUG + WLAN_DBGP("got COUNTRY IE\n"); +#endif + break; + + case WLAN_EID_EXT_SUPP_RATES: + /* only process extended supported rate if data rate is + * already found. Data rate IE should come before + * extended supported rate IE + */ +#ifdef SCAN_RESULT_DEBUG + WLAN_DBGP("got RATESEX IE\n"); +#endif + if (!got_basic_rates) { +#ifdef SCAN_RESULT_DEBUG + WLAN_DBGP("... but ignoring it\n"); +#endif + break; + } + + n_ex_rates = pos[1]; + if (n_basic_rates + n_ex_rates > MAX_RATES) + n_ex_rates = MAX_RATES - n_basic_rates; + + p = bss->rates + n_basic_rates; + memcpy(p, pos + 2, n_ex_rates); + break; + + case WLAN_EID_GENERIC: + if (pos[1] >= 4 && + pos[2] == 0x00 && pos[3] == 0x50 && + pos[4] == 0xf2 && pos[5] == 0x01) { + bss->wpa_ie_len = min(pos[1] + 2, MAX_WPA_IE_LEN); + bss->wpa_ie = kzalloc(bss->wpa_ie_len, GFP_KERNEL); + if(bss->wpa_ie) + memcpy(bss->wpa_ie, pos, bss->wpa_ie_len); + else + bss->wpa_ie_len = 0; +#ifdef SCAN_RESULT_DEBUG + WLAN_DBGP("got WPA IE \n"); +#endif + } + + /* huanglei add for wps */ + else if(pos[1] >= 4 && + pos[2] == 0x00 && pos[3] == 0x50 && + pos[4] == 0xf2 && pos[5] == 0x04 && + (priv->version == WLAN_VERSION_91_E || priv->version == WLAN_VERSION_91_F)) { + bss->wps_ie_len = min(pos[1] + 2, MAX_WPS_IE_LEN); + bss->wps_ie = kzalloc(bss->wps_ie_len, GFP_KERNEL); + if(bss->wps_ie) + memcpy(bss->wps_ie, pos, bss->wps_ie_len); + else + bss->wps_ie_len = 0; +#ifdef SCAN_RESULT_DEBUG + WLAN_DBGP("got WPS IE \n"); +#endif + } + else { +#ifdef SCAN_RESULT_DEBUG + WLAN_DBGP("got generic IE: %02x:%02x:%02x:%02x, len %d\n", + pos[2], pos[3], pos[4], pos[5], pos[1]); +#endif + } + break; + + case WLAN_EID_RSN: +#ifdef SCAN_RESULT_DEBUG + WLAN_DBGP("got RSN IE\n"); +#endif + bss->rsn_ie_len = min(pos[1] + 2, MAX_WPA_IE_LEN); + bss->rsn_ie = kzalloc(bss->rsn_ie_len, GFP_KERNEL); + if(bss->rsn_ie) + memcpy(bss->rsn_ie, pos, bss->rsn_ie_len); + else + bss->rsn_ie_len = 0; + + break; + + case IWAPI: +#ifdef SCAN_RESULT_DEBUG + WLAN_DBGP("got WAPI IE\n"); +#endif + bss->wapi_ie_len = min(pos[1] + 2, 100); + bss->wapi_ie = kzalloc(bss->wapi_ie_len, GFP_KERNEL); + if(bss->wapi_ie) + memcpy(bss->wapi_ie, pos, bss->wapi_ie_len); + else + bss->wapi_ie_len = 0; + break; + + default: + break; + } + + pos += pos[1] + 2; + } + + bss->last_scanned = jiffies; + + wlan_update_aver_rssi(priv, bss->bssid, bss->rssi); + /* add scaned bss into list */ + if (1) { + struct bss_descriptor *found = NULL; + struct bss_descriptor *oldest = NULL; + struct bss_descriptor *unsed = NULL; + struct bss_descriptor *bss_lower_rssi = NULL; + s8 rssi = 0, lowRssi = 0; + + spin_lock(&priv->ScanListLock); + /* Try to find this bss in the scan table */ + list_for_each_entry(iter_bss, &priv->network_list, list) { + if (is_same_network(iter_bss, bss)) { + found = iter_bss; + break; + } + + if (time_before(iter_bss->last_scanned + DEFAULT_MAX_SCAN_AGE, jiffies)) { + if(!oldest || (oldest->last_scanned > iter_bss->last_scanned)) + oldest = iter_bss; + } + + if (!iter_bss->ssid_len && unsed==NULL ) { + unsed=iter_bss; + break; + } + + if(!is_zero_eth_addr(iter_bss->bssid)){ + rssi = wlan_get_aver_rssi(priv, iter_bss->bssid); + if(bss_lower_rssi == NULL || rssi < lowRssi){ + lowRssi = rssi; + bss_lower_rssi = iter_bss; + if(rssi == INVALID_RSSI) + break; + } + } + } + + if (found) { // have in network list + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_DEBUG, "FOUND SAME %s, update\n", found->ssid); + /* found, clear it */ + clear_bss_descriptor(found); + memcpy(found, bss, offsetof(struct bss_descriptor, list)); + } else { //not have in network list + if (unsed) { + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_DEBUG, + "FOUND NEW %s, add\n", bss->ssid); + clear_bss_descriptor(unsed); + memcpy(unsed, bss, offsetof(struct bss_descriptor, list)); + }else { // do not have space + if(oldest) { // have oldest + printk("**FOUND NEW %s, no space, replace oldest %s\n", + bss->ssid, oldest->ssid); + clear_bss_descriptor(oldest); + memcpy(oldest, bss, offsetof(struct bss_descriptor, list)); + }else if (bss_lower_rssi) { // have lower rssi + printk("**FOUND NEW %s, no space, replace low_rssi %s\n", + bss->ssid, bss_lower_rssi->ssid); + clear_bss_descriptor(bss_lower_rssi); + memcpy(bss_lower_rssi, bss, offsetof(struct bss_descriptor, list)); + }else { // don't have oldest + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_CRIT, "Networklist Oldest is NULL\n"); + } + } + } + spin_unlock(&priv->ScanListLock); + } +#ifdef SCAN_RESULT_DEBUG + WLAN_DBGP("rda5890_network_information .\n"); +#endif + kfree(bss); + return; +} + +void wlan_report_scan_result(wlan_private * priv) +{ + union iwreq_data wrqu; + ENTER(); + priv->scan_running = WLAN_SCAN_COMPLET; + memset(&wrqu, 0, sizeof(union iwreq_data)); + wireless_send_event(priv->netDev, SIOCGIWSCAN, &wrqu, NULL); + wlan_mod_timer(&priv->CardToSleepTimer, 100); + LEAVE(); +} + diff --git a/drivers/net/wireless/rda/rda_wlan/wlan_sdio.c b/drivers/net/wireless/rda/rda_wlan/wlan_sdio.c new file mode 100755 index 00000000..ff456053 --- /dev/null +++ b/drivers/net/wireless/rda/rda_wlan/wlan_sdio.c @@ -0,0 +1,584 @@ +#include "wlan_includes.h" + +extern void rda_mci_enable_sdio_irq(struct mmc_host *mmc, int enable); +void check_sdio_status(wlan_private * priv, int result) +{ +#ifdef CHECK_SDIO_STAUTS + if (result) { + priv->SdioErrorCount++; + if ( !rda_combo_wifi_in_test_mode() && priv->SdioErrorCount > WLAN_SDIO_MAX_ERR) { + wlan_push_event(priv, WLAN_EVENT_CHECK_SDIO, priv, FALSE); + priv->SdioErrorCount = 0; + priv->sdio_need_reset = 1; + } + }else{ + priv->SdioErrorCount = 0; + } +#endif +} + +int wlan_card_check_sdio(wlan_private * priv) +{ + int ret = 0; +#ifdef WLAN_SDIO_RESET_DEBUG + priv->debug_count = 0; +#endif + WLAN_ERRP("###################################################"); + WLAN_ERRP("###################################################"); + WLAN_ERRP("###################################################"); + + wlan_indicate_disconnected(priv); + + ret = wlan_reset_card(priv); + if(ret < 0) + WLAN_ERRP("wlan sdio reset failed"); + priv->sdio_need_reset = 0; + return 0; +} +int wlan_read_byte(wlan_private * priv, u32 addr, u8* data) +{ + wlan_sdio_card *card; + int ret = 0; + + card = (wlan_sdio_card*)priv->card; + + if (!card || !card->func){ + WLAN_ERRP("wlan_read_byte(): card or function is NULL!\n"); + return WLAN_STATUS_FAILED; + } + + *data = sdio_readb(card->func, addr, &ret); + if (ret){ + WLAN_ERRP("wlan_read_byte(): sdio_readb failed! ret=%d\n", ret); + //kevin add ,fix restore factory default. sdio fail too many time! + if(ret == -110){ + WLAN_ERRP("sleep 100 msec\n"); + msleep(100); + } + check_sdio_status(priv, ret); + } + + return ret; +} + +int wlan_write_byte(wlan_private * priv, u32 addr, u8 data) +{ + wlan_sdio_card *card; + int ret = 0; + + card = (wlan_sdio_card*)priv->card; + + if (!card || !card->func){ + WLAN_ERRP("wlan_write_byte(): card or function is NULL!\n"); + return WLAN_STATUS_FAILED; + } + + sdio_writeb(card->func, data, addr, &ret); + if (ret){ + WLAN_ERRP("wlan_write_byte(): sdio_writeb failed! ret=%d\n", ret); + check_sdio_status(priv, ret); + } + + return ret; +} + +int wlan_read_bytes(wlan_private * priv, u32 addr, u8* buf, u32 count) +{ + wlan_sdio_card *card; + int ret = 0; + + card = (wlan_sdio_card*)priv->card; + + if (!card || !card->func){ + WLAN_ERRP("wlan_read_bytes(): card or function is NULL!\n"); + return WLAN_STATUS_FAILED; + } + + ret = sdio_readsb(card->func, buf, addr, count); + if (ret){ + WLAN_ERRP("wlan_read_bytes(): sdio_readsb failed! ret=%d\n", ret); + check_sdio_status(priv, ret); + }else{ + WLAN_DBGLAP(WLAN_DA_SDIO, WLAN_DL_DEBUG, "wlan_read_bytes :len %d\n", count); + } + + return ret; +} + +int wlan_write_sdio_2_ahb(wlan_private * priv, u32 addr, u8* buf, u32 count) +{ + wlan_sdio_card *card; + int ret = 0; + u16 size = 0; + u8 size_l = 0, size_h = 0; + u16 bytes_left = 0, offset = 0, batch = 0; +#ifdef RDA_ANDROID_PLATFORM + u32 blockSize = 4, nb = 0; + u8 *packet_to_send = NULL; + struct page *pg = NULL; +#endif + card = (wlan_sdio_card*)priv->card; + + if (!card || !card->func ){ + WLAN_ERRP("wlan_read_byte(): card or function is NULL!\n"); + return WLAN_STATUS_FAILED; + } + + if(rda_combo_wifi_in_test_mode() && is_sdio_init_complete()){ + return WLAN_STATUS_SUCCESS; + } + + if (priv->version == WLAN_VERSION_90_D + || priv->version == WLAN_VERSION_90_E) { + ret = wlan_sdio_flow_ctrl_90(priv); + if(ret){ + WLAN_ERRP("wlan_sdio_flow_ctrl 5990 failed! \n"); + return ret; + } + } else if(priv->version == WLAN_VERSION_91){ + ret = wlan_sdio_flow_ctrl_91(priv); + if(ret){ + WLAN_ERRP("wlan_sdio_flow_ctrl 5991 failed! \n"); + return ret; + } + }else if (priv->version == WLAN_VERSION_91_E) { + ret = wlan_sdio_flow_ctrl_91e(priv); + if (ret) { + WLAN_ERRP("wlan_sdio_flow_ctrl 5991e failed! \n"); + return ret; + } + }else if (priv->version == WLAN_VERSION_91_F) { + ret = wlan_sdio_flow_ctrl_91e(priv); + if (ret) { + WLAN_ERRP("wlan_sdio_flow_ctrl 5991f failed! \n"); + return ret; + } + } else { + WLAN_ERRP("wlan_sdio_flow_ctrl unkown version:%d\n",priv->version); + return ret; + } + +// IN rda android platform sdio should 2^n alligen +#ifdef RDA_ANDROID_PLATFORM + if(count > card->func->cur_blksize){//the left bytes should be 2^n alligen + nb = count%(card->func->cur_blksize); + count -= nb; + while (blockSize < nb ){ + blockSize = blockSize << 1; + } + count += blockSize; + blockSize = count; + } else { + while (blockSize < count){ + blockSize = blockSize << 1; + } + } + size = blockSize/4; + count = blockSize; + WLAN_DBGLAP(WLAN_DA_SDIO, WLAN_DL_DEBUG,"wlan_write_sdio_2_ahb size:%d %d cur_blk:%d\n",count, blockSize, card->func->cur_blksize); +#else + size = count/4; +#endif + size_l = size & 0xff; + size_h = ((size >> 8) & 0x7f) | 0x80; //0x80 flags means lenght higer bytes + + sdio_claim_host(card->func); + ret = wlan_write_byte(priv, IF_SDIO_SDIO2AHB_PKTLEN_L, size_l); + if(ret){ + WLAN_ERRP("SDIO write size_l failed! \n"); + goto out; + } + + ret = wlan_write_byte(priv, IF_SDIO_SDIO2AHB_PKTLEN_H, size_h); + if(ret){ + WLAN_ERRP("SDIO write size_h failed! \n"); + goto out; + } + + bytes_left = count; + while(bytes_left){ + batch = bytes_left > card->func->cur_blksize?card->func->cur_blksize:bytes_left; +#ifdef RDA_ANDROID_PLATFORM + { + packet_to_send = buf + offset; + + if (((u32)packet_to_send >> PAGE_SHIFT) != + (((u32)packet_to_send + batch - 1) >> PAGE_SHIFT)){ + + pg = alloc_page(GFP_KERNEL); + if(!pg){ + ret = -1; + break; + } + memcpy(page_address(pg), packet_to_send, batch); + packet_to_send = page_address(pg); + + ret = sdio_writesb(card->func, addr, packet_to_send, batch); + __free_page(pg); + WLAN_ERRP("wlan data cross page boundary addr:%x size:%x \n", (u32)(buf + offset), batch); + }else + ret = sdio_writesb(card->func, addr, packet_to_send, batch); + } +#else + ret = sdio_writesb(card->func, addr, buf + offset, batch); +#endif + if (ret){ + WLAN_ERRP("SDIO sdio_writesb failed! ret=%d len:%d \n", ret, size*4); + break; + } + offset += batch; + bytes_left -= batch; + } +#ifdef WLAN_SDIO_RESET_DEBUG + priv->debug_count++; +#endif +out: + sdio_release_host(card->func); +#ifdef WLAN_SDIO_RESET_DEBUG + WLAN_DBGLAP(WLAN_DA_SDIO, WLAN_DL_DEBUG, "########### len %d debug_count:%d #######********\n", size * 4, priv->debug_count); + if(priv->debug_count > 300) + ret = -5; +#endif + if (ret) + check_sdio_status(priv, ret); + return ret; +} + +int wlan_wake_up_card(wlan_private * priv) +{ + int ret = 0; +#ifdef WLAN_POWER_MANAGER + wlan_sdio_card *card = (wlan_sdio_card*)priv->card; +#endif + + ENTER(); +#ifdef WLAN_POWER_MANAGER + if (!rda_combo_wifi_in_test_mode()){ + atomic_set(&priv->CardNeedSleep, FALSE); + if(priv->CardInSleep) { + WLAN_DBGLAP(WLAN_DA_PM, WLAN_DL_DEBUG, "wake up card \n"); + sdio_claim_host(card->func); + ret = wlan_write_byte(priv, IF_SDIO_FUN1_INT_TO_DEV, 1); + sdio_release_host(card->func); + if(ret){ + WLAN_ERRP("wakeup card failed \n"); + }else{ + priv->CardInSleep = FALSE; + WLAN_DBGLAP(WLAN_DA_PM, WLAN_DL_DEBUG, + "CardInSleep = FALSE \n"); + wlan_sched_timeout(10); + } + + if (!priv->CardSleepWakeLockOn) { + priv->CardSleepWakeLockOn = TRUE; + wake_lock(&priv->CardSleepTimerLock); + } + } + } +#endif + LEAVE(); + return ret; +} + +void handle_card_to_sleep_cmd(wlan_private * priv) +{ + atomic_set(&priv->CardNeedSleep, TRUE); + complete(&priv->TxThread.comp); +} +int wlan_card_enter_sleep(wlan_private * priv) +{ + int ret = 0; +#ifdef WLAN_POWER_MANAGER + wlan_sdio_card *card = (wlan_sdio_card *) priv->card; +#endif + + ENTER(); + +#ifdef WLAN_POWER_MANAGER + if (!rda_combo_wifi_in_test_mode() + && priv->wlan_pm_enable + && (priv->scan_running != WLAN_SCAN_RUNNING) + && (!priv->assoc_ongoing)) { + if(atomic_read(&priv->CardNeedSleep)) { + sdio_claim_host(card->func); + ret = wlan_write_byte(priv, IF_SDIO_FUN1_INT_PEND, IF_SDIO_HOST_TX_FLAG); + sdio_release_host(card->func); + if (ret) { + WLAN_ERRP("enter sleep failed \n"); + wlan_mod_timer(&priv->CardToSleepTimer, CARD_ENTER_SLEEP_TIMER); + return ret; + } else { + priv->CardInSleep = TRUE; + WLAN_DBGLAP(WLAN_DA_PM, WLAN_DL_DEBUG, "CardInSleep = TRUE \n"); + atomic_set(&priv->CardNeedSleep, FALSE); + } + if (priv->CardSleepWakeLockOn) { + wake_unlock(&priv->CardSleepTimerLock); + priv->CardSleepWakeLockOn = FALSE; + } + if(!(priv->CardToSleepTimer).timer_is_canceled) + wlan_cancel_timer(&priv->CardToSleepTimer); + + WLAN_DBGLAP(WLAN_DA_SDIO, WLAN_DL_DEBUG, "card enter sleep \n"); + } else { + wlan_mod_timer(&priv->CardToSleepTimer, CARD_ENTER_SLEEP_TIMER); + } + } + +#endif + LEAVE(); + return ret; +} +#ifdef WLAN_FLOW_CTRL_90E +int wlan_sdio_flow_ctrl_90(wlan_private * priv) +{ + int ret = 0; + u8 status = 0; + s32 int_sleep_count = 0; + wlan_sdio_card *card = (wlan_sdio_card *) priv->card; + + ENTER(); + wlan_wake_up_card(priv); + while ((!priv->CardRemoved) && is_sdio_patch_complete()) { + sdio_claim_host(card->func); + ret = wlan_read_byte(priv, IF_SDIO_FUN1_INT_PEND, &status); + sdio_release_host(card->func); + if (ret) { + WLAN_ERRP("wlan read IF_SDIO_FUN1_INT_PEND failed \n"); + schedule(); + continue; + } + if ((status & IF_SDIO_INT_SLEEP) == 0) { // If SDIO can't write + if (int_sleep_count >= FLOW_CTRL_INT_SLEEP_RETRY_COUNT_90){ + WLAN_ERRP("Flow_ctrl:max int_sleep_count:%d\n",int_sleep_count); + complete(&priv->RxThread.comp); + msleep(100); + break; + } else { + int_sleep_count++; + } + } else { + if (int_sleep_count > 10) + WLAN_ERRP("Flow_ctrl:int_sleep_count:%d\n",int_sleep_count); + sdio_claim_host(card->func); + ret = wlan_write_byte(priv, IF_SDIO_FUN1_INT_PEND, IF_SDIO_INT_SLEEP); + sdio_release_host(card->func); + break; + } + schedule(); + } + LEAVE(); + return ret; +} +#else +//return 0 success +int wlan_sdio_flow_ctrl_90(wlan_private * priv) +{ + int ret = -1; + u8 status = 0; + s32 count = 0; + wlan_sdio_card * card = (wlan_sdio_card*)priv->card; + + //first wake up card if needed + wlan_wake_up_card(priv); + + + ENTER(); + + while(!priv->CardRemoved){ + sdio_claim_host(card->func); + ret = wlan_read_byte(priv,IF_SDIO_FUN1_INT_PEND, &status); + sdio_release_host(card->func); + if(status & IF_SDIO_INT_RXCMPL) + WLAN_DBGLAP(WLAN_DA_SDIO, WLAN_DL_DEBUG, "IF_SDIO_FUN1_INT_PEND:count count %d : %x \n",count, status); + if(!ret){ + if((status & IF_SDIO_INT_RXCMPL) == 0){ //flows ctrl failed + if(count > FLOW_CTRL_RXCMPL_RETRY_COUNT_90){ + sdio_claim_host(card->func); + wlan_write_byte( priv, IF_SDIO_FUN1_INT_PEND, 0x40); + sdio_release_host(card->func); + complete(&priv->RxThread.comp); + msleep(100); + ret = 0; + WLAN_DBGLAP(WLAN_DA_SDIO, WLAN_DL_CRIT, + "flows ctrl RXCMPL failed, count:%d over,return back \n", + FLOW_CTRL_RXCMPL_RETRY_COUNT_90); + break; + } else { + count ++ ; + } + }else{ + sdio_claim_host(card->func); + ret = wlan_write_byte( priv, IF_SDIO_FUN1_INT_PEND, 0x40); + sdio_release_host(card->func); + if(!ret){ + break; + } + } + } + schedule(); + } + + LEAVE(); + return ret; +} +#endif + +//return 0 success +int wlan_sdio_flow_ctrl_91(wlan_private * priv) +{ + int ret = 0; + u8 status = 0; + s32 int_sleep_count = 0; + wlan_sdio_card * card = (wlan_sdio_card*)priv->card; + + ENTER(); + + //first wake up card if needed + wlan_wake_up_card(priv); + + + + while ((!priv->CardRemoved) && is_sdio_patch_complete()) { + sdio_claim_host(card->func); + ret = wlan_read_byte(priv,IF_SDIO_FUN1_INT_PEND, &status); + sdio_release_host(card->func); + if(ret){ + WLAN_ERRP("wlan read IF_SDIO_FUN1_INT_PEND failed \n"); + schedule(); + continue; + } + + if ((status & IF_SDIO_INT_SLEEP) == 0) { // If SDIO can't write + if (int_sleep_count >= FLOW_CTRL_INT_SLEEP_RETRY_COUNT_91){ + break; + } else { + int_sleep_count++; + } + }else{ + sdio_claim_host(card->func); + ret = wlan_write_byte(priv, IF_SDIO_FUN1_INT_PEND, IF_SDIO_INT_SLEEP); + sdio_release_host(card->func); + break; + + } + if(int_sleep_count < 20) + udelay(10); + else + msleep(1); + } + LEAVE(); + return ret; +} +#ifndef FLOWCTRL_91E +//return 0 success +//int seq_num =0; +int wlan_sdio_flow_ctrl_91e(wlan_private * priv) +{ + int ret = -1; + u8 status = 0; + s32 count = 0; + wlan_sdio_card *card = (wlan_sdio_card *) priv->card; + + wlan_wake_up_card(priv); + + ENTER(); + + while (!priv->CardRemoved) { + sdio_claim_host(card->func); + ret = wlan_read_byte(priv, IF_SDIO_FUN1_INT_PEND, &status); + sdio_release_host(card->func); + if (status & IF_SDIO_INT_RXCMPL) + WLAN_DBGLAP(WLAN_DA_SDIO, WLAN_DL_DEBUG, "IF_SDIO_FUN1_INT_PEND:count count %d : %x \n", count, status); + if (!ret) { + if ((status & IF_SDIO_INT_RXCMPL) == 0) { //flows ctrl failed + if (count > FLOW_CTRL_RXCMPL_RETRY_COUNT_91) { + sdio_claim_host(card->func); + wlan_write_byte(priv, IF_SDIO_FUN1_INT_PEND, 0x40); + sdio_release_host(card->func); + complete(&priv->RxThread.comp); + //msleep(100); + ret = 0; + //seq_num++; + //if(count>4) + //printk("count is %d,seq is %d,sleep_st is %d\n",count,seq_num,priv->CardInSleep); + break; + } else { + count++; + } + //schedule(); + if(count < 20) + udelay(2); + else + msleep(1); + } else { + sdio_claim_host(card->func); + ret = wlan_write_byte(priv, IF_SDIO_FUN1_INT_PEND,0x40); + sdio_release_host(card->func); + //seq_num++; + //if(count>5) + //printk("count is %d,seq is %d,sleep_st is %d\n",count,seq_num,priv->CardInSleep); + if (!ret) { + break; + } + } + } + //schedule(); + + } + + LEAVE(); + return ret; +} +#else +//int seq_num =0; +//return 0 success +int wlan_sdio_flow_ctrl_91e(wlan_private * priv) +{ + int ret = 0; + u8 status = 0; + s32 int_sleep_count = 0; + wlan_sdio_card *card = (wlan_sdio_card *) priv->card; + + ENTER(); + + wlan_wake_up_card(priv); + + while ((!priv->CardRemoved) && is_sdio_patch_complete()) { + sdio_claim_host(card->func); + ret = wlan_read_byte(priv, IF_SDIO_FUN1_INT_PEND, &status); + sdio_release_host(card->func); + if (ret) { + WLAN_ERRP("wlan read IF_SDIO_FUN1_INT_PEND failed \n"); + schedule(); + continue; + } + + if ((status & IF_SDIO_INT_SLEEP) == 0) { // If SDIO can't write + if (int_sleep_count >= FLOW_CTRL_INT_SLEEP_RETRY_COUNT_91){ + //seq_num++; + //printk("count is %d,seq is %d,sleep_st is %d\n",int_sleep_count,seq_num,priv->CardInSleep); + break; + } else { + int_sleep_count++; + } + } else { + + //seq_num++; + //if(int_sleep_count > 10) + // printk("count is %d,seq is %d,sleep_st is %d\n",int_sleep_count,seq_num,priv->CardInSleep); + sdio_claim_host(card->func); + ret = wlan_write_byte(priv, IF_SDIO_FUN1_INT_PEND, IF_SDIO_INT_SLEEP); + sdio_release_host(card->func); + break; + } + if(int_sleep_count < 20) + udelay(10); + else + msleep(1); + } + LEAVE(); + return ret; +} +#endif + diff --git a/drivers/net/wireless/rda/rda_wlan/wlan_sdio.h b/drivers/net/wireless/rda/rda_wlan/wlan_sdio.h new file mode 100755 index 00000000..8306e695 --- /dev/null +++ b/drivers/net/wireless/rda/rda_wlan/wlan_sdio.h @@ -0,0 +1,42 @@ +#ifndef _RDA5890_IF_SDIO_H +#define _RDA5890_IF_SDIO_H +#include + +#define IF_SDIO_SDIO2AHB_PKTLEN_L 0x00 +#define IF_SDIO_SDIO2AHB_PKTLEN_H 0x01 + +#define IF_SDIO_AHB2SDIO_PKTLEN_L 0x02 +#define IF_SDIO_AHB2SDIO_PKTLEN_H 0x03 + +#define IF_SDIO_FUN1_INT_MASK 0x04 +#define IF_SDIO_FUN1_INT_PEND 0x05 +#define IF_SDIO_FUN1_INT_STAT 0x06 + +#define IF_SDIO_INT_AHB2SDIO 0x01 +#define IF_SDIO_INT_ERROR 0x04 +#define IF_SDIO_INT_SLEEP 0x10 +#define IF_SDIO_INT_AWAKE 0x20 +#define IF_SDIO_INT_RXCMPL 0x40 +#define IF_SDIO_HOST_TX_FLAG 0x80 + +#define IF_SDIO_FUN1_FIFO_WR 0x07 +#define IF_SDIO_FUN1_FIFO_RD 0x08 + +#define IF_SDIO_FUN1_INT_TO_DEV 0x09 + +int wlan_card_check_sdio(wlan_private * priv); +int wlan_read_byte(wlan_private * priv, u32 addr, u8* data); +int wlan_write_byte(wlan_private * priv, u32 addr, u8 data); +int wlan_read_bytes(wlan_private * priv, u32 addr, u8* buf, u32 count); +int wlan_write_sdio_2_ahb(wlan_private * priv, u32 addr, u8* buf, u32 count); +int wlan_wake_up_card(wlan_private * priv); +int wlan_card_enter_sleep(wlan_private * priv); +void handle_card_to_sleep_cmd(wlan_private * priv); +int wlan_sdio_flow_ctrl_90(wlan_private * priv); +int wlan_sdio_flow_ctrl_91(wlan_private * priv); +int wlan_sdio_flow_ctrl_91e(wlan_private * priv); +int sdio_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr); +int sdio_select_card(struct mmc_host *host, struct mmc_card *card); +int sdio_send_relative_addr(struct mmc_host *host, unsigned int *rca); +#endif + diff --git a/drivers/net/wireless/rda/rda_wlan/wlan_sdio_patch.c b/drivers/net/wireless/rda/rda_wlan/wlan_sdio_patch.c new file mode 100755 index 00000000..24842297 --- /dev/null +++ b/drivers/net/wireless/rda/rda_wlan/wlan_sdio_patch.c @@ -0,0 +1,429 @@ +#include "wlan_includes.h" +#include "wlan_sdio_patch_90.h" +#include "wlan_sdio_patch_91.h" +#include "wlan_sdio_patch_91e.h" +#include "wlan_sdio_patch_91f.h" + +static u8 sdio_patch_complete = 0; +static atomic_t sdio_init_complete = ATOMIC_INIT(0); + +int wlan_get_fw_version_polling(wlan_private *priv, u32* version) +{ + int ret = 0; + + ENTER(); + + ret = wlan_generic_get_ulong(priv, WID_SYS_FW_VER, (u8*)version); + if (ret) { + WLAN_ERRP("get version failed \n"); + goto out; + } + + WLAN_ERRP("version %x \n", *version); + +out: + LEAVE(); + return ret; +} + +int wlan_write_sdio32_polling(wlan_private * priv, const u32(*data)[2], + u32 size) +{ + int count = size, index = 0; + int ret = 0; + + ENTER(); + //each time write five init data + for(index = 0; index < count/8; index ++){ + ret = wlan_set_core_init_patch(priv, (const unsigned int (*)[2])&data[8*index][0], 8); + if(ret) + goto err; + WLAN_DBGLAP(WLAN_DA_PM, WLAN_DL_DEBUG, "index:%d\n", index); + } + + if(count%8 > 0){ + ret = wlan_set_core_init_patch(priv, (const unsigned int (*)[2])&data[8*index][0], count%8); + if(ret) + goto err; + } +err: + LEAVE(); + return ret; +} + +int wlan_write_sdio8_polling(wlan_private *priv, const u8 (*data)[2], u32 size) +{ + int count = size, index = 0; + int ret = 0; + + ENTER(); + //each time write five init data + for(index = 0; index < count/8; index ++){ + WLAN_DBGLAP(WLAN_DA_PM, WLAN_DL_DEBUG, "index:%d\n", index); + ret = wlan_set_core_patch(priv, (const unsigned char (*)[2])data[8*index], 8); + if(ret) + goto err; + } + + if(count%8 > 0){ + ret = wlan_set_core_patch(priv, (const unsigned char (*)[2])data[8*index], count%8); + if(ret) + goto err; + } + +err: + LEAVE(); + return ret; +} + +int wlan_sdio_patch_core_32(wlan_private *priv) +{ + int ret = 0; + + ENTER(); + + if (priv->version == WLAN_VERSION_90_D) { + ret = wlan_write_sdio32_polling(priv, wifi_core_patch_data_32_90_D, + sizeof(wifi_core_patch_data_32_90_D) / + sizeof(wifi_core_patch_data_32_90_D[0])); + } else if (priv->version == WLAN_VERSION_90_E) { + ret = wlan_write_sdio32_polling(priv, wifi_core_patch_data_32_90_E, + sizeof(wifi_core_patch_data_32_90_E) / + sizeof(wifi_core_patch_data_32_90_E[0])); + } else if (priv->version == WLAN_VERSION_91) { + ret = wlan_write_sdio32_polling(priv, wifi_core_patch_data_32_91, + sizeof(wifi_core_patch_data_32_91)/ + sizeof(wifi_core_patch_data_32_91[0])); + + ret = wlan_write_sdio32_polling(priv, wifi_clock_switch_91, + sizeof(wifi_clock_switch_91) / + sizeof(wifi_clock_switch_91[0])); + }else if (priv->version == WLAN_VERSION_91_E) { + ret = wlan_write_sdio32_polling(priv, wifi_core_patch_data_32_91e, + sizeof(wifi_core_patch_data_32_91e)/ + sizeof(wifi_core_patch_data_32_91e[0])); + + ret = wlan_write_sdio32_polling(priv, wifi_clock_switch_91e, + sizeof(wifi_clock_switch_91e) / + sizeof(wifi_clock_switch_91e[0])); + }else if (priv->version == WLAN_VERSION_91_F) { + ret = wlan_write_sdio32_polling(priv, wifi_core_patch_data_32_91f, + sizeof(wifi_core_patch_data_32_91f)/ + sizeof(wifi_core_patch_data_32_91f[0])); + ret = wlan_write_sdio32_polling(priv, wifi_clock_switch_91f, + sizeof(wifi_clock_switch_91f) / + sizeof(wifi_clock_switch_91f[0])); + } + LEAVE(); + return ret; +} + +int wlan_sdio_init_core_polling(wlan_private *priv) +{ + int ret = 0; + + ENTER(); + if(priv->version == WLAN_VERSION_90_D) + ret = wlan_write_sdio32_polling(priv, wifi_core_init_data_32_90_D, + sizeof(wifi_core_init_data_32_90_D) / + sizeof(wifi_core_init_data_32_90_D[0])); + else if(priv->version == WLAN_VERSION_90_E) + ret = wlan_write_sdio32_polling(priv, wifi_core_init_data_32_90_E, + sizeof(wifi_core_init_data_32_90_E) / + sizeof(wifi_core_init_data_32_90_E[0])); + else if(priv->version == WLAN_VERSION_91){ + ret = wlan_write_sdio32_polling(priv, wifi_core_init_data_32_91, + sizeof(wifi_core_init_data_32_91) / + sizeof(wifi_core_init_data_32_91[0])); + ret = wlan_write_sdio32_polling(priv, wifi_core_AM_PM_data_32_91, + sizeof(wifi_core_AM_PM_data_32_91)/ + sizeof(wifi_core_AM_PM_data_32_91[0])); + }else if (priv->version == WLAN_VERSION_91_E) { + ret = wlan_write_sdio32_polling(priv, wifi_core_init_data_32_91e, + sizeof(wifi_core_init_data_32_91e) / + sizeof(wifi_core_init_data_32_91e[0])); + ret = wlan_write_sdio32_polling(priv, wifi_core_AM_PM_data_32_91e, + sizeof(wifi_core_AM_PM_data_32_91e)/ + sizeof(wifi_core_AM_PM_data_32_91e[0])); + }else if (priv->version == WLAN_VERSION_91_F) { + ret = wlan_write_sdio32_polling(priv, wifi_core_init_data_32_91f, + sizeof(wifi_core_init_data_32_91f) / + sizeof(wifi_core_init_data_32_91f[0])); + ret = wlan_write_sdio32_polling(priv, wifi_core_AM_PM_data_32_91f, + sizeof(wifi_core_AM_PM_data_32_91f)/ + sizeof(wifi_core_AM_PM_data_32_91f[0])); + } + LEAVE(); + return ret; +} + +int wlan_sdio_core_wake_mode_polling(wlan_private *priv) +{ + int ret = 0; + + if (priv->version == WLAN_VERSION_91 || priv->version == WLAN_VERSION_91_E || priv->version == WLAN_VERSION_91_F) + return 0; + + ret = wlan_write_sdio32_polling(priv, wifi_core_data_wake, + sizeof(wifi_core_data_wake) / + sizeof(wifi_core_data_wake[0])); + return ret; +} + +int wlan_sdio_patch_core_8_polling(wlan_private *priv) +{ + int ret = 0; + //for patch in byte mode + + ENTER(); + + if (priv->version == WLAN_VERSION_90_D + || priv->version == WLAN_VERSION_90_E) { + ret = wlan_write_sdio8_polling(priv, wifi_core_patch_data_90_8, + sizeof(wifi_core_patch_data_90_8) / + sizeof(wifi_core_patch_data_90_8[0])); + if(ret) + goto err; + }else if(priv->version == WLAN_VERSION_91){ + ret = wlan_write_sdio8_polling(priv, wifi_core_patch_data_91_8, + sizeof(wifi_core_patch_data_91_8)/ + sizeof(wifi_core_patch_data_91_8[0])); + if (ret) + goto err; + }else if (priv->version == WLAN_VERSION_91_E) { + ret = wlan_write_sdio8_polling(priv, wifi_core_patch_data_91e_8, + sizeof(wifi_core_patch_data_91e_8)/ + sizeof(wifi_core_patch_data_91e_8[0])); + if(ret) + goto err; + }else if (priv->version == WLAN_VERSION_91_F) { + ret = wlan_write_sdio8_polling(priv, wifi_core_patch_data_91f_8, + sizeof(wifi_core_patch_data_91f_8)/ + sizeof(wifi_core_patch_data_91f_8[0])); + if (ret) + goto err; + } + + //for patch in wake continue clock mode + ret = wlan_sdio_core_wake_mode_polling(priv); + if(ret) + goto err; + +err: + LEAVE(); + return ret; +} + +int wlan_sdio_set_default_notch_polling(wlan_private *priv) +{ + int ret = 0; + + ENTER(); + + if (priv->version == WLAN_VERSION_91 || priv->version == WLAN_VERSION_91_E || priv->version == WLAN_VERSION_91_F) + return 0; + + if(priv->version == WLAN_VERSION_90_D) + ret = wlan_write_sdio32_polling(priv, wifi_notch_data_90_D, + sizeof(wifi_notch_data_90_D) / + sizeof(wifi_notch_data_90_D[0])); + else if(priv->version == WLAN_VERSION_90_E) + ret = wlan_write_sdio32_polling(priv, wifi_notch_data_90_E, + sizeof(wifi_notch_data_90_E) / + sizeof(wifi_notch_data_90_E[0])); + LEAVE(); + + return ret; +} + +extern void rda_mci_enable_sdio_irq(struct mmc_host *mmc, int enable); +int wlan_sdio_init(wlan_private *priv) +{ + int ret = 0; + + atomic_set(&sdio_init_complete, 0); + sdio_patch_complete = 0; + + ret = wlan_sdio_patch_core_32(priv); + if(ret < 0) + goto err; + + + sdio_patch_complete = 1; + wlan_sched_timeout(10); //10ms delay + + ret = wlan_sdio_init_core_polling(priv); + if(ret) + goto err; + + ret = wlan_sdio_patch_core_8_polling(priv); + if(ret < 0) + goto err; + + ret = wlan_sdio_set_default_notch_polling(priv); + if(ret < 0) + goto err; + + atomic_set(&sdio_init_complete, 1); + //wlan_register_host_wake_irq(priv); + rda_mci_enable_sdio_irq(priv->MmcCard->host, 1); + priv->sdio_irq_enable = TRUE; + +err: + return ret; +} + +u8 is_sdio_init_complete(void) +{ + return atomic_read(&sdio_init_complete); +} +u8 is_sdio_patch_complete(void) //after patch complete need check write flow +{ + return sdio_patch_complete; + + + +} + +int wlan_set_test_mode(wlan_private *priv) +{ + int ret = 0; + ENTER(); + atomic_set(&sdio_init_complete, 0); + sdio_patch_complete = 0; + ret = wlan_sdio_patch_core_32(priv); + if(ret) + goto err; + + sdio_patch_complete = 1; + + if (priv->version == WLAN_VERSION_90_D + || priv->version == WLAN_VERSION_90_E) { + ret = wlan_write_sdio8_polling(priv, wifi_core_patch_data_90_8, + sizeof(wifi_core_patch_data_90_8)/ + sizeof(wifi_core_patch_data_90_8[0])); + if(ret) + goto err; + }else if(priv->version == WLAN_VERSION_91){ + ret = wlan_write_sdio32_polling(priv, wifi_core_init_data_32_91, + sizeof(wifi_core_init_data_32_91) / + sizeof(wifi_core_init_data_32_91[0])); + if (ret) + goto err; + ret = wlan_write_sdio32_polling(priv, wifi_core_AM_PM_data_32_91, + sizeof(wifi_core_AM_PM_data_32_91)/ + sizeof(wifi_core_AM_PM_data_32_91[0])); + if (ret) + goto err; + ret = wlan_write_sdio8_polling(priv, wifi_core_patch_data_91_8, + sizeof(wifi_core_patch_data_91_8)/ + sizeof(wifi_core_patch_data_91_8[0])); + if(ret) + goto err; + + }else if (priv->version == WLAN_VERSION_91_E) { + ret = wlan_write_sdio32_polling(priv, wifi_core_init_data_32_91e, + sizeof(wifi_core_init_data_32_91e) / + sizeof(wifi_core_init_data_32_91e[0])); + if(ret) + goto err; + ret = wlan_write_sdio32_polling(priv, wifi_core_AM_PM_data_32_91e, + sizeof(wifi_core_AM_PM_data_32_91e)/ + sizeof(wifi_core_AM_PM_data_32_91e[0])); + if(ret) + goto err; + + ret = wlan_write_sdio8_polling(priv, wifi_core_patch_data_91e_8, + sizeof(wifi_core_patch_data_91e_8)/ + sizeof(wifi_core_patch_data_91e_8[0])); + if(ret) + goto err; + }else if (priv->version == WLAN_VERSION_91_F) { + ret = wlan_write_sdio32_polling(priv, wifi_core_init_data_32_91f, + sizeof(wifi_core_init_data_32_91f) / + sizeof(wifi_core_init_data_32_91f[0])); + if (ret) + goto err; + ret = wlan_write_sdio32_polling(priv, wifi_core_AM_PM_data_32_91f, + sizeof(wifi_core_AM_PM_data_32_91f)/ + sizeof(wifi_core_AM_PM_data_32_91f[0])); + if (ret) + goto err; + ret = wlan_write_sdio8_polling(priv, wifi_core_patch_data_91f_8, + sizeof(wifi_core_patch_data_91f_8)/ + sizeof(wifi_core_patch_data_91f_8[0])); + if (ret) + goto err; + } + if (priv->version == WLAN_VERSION_90_D + || priv->version == WLAN_VERSION_90_E) { + ret = wlan_write_sdio32_polling(priv, wlan_test_mode_digital32_90, + sizeof(wlan_test_mode_digital32_90) / + sizeof(wlan_test_mode_digital32_90[0])); + if(ret) + goto err; + } + if (priv->version == WLAN_VERSION_90_D + || priv->version == WLAN_VERSION_90_E) { + ret = wlan_write_sdio32_polling(priv, + wifi_test_mode_agc_patch32_90, + sizeof(wifi_test_mode_agc_patch32_90) / + sizeof(wifi_test_mode_agc_patch32_90[0])); + if(ret) + goto err; + } + + if (priv->version == WLAN_VERSION_90_D + || priv->version == WLAN_VERSION_90_E) { + ret = wlan_write_sdio32_polling(priv, + wifi_test_mode_rx_notch_32_90, + sizeof(wifi_test_mode_rx_notch_32_90) / + sizeof(wifi_test_mode_rx_notch_32_90[0])); + if(ret) + goto err; + } + + ret = wlan_sdio_set_default_notch_polling(priv); + if(ret) + goto err; + + atomic_set(&sdio_init_complete, 1); + rda_mci_enable_sdio_irq(priv->MmcCard->host, 1); + priv->sdio_irq_enable = TRUE; + +err: + + LEAVE(); + return ret; +} +int wlan_assoc_power_save(wlan_private * priv) +{ + int ret = 0; + ENTER(); + if (priv->version == WLAN_VERSION_91){ + ret = wlan_set_core_init_patch(priv, wifi_assoc_power_save_data_32_91, + sizeof(wifi_assoc_power_save_data_32_91) / sizeof(wifi_assoc_power_save_data_32_91[0])); + } + + LEAVE(); + return ret; +} +int wlan_set_phy_timeout(wlan_private * priv) +{ + int ret = 0; + if ((priv->version == WLAN_VERSION_90_D) || + (priv->version == WLAN_VERSION_90_E)) { + ret = wlan_write_sdio32_polling(priv, + wifi_phy_timeout_cfg_90, + sizeof(wifi_phy_timeout_cfg_90) / + sizeof(wifi_phy_timeout_cfg_90[0])); + } else if ((priv->version == WLAN_VERSION_91) || + (priv->version == WLAN_VERSION_91_E) || priv->version == WLAN_VERSION_91_F) { + ret = wlan_write_sdio32_polling(priv, + wifi_phy_timeout_cfg_91e, + sizeof(wifi_phy_timeout_cfg_91e) / + sizeof(wifi_phy_timeout_cfg_91e[0])); + } + return ret; +} + diff --git a/drivers/net/wireless/rda/rda_wlan/wlan_sdio_patch.h b/drivers/net/wireless/rda/rda_wlan/wlan_sdio_patch.h new file mode 100755 index 00000000..546241bf --- /dev/null +++ b/drivers/net/wireless/rda/rda_wlan/wlan_sdio_patch.h @@ -0,0 +1,12 @@ +#ifndef __WLAN_SDIO_PATCH_H__ +#define __WLAN_SDIO_PATCH_H__ + +int wlan_sdio_init(wlan_private *priv); +u8 is_sdio_init_complete(void); +u8 is_sdio_patch_complete(void) ; +int wlan_set_test_mode(wlan_private *priv); +int wlan_assoc_power_save(wlan_private * priv); +int wlan_set_phy_timeout(wlan_private * priv); + +#endif//__WLAN_SDIO_PATCH_H__ + diff --git a/drivers/net/wireless/rda/rda_wlan/wlan_sdio_patch_90.h b/drivers/net/wireless/rda/rda_wlan/wlan_sdio_patch_90.h new file mode 100755 index 00000000..eb4c614c --- /dev/null +++ b/drivers/net/wireless/rda/rda_wlan/wlan_sdio_patch_90.h @@ -0,0 +1,1793 @@ +#ifndef __WLAN_SDIO_PATCH_90_H__ +#define __WLAN_SDIO_PATCH_90_H__ + +//#define dig_access_pmu_cancel +const u32 wifi_core_patch_data_32_90_D[][2] = +{ + {0x00108000, 0xEA03DF9C}, + {0x00108004, 0xE59F101C}, + {0x00108008, 0xE3A00040}, + {0x0010800C, 0xE5C10038}, + {0x00108010, 0xE1A0F00E}, + {0x00108014, 0xEA03DF95}, + {0x00108018, 0xE59F1008}, + {0x0010801C, 0xE3A00040}, + {0x00108020, 0xE5C10038}, + {0x00108024, 0xE1A0F00E}, + {0x00108028, 0x50300000}, + {0x0010802C, 0xEB03D6F2}, + {0x00108030, 0xE1A00B84}, + {0x00108034, 0xE1B00BA0}, + {0x00108038, 0x11A00B84}, + {0x0010803C, 0x11A00BA0}, + {0x00108040, 0x12600F80}, + {0x00108044, 0x10804004}, + {0x00108048, 0xE1A00124}, + {0x0010804C, 0xE92D0011}, + {0x00108050, 0xE51F4030}, + {0x00108054, 0xE3A00020}, + {0x00108058, 0xE5C40038}, + {0x0010805C, 0xE8BD0011}, + {0x00108060, 0xE1A0F00E}, + {0x00108064, 0xEA03D3D2}, + {0x00108068, 0xE3A00001}, + {0x0010806C, 0xE1A0F00E}, + {0x00108070, 0xEA03D6CD}, + {0x00108074, 0xE3A00001}, + {0x00108078, 0xE1A0F00E}, + {0x0010807C, 0xEB03C786}, + {0x00108080, 0xE51F0060}, + {0x00108084, 0xE5D00038}, + {0x00108088, 0xE3100080}, + {0x0010808C, 0x1A000001}, + {0x00108090, 0xE3A00001}, + {0x00108094, 0xE1A0F00E}, + {0x00108098, 0xE3A00000}, + {0x0010809C, 0xE1A0F00E}, + {0x001080A0, 0xEB03EADE}, + {0x001080A4, 0xE51F0084}, + {0x001080A8, 0xE5D00038}, + {0x001080AC, 0xE3100080}, + {0x001080B0, 0x1A000001}, + {0x001080B4, 0xE3A00001}, + {0x001080B8, 0xE1A0F00E}, + {0x001080BC, 0xE3A00000}, + {0x001080C0, 0xE1A0F00E}, + {0x001080C4, 0xEB03D89D}, + {0x001080C8, 0xE51F00A8}, + {0x001080CC, 0xE3A01080}, + {0x001080D0, 0xE5C01038}, + {0x001080D4, 0xE1A0F00E}, + {0x001080D8, 0xEB03D714}, + {0x001080DC, 0xE51F10BC}, + {0x001080E0, 0xE5D10038}, + {0x001080E4, 0xE3100080}, + {0x001080E8, 0x159F001C}, + {0x001080EC, 0x059F0014}, + {0x001080F0, 0xE59F100C}, + {0x001080F4, 0xE581003C}, + {0x001080F8, 0xE51F10D8}, + {0x001080FC, 0xE1D101B4}, + {0x00108100, 0xE1A0F00E}, + {0x00108104, 0x30010000}, + {0x00108108, 0x2E00A100}, + {0x0010810C, 0x2E00A000}, + {0x00108110, 0xEB03B485}, + {0x00108114, 0x13100010}, + {0x00108118, 0x13A00002}, + {0x0010811C, 0x15C50067}, + {0x00108120, 0xE1A0F00E}, + {0x00108124, 0xEA03D804}, + {0x00108128, 0xE51F1108}, + {0x0010812C, 0xE5D10038}, + {0x00108130, 0xE2000020}, + {0x00108134, 0xE3500000}, + {0x00108138, 0x1AFFFFFB}, + {0x0010813C, 0xE3A01004}, + {0x00108140, 0xE3A00B48}, + {0x00108144, 0xE280FF45}, + {0x00108148, 0xEA04020A}, + {0x0010814C, 0x08BD4010}, + {0x00108150, 0x0A000002}, + {0x00108154, 0x13A00001}, + {0x00108158, 0x18BD4010}, + {0x0010815C, 0x1A000001}, + {0x00108160, 0xE51FF004}, + {0x00108164, 0x0000D470}, + {0x00108168, 0xE51FF004}, + {0x0010816C, 0x0000D2C0}, + {0x00108170, 0xEA0402CF}, + {0x00108174, 0xE59F600C}, + {0x00108178, 0xE3A04000}, + {0x0010817C, 0xE5C64000}, + {0x00108180, 0xE59F6004}, + {0x00108184, 0xE59FF004}, + {0x00108188, 0x0010200B}, + {0x0010818C, 0x0010121D}, + {0x00108190, 0x00007634}, + {0x00108194, 0xEAFFFFEC}, + {0x00108198, 0xE1A00004}, + {0x0010819C, 0xE1A00000}, + {0x20040004, 0x0001018C}, + {0x20040024, 0x00108000}, + {0x20040008, 0x000101BC}, + {0x20040028, 0x00108014}, + {0x2004000C, 0x00012460}, + {0x2004002C, 0x0010802C}, + {0x20040010, 0x00013118}, + {0x20040030, 0x00108064}, + {0x20040014, 0x00012538}, + {0x20040034, 0x00108070}, + {0x20040018, 0x00016260}, + {0x20040038, 0x0010807C}, + {0x2004001C, 0x0000D524}, + {0x2004003C, 0x001080A0}, + {0x20040020, 0x00011E4C}, + {0x20040040, 0x001080C4}, + {0x20040100, 0x00012484}, + {0x20040120, 0x001080D8}, + {0x20040104, 0x0001AEF8}, + {0x20040124, 0x00108110}, + {0x20040108, 0x00012110}, + {0x20040128, 0x00108124}, + {0x2004010C, 0x0000791C}, + {0x2004012C, 0x00108148}, + {0x20040110, 0x00007630}, + {0x20040130, 0x00108170}, + {0x20040114, 0x00017158}, + {0x20040134, 0x00108194}, + {0x20040118, 0x00002594}, + {0x20040138, 0x00108198}, + {0x2004011C, 0x000172A4}, + {0x2004013C, 0x0010819C}, + {0x20040000, 0x0000FFFF}, +}; + + + +const u32 wifi_core_patch_data_32_90_E[][2] = +{ +#ifdef NORMAL_FIXED +/******************************************************************************* +* RDA5990E/F固件补丁说明: +* 1. 关联前不能进入睡眠,大电流。 +* 2. 802.1X的EAPOL数据包使用最小基本速率发送。 +* 3. 睡眠和唤醒中MPLL概率性不锁 +* 4. 数据包中PM可能为1 +* 5. ACK控制包中PM可能为1 +* 6. 重名(SSID)的AP连接 +* 7. 隐藏SSID的AP连接 +* 8. 睡眠相关的杂项 +* 9. 不能连接支持DSSS-OFDM,PBCC,Channel Agility等选项的AP,一般表现为 +* 交替显示正在扫描,正在连接 +* 10.不能连接组播TKIP加密方式key index不为1的AP,一般表现为认证方式是 +* WPA/WPA2的AP某一段时间连接不上路由器,界面一直显示正在获取IP地址但 +* 总是获取不到,而过一段时间之后(不需要重启路由器)就能正常连接 +* 11.优化Wlan发送自动速率控制 +* 12.优化BT/WIFI共存机制 +* +* 补丁时间: +* 2012-11-21 +* +******************************************************************************/ + {0x00107FFC, 0x20121203}, + {0x00108000, 0xEA04012F}, + {0x00108004, 0x1A000001}, + {0x00108008, 0xE8BD4010}, + {0x0010800C, 0xEA000001}, + {0x00108010, 0xE51FF004}, + {0x00108014, 0x0000D4AC}, + {0x00108018, 0xE51FF004}, + {0x0010801C, 0x0000D654}, + {0x00108020, 0xEA03EABA}, + {0x00108024, 0xEB000003}, + {0x00108028, 0xE3500000}, + {0x0010802C, 0x0BFFFFF9}, + {0x00108030, 0xE8BD4008}, + {0x00108034, 0xE1A0F00E}, + {0x00108038, 0xE51FF004}, + {0x0010803C, 0x0000D6B4}, + {0x00108040, 0x00000000}, + {0x00108044, 0xEAFFFFEC}, + {0x00108048, 0xEA040DFF}, + {0x0010804C, 0xE3540000}, + {0x00108050, 0x08BD8FF8}, + {0x00108054, 0xE2440002}, + {0x00108058, 0xE51FF004}, + {0x0010805C, 0x0000484C}, + {0x00108060, 0x00000000}, + {0x00108064, 0x00000000}, + {0x00108068, 0xE1A00004}, + {0x0010806C, 0xE3A04000}, + {0x00108070, 0x00001468}, + {0x00108074, 0x00108070}, + {0x00108078, 0xEA03EA36}, + {0x0010807C, 0x0A000019}, + {0x00108080, 0xE3E00006}, + {0x00108084, 0xE3A015C0}, + {0x00108088, 0xE5810000}, + {0x0010808C, 0xE3A0000F}, + {0x00108090, 0xEB000015}, + {0x00108094, 0xE51F1028}, + {0x00108098, 0xE5912000}, + {0x0010809C, 0xE3822C80}, + {0x001080A0, 0xE5812000}, + {0x001080A4, 0xE1A01002}, + {0x001080A8, 0xE3A00029}, + {0x001080AC, 0xEB000012}, + {0x001080B0, 0xE51F1044}, + {0x001080B4, 0xE5912000}, + {0x001080B8, 0xE3822CC0}, + {0x001080BC, 0xE5812000}, + {0x001080C0, 0xE1A01002}, + {0x001080C4, 0xE3A00029}, + {0x001080C8, 0xEB00000B}, + {0x001080CC, 0xE51F1060}, + {0x001080D0, 0xE5912000}, + {0x001080D4, 0xE3C22CC0}, + {0x001080D8, 0xE5812000}, + {0x001080DC, 0xE1A01002}, + {0x001080E0, 0xE3A00029}, + {0x001080E4, 0xEB000004}, + {0x001080E8, 0xE59FF014}, + {0x001080EC, 0xE51FF004}, + {0x001080F0, 0x00003784}, + {0x001080F4, 0xE51FF004}, + {0x001080F8, 0x000114B0}, + {0x001080FC, 0xE51FF004}, + {0x00108100, 0x0001BD58}, + {0x00108104, 0x0000D7B0}, + {0x00108108, 0xEA03C6DA}, + {0x0010810C, 0x0A000019}, + {0x00108110, 0xE3E00006}, + {0x00108114, 0xE3A015C0}, + {0x00108118, 0xE5810000}, + {0x0010811C, 0xE3A0000F}, + {0x00108120, 0xEBFFFFF1}, + {0x00108124, 0xE51F10B8}, + {0x00108128, 0xE5912000}, + {0x0010812C, 0xE3822C80}, + {0x00108130, 0xE5812000}, + {0x00108134, 0xE1A01002}, + {0x00108138, 0xE3A00029}, + {0x0010813C, 0xEBFFFFEE}, + {0x00108140, 0xE51F10D4}, + {0x00108144, 0xE5912000}, + {0x00108148, 0xE3822CC0}, + {0x0010814C, 0xE5812000}, + {0x00108150, 0xE1A01002}, + {0x00108154, 0xE3A00029}, + {0x00108158, 0xEBFFFFE7}, + {0x0010815C, 0xE51F10F0}, + {0x00108160, 0xE5912000}, + {0x00108164, 0xE3C22CC0}, + {0x00108168, 0xE5812000}, + {0x0010816C, 0xE1A01002}, + {0x00108170, 0xE3A00029}, + {0x00108174, 0xEBFFFFE0}, + {0x00108178, 0xE51FF004}, + {0x0010817C, 0x000165B0}, + {0x00108180, 0x00000000}, + {0x00108184, 0x00000000}, + {0x00108188, 0x00000000}, + {0x0010818C, 0x00000000}, + {0x00108190, 0x00000000}, + {0x00108194, 0x00000000}, + {0x00108198, 0x00000000}, + {0x0010819C, 0x00000000}, + {0x001081A0, 0x00000000}, + {0x001081A4, 0x00108180}, + {0x001081A8, 0xEA03D197}, + {0x001081AC, 0xE92D40F8}, + {0x001081B0, 0xE51F5014}, + {0x001081B4, 0xE51FF004}, + {0x001081B8, 0x00015730}, + {0x001081BC, 0xEA03E13E}, + {0x001081C0, 0xE59F0018}, + {0x001081C4, 0xE5901038}, + {0x001081C8, 0xE3110080}, + {0x001081CC, 0x1A000001}, + {0x001081D0, 0xE3A01003}, + {0x001081D4, 0xE59FF008}, + {0x001081D8, 0xE51FF004}, + {0x001081DC, 0x0000FD18}, + {0x001081E0, 0x50300000}, + {0x001081E4, 0x0000FCC4}, + {0x001081E8, 0xE1A00000}, + {0x001081EC, 0x00000000}, + {0x001081F0, 0x00000000}, + {0x001081F4, 0x001081EC}, + {0x001081F8, 0xEA0415B4}, + {0x001081FC, 0xE2860018}, + {0x00108200, 0xE3A02006}, + {0x00108204, 0xE51F1018}, + {0x00108208, 0xEB000003}, + {0x0010820C, 0xE3500000}, + {0x00108210, 0x01A07004}, + {0x00108214, 0x0A000002}, + {0x00108218, 0x1A000003}, + {0x0010821C, 0xE51FF004}, + {0x00108220, 0x00000160}, + {0x00108224, 0xE51FF004}, + {0x00108228, 0x00002BA0}, + {0x0010822C, 0xE51FF004}, + {0x00108230, 0x00002B8C}, + {0x00108234, 0xE3A00002}, + {0x00108238, 0x00000000}, + {0x0010823C, 0x00108238}, + {0x00108240, 0xEA03DFBB}, + {0x00108244, 0xE5902834}, + {0x00108248, 0xE51F1014}, + {0x0010824C, 0xE5812000}, + {0x00108250, 0xE3A01000}, + {0x00108254, 0xE5801834}, + {0x00108258, 0xE1A0F00E}, + {0x0010825C, 0xEA03E040}, + {0x00108260, 0xE51F002C}, + {0x00108264, 0xE5900000}, + {0x00108268, 0xE5810834}, + {0x0010826C, 0xE1A0F00E}, + {0x00108270, 0xE3500000}, + {0x20040004, 0x00007B40}, + {0x20040024, 0x00108000}, + {0x20040008, 0x0000D534}, + {0x20040028, 0x00108020}, + {0x2004000C, 0x00017518}, + {0x2004002C, 0x00108044}, + {0x20040010, 0x00004848}, + {0x20040030, 0x00108048}, + {0x20040014, 0x00002520}, + {0x20040034, 0x00108068}, + {0x20040018, 0x00010000}, + {0x20040038, 0x0010806C}, + {0x2004001C, 0x0000D79C}, + {0x2004003C, 0x00108078}, + {0x20040020, 0x0001659C}, + {0x20040040, 0x00108108}, + {0x20040100, 0x00013B48}, + {0x20040120, 0x001081A8}, + {0x20040104, 0x0000FCC0}, + {0x20040124, 0x001081BC}, + {0x20040108, 0x00015090}, + {0x20040128, 0x001081E8}, + {0x2004010C, 0x00002B24}, + {0x2004012C, 0x001081F8}, + {0x20040110, 0x00001790}, + {0x20040130, 0x00108234}, + {0x20040114, 0x00010350}, + {0x20040134, 0x00108240}, + {0x20040118, 0x00010158}, + {0x20040138, 0x0010825C}, + {0x2004011C, 0x00004290}, + {0x2004013C, 0x00108270}, + {0x20040000, 0x0000FFFF}, +/*****************************************************************************/ + +#elif defined WLAN_BIG_CURRENT_90E +/*****************************************************************************/ + {0x00107FFC, 0x20140312}, + {0x00108000, 0xEA04012F}, + {0x00108004, 0x1A000001}, + {0x00108008, 0xE8BD4010}, + {0x0010800C, 0xEA000001}, + {0x00108010, 0xE51FF004}, + {0x00108014, 0x0000D4AC}, + {0x00108018, 0xE51FF004}, + {0x0010801C, 0x0000D654}, + {0x00108020, 0xEA03EABA}, + {0x00108024, 0xEB000003}, + {0x00108028, 0xE3500000}, + {0x0010802C, 0x0BFFFFF9}, + {0x00108030, 0xE8BD4008}, + {0x00108034, 0xE1A0F00E}, + {0x00108038, 0xE51FF004}, + {0x0010803C, 0x0000D6B4}, + {0x00108040, 0xE1A00004}, + {0x00108044, 0xE3A04000}, + {0x00108048, 0xEA03EA2A}, + {0x0010804C, 0x0A000019}, + {0x00108050, 0xE3E00006}, + {0x00108054, 0xE3A015C0}, + {0x00108058, 0xE5810000}, + {0x0010805C, 0xE3A0000F}, + {0x00108060, 0xEB000015}, + {0x00108064, 0xE59F106C}, + {0x00108068, 0xE5912000}, + {0x0010806C, 0xE3822C80}, + {0x00108070, 0xE5812000}, + {0x00108074, 0xE1A01002}, + {0x00108078, 0xE3A00029}, + {0x0010807C, 0xEB000012}, + {0x00108080, 0xE59F1050}, + {0x00108084, 0xE5912000}, + {0x00108088, 0xE3822CC0}, + {0x0010808C, 0xE5812000}, + {0x00108090, 0xE1A01002}, + {0x00108094, 0xE3A00029}, + {0x00108098, 0xEB00000B}, + {0x0010809C, 0xE59F1034}, + {0x001080A0, 0xE5912000}, + {0x001080A4, 0xE3C22CC0}, + {0x001080A8, 0xE5812000}, + {0x001080AC, 0xE1A01002}, + {0x001080B0, 0xE3A00029}, + {0x001080B4, 0xEB000004}, + {0x001080B8, 0xE59FF01C}, + {0x001080BC, 0xE51FF004}, + {0x001080C0, 0x00003784}, + {0x001080C4, 0xE51FF004}, + {0x001080C8, 0x000114B0}, + {0x001080CC, 0xE51FF004}, + {0x001080D0, 0x0001BD58}, + {0x001080D4, 0x00001468}, + {0x001080D8, 0x001080D4}, + {0x001080DC, 0x0000D7B0}, + {0x001080E0, 0xEA03C6D0}, + {0x001080E4, 0x0A000019}, + {0x001080E8, 0xE3E00006}, + {0x001080EC, 0xE3A015C0}, + {0x001080F0, 0xE5810000}, + {0x001080F4, 0xE3A0000F}, + {0x001080F8, 0xEBFFFFEF}, + {0x001080FC, 0xE51F102C}, + {0x00108100, 0xE5912000}, + {0x00108104, 0xE3822C80}, + {0x00108108, 0xE5812000}, + {0x0010810C, 0xE1A01002}, + {0x00108110, 0xE3A00029}, + {0x00108114, 0xEBFFFFEC}, + {0x00108118, 0xE51F1048}, + {0x0010811C, 0xE5912000}, + {0x00108120, 0xE3822CC0}, + {0x00108124, 0xE5812000}, + {0x00108128, 0xE1A01002}, + {0x0010812C, 0xE3A00029}, + {0x00108130, 0xEBFFFFE5}, + {0x00108134, 0xE51F1064}, + {0x00108138, 0xE5912000}, + {0x0010813C, 0xE3C22CC0}, + {0x00108140, 0xE5812000}, + {0x00108144, 0xE1A01002}, + {0x00108148, 0xE3A00029}, + {0x0010814C, 0xEBFFFFDE}, + {0x00108150, 0xE51FF004}, + {0x00108154, 0x000165B0}, + {0x00108158, 0xE1A00000}, + {0x0010815C, 0xE1A00000}, + {0x00108160, 0xE1A00000}, + {0x00108164, 0xE1A00000}, + {0x00108168, 0xE1A00000}, + {0x0010816C, 0xE1A00000}, + {0x00108170, 0xEA03D189}, + {0x00108174, 0xE92D40F8}, + {0x00108178, 0xE59F5024}, + {0x0010817C, 0xE59FF024}, + {0x00108180, 0x00000000}, + {0x00108184, 0x00000000}, + {0x00108188, 0x00000000}, + {0x0010818C, 0x00000000}, + {0x00108190, 0x00000000}, + {0x00108194, 0x00000000}, + {0x00108198, 0x00000000}, + {0x0010819C, 0x00000000}, + {0x001081A0, 0x00000000}, + {0x001081A4, 0x00108180}, + {0x001081A8, 0x00015730}, + {0x001081AC, 0xEA03E13A}, + {0x001081B0, 0xE59F0018}, + {0x001081B4, 0xE5901038}, + {0x001081B8, 0xE3110080}, + {0x001081BC, 0x1A000001}, + {0x001081C0, 0xE3A01003}, + {0x001081C4, 0xE59FF008}, + {0x001081C8, 0xE51FF004}, + {0x001081CC, 0x0000FD18}, + {0x001081D0, 0x50300000}, + {0x001081D4, 0x0000FCC4}, + {0x001081D8, 0xE1A00000}, + {0x001081DC, 0xE1A00000}, + {0x001081E0, 0xE1A00000}, + {0x001081E4, 0xE1A00000}, + {0x001081E8, 0xE1A00000}, + {0x001081EC, 0x00000000}, + {0x001081F0, 0x00000000}, + {0x001081F4, 0x001081EC}, + {0x001081F8, 0xEA0415B4}, + {0x001081FC, 0xE2860018}, + {0x00108200, 0xE3A02006}, + {0x00108204, 0xE51F1018}, + {0x00108208, 0xEB000003}, + {0x0010820C, 0xE3500000}, + {0x00108210, 0x01A07004}, + {0x00108214, 0x0A000002}, + {0x00108218, 0x1A000003}, + {0x0010821C, 0xE51FF004}, + {0x00108220, 0x00000160}, + {0x00108224, 0xE51FF004}, + {0x00108228, 0x00002BA0}, + {0x0010822C, 0xE51FF004}, + {0x00108230, 0x00002B8C}, + {0x00108234, 0xE3A00002}, + {0x00108238, 0xEA03DFB9}, + {0x0010823C, 0xE5902834}, + {0x00108240, 0xE59F1010}, + {0x00108244, 0xE5812000}, + {0x00108248, 0xE3A01000}, + {0x0010824C, 0xE5801834}, + {0x00108250, 0xE1A0F00E}, + {0x00108254, 0x00000000}, + {0x00108258, 0x00108254}, + {0x0010825C, 0xEA03E040}, + {0x00108260, 0xE51F0010}, + {0x00108264, 0xE5900000}, + {0x00108268, 0xE5810834}, + {0x0010826C, 0xE1A0F00E}, + {0x00108270, 0x00000000}, + {0x00108274, 0x00108270}, + {0x00108278, 0xEA03C6EE}, + {0x0010827C, 0xE3500001}, + {0x00108280, 0x1A00001A}, + {0x00108284, 0xE92D0007}, + {0x00108288, 0xE51F001C}, + {0x0010828C, 0xE5901000}, + {0x00108290, 0xE59F0050}, + {0x00108294, 0xE5D02000}, + {0x00108298, 0xE3520000}, + {0x0010829C, 0x02811001}, + {0x001082A0, 0x159F0044}, + {0x001082A4, 0x15D02000}, + {0x001082A8, 0x10811002}, + {0x001082AC, 0xE51F0040}, + {0x001082B0, 0xE3510F40}, + {0x001082B4, 0x83A01000}, + {0x001082B8, 0xE5801000}, + {0x001082BC, 0x9A000007}, + {0x001082C0, 0xE59F0020}, + {0x001082C4, 0xE5D00000}, + {0x001082C8, 0xE3500000}, + {0x001082CC, 0x0A000003}, + {0x001082D0, 0x13A00001}, + {0x001082D4, 0xE3A01000}, + {0x001082D8, 0xE3A02000}, + {0x001082DC, 0xEB000005}, + {0x001082E0, 0xE8BD0007}, + {0x001082E4, 0xE59FF014}, + {0x001082E8, 0x0010670D}, + {0x001082EC, 0x00106046}, + {0x001082F0, 0xE51FF004}, + {0x001082F4, 0x00016770}, + {0x001082F8, 0xE51FF004}, + {0x001082FC, 0x00012DB0}, + {0x00108300, 0x000166C4}, + {0x00108304, 0xEA0401FB}, + {0x00108308, 0xE3A00030}, + {0x0010830C, 0xE59F100C}, + {0x00108310, 0xEBFFFF6D}, + {0x00108314, 0xE59F4000}, + {0x00108318, 0xE59FF004}, + {0x0010831C, 0x0010670C}, + {0x00108320, 0x00000241}, + {0x00108324, 0x00007B18}, + {0x00108328, 0xEA03E128}, + {0x0010832C, 0xE3A00030}, + {0x00108330, 0xE59F100C}, + {0x00108334, 0xEBFFFF64}, + {0x00108338, 0xE2044001}, + {0x0010833C, 0xE3540000}, + {0x00108340, 0xE59FF000}, + {0x00108344, 0x00000249}, + {0x00108348, 0x0000FE88}, + {0x0010834C, 0xEA03D8FA}, + {0x00108350, 0xE3A00030}, + {0x00108354, 0xE51F103C}, + {0x00108358, 0xEBFFFF5B}, + {0x0010835C, 0xE3A01003}, + {0x00108360, 0xE51FF004}, + {0x00108364, 0x00011F6C}, + {0x20040004, 0x00007B40}, + {0x20040024, 0x00108000}, + {0x20040008, 0x0000D534}, + {0x20040028, 0x00108020}, + {0x2004000C, 0x00002520}, + {0x2004002C, 0x00108040}, + {0x20040010, 0x00010000}, + {0x20040030, 0x00108044}, + {0x20040014, 0x0000D79C}, + {0x20040034, 0x00108048}, + {0x20040018, 0x0001659C}, + {0x20040038, 0x001080E0}, + {0x2004001C, 0x00013B48}, + {0x2004003C, 0x00108170}, + {0x20040020, 0x0000FCC0}, + {0x20040040, 0x001081AC}, + {0x20040100, 0x00002B24}, + {0x20040120, 0x001081F8}, + {0x20040104, 0x00001790}, + {0x20040124, 0x00108234}, + {0x20040108, 0x00010350}, + {0x20040128, 0x00108238}, + {0x2004010C, 0x00010158}, + {0x2004012C, 0x0010825C}, + {0x20040110, 0x000166BC}, + {0x20040130, 0x00108278}, + {0x20040114, 0x00007B14}, + {0x20040134, 0x00108304}, + {0x20040118, 0x0000FE84}, + {0x20040138, 0x00108328}, + {0x2004011C, 0x00011F60}, + {0x2004013C, 0x0010834C}, + {0x20040000, 0x0000FFFF}, +/*****************************************************************************/ + +#elif defined WLAN_FLOW_CTRL_90E +/*****************************************************************************/ + {0x00107FFC, 0x20140122}, + {0x00108000, 0xEA04012F}, + {0x00108004, 0x1A000001}, + {0x00108008, 0xE8BD4010}, + {0x0010800C, 0xEA000001}, + {0x00108010, 0xE51FF004}, + {0x00108014, 0x0000D4AC}, + {0x00108018, 0xE51FF004}, + {0x0010801C, 0x0000D654}, + {0x00108020, 0xEA03EABA}, + {0x00108024, 0xEB000003}, + {0x00108028, 0xE3500000}, + {0x0010802C, 0x0BFFFFF9}, + {0x00108030, 0xE8BD4008}, + {0x00108034, 0xE1A0F00E}, + {0x00108038, 0xE51FF004}, + {0x0010803C, 0x0000D6B4}, + {0x00108040, 0x00000000}, + {0x00108044, 0xEAFFFFEC}, + {0x00108048, 0x0000484C}, + {0x0010804C, 0x00000000}, + {0x00108050, 0x00000000}, + {0x00108054, 0x00000000}, + {0x00108058, 0x00000000}, + {0x0010805C, 0x00000000}, + {0x00108060, 0x00000000}, + {0x00108064, 0x00000000}, + {0x00108068, 0xE1A00004}, + {0x0010806C, 0xE3A04000}, + {0x00108070, 0x00001468}, + {0x00108074, 0x00108070}, + {0x00108078, 0xEA03EA36}, + {0x0010807C, 0x0A000019}, + {0x00108080, 0xE3E00006}, + {0x00108084, 0xE3A015C0}, + {0x00108088, 0xE5810000}, + {0x0010808C, 0xE3A0000F}, + {0x00108090, 0xEB000015}, + {0x00108094, 0xE51F1028}, + {0x00108098, 0xE5912000}, + {0x0010809C, 0xE3822C80}, + {0x001080A0, 0xE5812000}, + {0x001080A4, 0xE1A01002}, + {0x001080A8, 0xE3A00029}, + {0x001080AC, 0xEB000012}, + {0x001080B0, 0xE51F1044}, + {0x001080B4, 0xE5912000}, + {0x001080B8, 0xE3822CC0}, + {0x001080BC, 0xE5812000}, + {0x001080C0, 0xE1A01002}, + {0x001080C4, 0xE3A00029}, + {0x001080C8, 0xEB00000B}, + {0x001080CC, 0xE51F1060}, + {0x001080D0, 0xE5912000}, + {0x001080D4, 0xE3C22CC0}, + {0x001080D8, 0xE5812000}, + {0x001080DC, 0xE1A01002}, + {0x001080E0, 0xE3A00029}, + {0x001080E4, 0xEB000004}, + {0x001080E8, 0xE59FF014}, + {0x001080EC, 0xE51FF004}, + {0x001080F0, 0x00003784}, + {0x001080F4, 0xE51FF004}, + {0x001080F8, 0x000114B0}, + {0x001080FC, 0xE51FF004}, + {0x00108100, 0x0001BD58}, + {0x00108104, 0x0000D7B0}, + {0x00108108, 0xEA03C6DA}, + {0x0010810C, 0x0A000019}, + {0x00108110, 0xE3E00006}, + {0x00108114, 0xE3A015C0}, + {0x00108118, 0xE5810000}, + {0x0010811C, 0xE3A0000F}, + {0x00108120, 0xEBFFFFF1}, + {0x00108124, 0xE51F10B8}, + {0x00108128, 0xE5912000}, + {0x0010812C, 0xE3822C80}, + {0x00108130, 0xE5812000}, + {0x00108134, 0xE1A01002}, + {0x00108138, 0xE3A00029}, + {0x0010813C, 0xEBFFFFEE}, + {0x00108140, 0xE51F10D4}, + {0x00108144, 0xE5912000}, + {0x00108148, 0xE3822CC0}, + {0x0010814C, 0xE5812000}, + {0x00108150, 0xE1A01002}, + {0x00108154, 0xE3A00029}, + {0x00108158, 0xEBFFFFE7}, + {0x0010815C, 0xE51F10F0}, + {0x00108160, 0xE5912000}, + {0x00108164, 0xE3C22CC0}, + {0x00108168, 0xE5812000}, + {0x0010816C, 0xE1A01002}, + {0x00108170, 0xE3A00029}, + {0x00108174, 0xEBFFFFE0}, + {0x00108178, 0xE51FF004}, + {0x0010817C, 0x000165B0}, + {0x00108180, 0x00000000}, + {0x00108184, 0x00000000}, + {0x00108188, 0x00000000}, + {0x0010818C, 0x00000000}, + {0x00108190, 0x00000000}, + {0x00108194, 0x00000000}, + {0x00108198, 0x00000000}, + {0x0010819C, 0x00000000}, + {0x001081A0, 0x00000000}, + {0x001081A4, 0x00108180}, + {0x001081A8, 0xEA03D197}, + {0x001081AC, 0xE92D40F8}, + {0x001081B0, 0xE51F5014}, + {0x001081B4, 0xE51FF004}, + {0x001081B8, 0x00015730}, + {0x001081BC, 0xEA03E13E}, + {0x001081C0, 0xE59F0018}, + {0x001081C4, 0xE5901038}, + {0x001081C8, 0xE3110080}, + {0x001081CC, 0x1A000001}, + {0x001081D0, 0xE3A01003}, + {0x001081D4, 0xE59FF008}, + {0x001081D8, 0xE51FF004}, + {0x001081DC, 0x0000FD18}, + {0x001081E0, 0x50300000}, + {0x001081E4, 0x0000FCC4}, + {0x001081E8, 0xE1A00000}, + {0x001081EC, 0x00000000}, + {0x001081F0, 0x00000000}, + {0x001081F4, 0x001081EC}, + {0x001081F8, 0xEA0415B4}, + {0x001081FC, 0xE2860018}, + {0x00108200, 0xE3A02006}, + {0x00108204, 0xE51F1018}, + {0x00108208, 0xEB000003}, + {0x0010820C, 0xE3500000}, + {0x00108210, 0x01A07004}, + {0x00108214, 0x0A000002}, + {0x00108218, 0x1A000003}, + {0x0010821C, 0xE51FF004}, + {0x00108220, 0x00000160}, + {0x00108224, 0xE51FF004}, + {0x00108228, 0x00002BA0}, + {0x0010822C, 0xE51FF004}, + {0x00108230, 0x00002B8C}, + {0x00108234, 0xE3A00002}, + {0x00108238, 0x00000000}, + {0x0010823C, 0x00108238}, + {0x00108240, 0xEA03DFBB}, + {0x00108244, 0xE5902834}, + {0x00108248, 0xE51F1014}, + {0x0010824C, 0xE5812000}, + {0x00108250, 0xE3A01000}, + {0x00108254, 0xE5801834}, + {0x00108258, 0xE1A0F00E}, + {0x0010825C, 0xEA03E040}, + {0x00108260, 0xE51F002C}, + {0x00108264, 0xE5900000}, + {0x00108268, 0xE5810834}, + {0x0010826C, 0xE1A0F00E}, + {0x00108270, 0xE3500000}, + {0x00108274, 0xEA03E602}, + {0x00108278, 0xE59F200C}, + {0x0010827C, 0xE3A01010}, + {0x00108280, 0xE5C21000}, + {0x00108284, 0xE1A02000}, + {0x00108288, 0xE59FF000}, + {0x0010828C, 0x50300038}, + {0x00108290, 0x0000EA6C}, + {0x00108294, 0x00000000}, + {0x00108298, 0x00108294}, + {0x0010829C, 0xEA03C6F7}, + {0x001082A0, 0xE3500001}, + {0x001082A4, 0x1A00001A}, + {0x001082A8, 0xE92D0007}, + {0x001082AC, 0xE51F001C}, + {0x001082B0, 0xE5901000}, + {0x001082B4, 0xE59F0050}, + {0x001082B8, 0xE5D02000}, + {0x001082BC, 0xE3520000}, + {0x001082C0, 0x02811001}, + {0x001082C4, 0x159F0044}, + {0x001082C8, 0x15D02000}, + {0x001082CC, 0x10811002}, + {0x001082D0, 0xE51F0040}, + {0x001082D4, 0xE3510F40}, + {0x001082D8, 0x83A01000}, + {0x001082DC, 0xE5801000}, + {0x001082E0, 0x9A000007}, + {0x001082E4, 0xE59F0020}, + {0x001082E8, 0xE5D00000}, + {0x001082EC, 0xE3500000}, + {0x001082F0, 0x0A000003}, + {0x001082F4, 0x13A00001}, + {0x001082F8, 0xE3A01000}, + {0x001082FC, 0xE3A02000}, + {0x00108300, 0xEB000005}, + {0x00108304, 0xE8BD0007}, + {0x00108308, 0xE59FF014}, + {0x0010830C, 0x0010670D}, + {0x00108310, 0x00106046}, + {0x00108314, 0xE51FF004}, + {0x00108318, 0x00016770}, + {0x0010831C, 0xE51FF004}, + {0x00108320, 0x00012DB0}, + {0x00108324, 0x000166C4}, + {0x20040004, 0x00007B40}, + {0x20040024, 0x00108000}, + {0x20040008, 0x0000D534}, + {0x20040028, 0x00108020}, + {0x2004000C, 0x00017518}, + {0x2004002C, 0x00108044}, + {0x20040010, 0x00002520}, + {0x20040030, 0x00108068}, + {0x20040014, 0x00010000}, + {0x20040034, 0x0010806C}, + {0x20040018, 0x0000D79C}, + {0x20040038, 0x00108078}, + {0x2004001C, 0x0001659C}, + {0x2004003C, 0x00108108}, + {0x20040020, 0x00013B48}, + {0x20040040, 0x001081A8}, + {0x20040100, 0x0000FCC0}, + {0x20040120, 0x001081BC}, + {0x20040104, 0x00015090}, + {0x20040124, 0x001081E8}, + {0x20040108, 0x00002B24}, + {0x20040128, 0x001081F8}, + {0x2004010C, 0x00001790}, + {0x2004012C, 0x00108234}, + {0x20040110, 0x00010350}, + {0x20040130, 0x00108240}, + {0x20040114, 0x00010158}, + {0x20040134, 0x0010825C}, + {0x20040118, 0x0000EA68}, + {0x20040138, 0x00108274}, + {0x2004011C, 0x000166BC}, + {0x2004013C, 0x0010829C}, + {0x20040000, 0x0000FFFF}, +/*****************************************************************************/ + +#else +/******************************************************************************* +* RDA5990E/F固件补丁说明: +* 1. 关联前不能进入睡眠,大电流。 +* 2. 802.1X的EAPOL数据包使用最小基本速率发送。 +* 3. 睡眠和唤醒中MPLL概率性不锁 +* 4. 数据包中PM可能为1 +* 5. ACK控制包中PM可能为1 +* 6. 重名(SSID)的AP连接 +* 7. 隐藏SSID的AP连接 +* 8. 睡眠相关的杂项 +* 9. 不能连接支持DSSS-OFDM,PBCC,Channel Agility等选项的AP,一般表现为 +* 交替显示正在扫描,正在连接 +* 10.不能连接组播TKIP加密方式key index不为1的AP,一般表现为认证方式是 +* WPA/WPA2的AP某一段时间连接不上路由器,界面一直显示正在获取IP地址但 +* 总是获取不到,而过一段时间之后(不需要重启路由器)就能正常连接 +* 11.针对特定路由器睡眠电流大的补丁,一般不推荐 +* 12.优化BT/WIFI共存机制 +* +* 补丁时间: +* 2012-11-22 +* +******************************************************************************/ + {0x00107FFC, 0x20121121}, + {0x00108000, 0xEA04012F}, + {0x00108004, 0x1A000001}, + {0x00108008, 0xE8BD4010}, + {0x0010800C, 0xEA000001}, + {0x00108010, 0xE51FF004}, + {0x00108014, 0x0000D4AC}, + {0x00108018, 0xE51FF004}, + {0x0010801C, 0x0000D654}, + {0x00108020, 0xEA040142}, + {0x00108024, 0xE3A00030}, + {0x00108028, 0xE59F1008}, + {0x0010802C, 0xEB000032}, + {0x00108030, 0xE59F4004}, + {0x00108034, 0xE59FF004}, + {0x00108038, 0x00000241}, + {0x0010803C, 0x0010670C}, + {0x00108040, 0x00007B18}, + {0x00108044, 0xEA03E06F}, + {0x00108048, 0xE3A00030}, + {0x0010804C, 0xE59F100C}, + {0x00108050, 0xEB000029}, + {0x00108054, 0xE2044001}, + {0x00108058, 0xE3540000}, + {0x0010805C, 0xE59FF000}, + {0x00108060, 0x00000249}, + {0x00108064, 0x0000FE88}, + {0x00108068, 0xE1A00004}, + {0x0010806C, 0xE3A04000}, + {0x00108070, 0x00001468}, + {0x00108074, 0x00108070}, + {0x00108078, 0xEA03EA36}, + {0x0010807C, 0x0A000019}, + {0x00108080, 0xE3E00006}, + {0x00108084, 0xE3A015C0}, + {0x00108088, 0xE5810000}, + {0x0010808C, 0xE3A0000F}, + {0x00108090, 0xEB000015}, + {0x00108094, 0xE51F1028}, + {0x00108098, 0xE5912000}, + {0x0010809C, 0xE3822C80}, + {0x001080A0, 0xE5812000}, + {0x001080A4, 0xE1A01002}, + {0x001080A8, 0xE3A00029}, + {0x001080AC, 0xEB000012}, + {0x001080B0, 0xE51F1044}, + {0x001080B4, 0xE5912000}, + {0x001080B8, 0xE3822CC0}, + {0x001080BC, 0xE5812000}, + {0x001080C0, 0xE1A01002}, + {0x001080C4, 0xE3A00029}, + {0x001080C8, 0xEB00000B}, + {0x001080CC, 0xE51F1060}, + {0x001080D0, 0xE5912000}, + {0x001080D4, 0xE3C22CC0}, + {0x001080D8, 0xE5812000}, + {0x001080DC, 0xE1A01002}, + {0x001080E0, 0xE3A00029}, + {0x001080E4, 0xEB000004}, + {0x001080E8, 0xE59FF014}, + {0x001080EC, 0xE51FF004}, + {0x001080F0, 0x00003784}, + {0x001080F4, 0xE51FF004}, + {0x001080F8, 0x000114B0}, + {0x001080FC, 0xE51FF004}, + {0x00108100, 0x0001BD58}, + {0x00108104, 0x0000D7B0}, + {0x00108108, 0xEA03C6DA}, + {0x0010810C, 0x0A000019}, + {0x00108110, 0xE3E00006}, + {0x00108114, 0xE3A015C0}, + {0x00108118, 0xE5810000}, + {0x0010811C, 0xE3A0000F}, + {0x00108120, 0xEBFFFFF1}, + {0x00108124, 0xE51F10B8}, + {0x00108128, 0xE5912000}, + {0x0010812C, 0xE3822C80}, + {0x00108130, 0xE5812000}, + {0x00108134, 0xE1A01002}, + {0x00108138, 0xE3A00029}, + {0x0010813C, 0xEBFFFFEE}, + {0x00108140, 0xE51F10D4}, + {0x00108144, 0xE5912000}, + {0x00108148, 0xE3822CC0}, + {0x0010814C, 0xE5812000}, + {0x00108150, 0xE1A01002}, + {0x00108154, 0xE3A00029}, + {0x00108158, 0xEBFFFFE7}, + {0x0010815C, 0xE51F10F0}, + {0x00108160, 0xE5912000}, + {0x00108164, 0xE3C22CC0}, + {0x00108168, 0xE5812000}, + {0x0010816C, 0xE1A01002}, + {0x00108170, 0xE3A00029}, + {0x00108174, 0xEBFFFFE0}, + {0x00108178, 0xE51FF004}, + {0x0010817C, 0x000165B0}, + {0x00108180, 0x00000000}, + {0x00108184, 0x00000000}, + {0x00108188, 0x00000000}, + {0x0010818C, 0x00000000}, + {0x00108190, 0x00000000}, + {0x00108194, 0x00000000}, + {0x00108198, 0x00000000}, + {0x0010819C, 0x00000000}, + {0x001081A0, 0x00000000}, + {0x001081A4, 0x00108180}, + {0x001081A8, 0xEA03D197}, + {0x001081AC, 0xE92D40F8}, + {0x001081B0, 0xE51F5014}, + {0x001081B4, 0xE51FF004}, + {0x001081B8, 0x00015730}, + {0x001081BC, 0xEA03E13E}, + {0x001081C0, 0xE59F0018}, + {0x001081C4, 0xE5901038}, + {0x001081C8, 0xE3110080}, + {0x001081CC, 0x1A000001}, + {0x001081D0, 0xE3A01003}, + {0x001081D4, 0xE59FF008}, + {0x001081D8, 0xE51FF004}, + {0x001081DC, 0x0000FD18}, + {0x001081E0, 0x50300000}, + {0x001081E4, 0x0000FCC4}, + {0x001081E8, 0xE1A00000}, + {0x001081EC, 0x00000000}, + {0x001081F0, 0x00000000}, + {0x001081F4, 0x001081EC}, + {0x001081F8, 0xEA0415B4}, + {0x001081FC, 0xE2860018}, + {0x00108200, 0xE3A02006}, + {0x00108204, 0xE51F1018}, + {0x00108208, 0xEB000003}, + {0x0010820C, 0xE3500000}, + {0x00108210, 0x01A07004}, + {0x00108214, 0x0A000002}, + {0x00108218, 0x1A000003}, + {0x0010821C, 0xE51FF004}, + {0x00108220, 0x00000160}, + {0x00108224, 0xE51FF004}, + {0x00108228, 0x00002BA0}, + {0x0010822C, 0xE51FF004}, + {0x00108230, 0x00002B8C}, + {0x00108234, 0xE3A00002}, + {0x00108238, 0x00000000}, + {0x0010823C, 0x00108238}, + {0x00108240, 0xEA03DFBB}, + {0x00108244, 0xE5902834}, + {0x00108248, 0xE51F1014}, + {0x0010824C, 0xE5812000}, + {0x00108250, 0xE3A01000}, + {0x00108254, 0xE5801834}, + {0x00108258, 0xE1A0F00E}, + {0x0010825C, 0xEA03E040}, + {0x00108260, 0xE51F002C}, + {0x00108264, 0xE5900000}, + {0x00108268, 0xE5810834}, + {0x0010826C, 0xE1A0F00E}, + {0x00108270, 0xEAFFFFEC}, + {0x00108274, 0xEA03D8C4}, + {0x00108278, 0xE3A00030}, + {0x0010827C, 0xE59F1008}, + {0x00108280, 0xEBFFFF9D}, + {0x00108284, 0xE3A01003}, + {0x00108288, 0xE59FF000}, + {0x0010828C, 0x00000241}, + {0x00108290, 0x00011F6C}, + {0x20040004, 0x00007B40}, + {0x20040024, 0x00108000}, + {0x20040008, 0x00007B14}, + {0x20040028, 0x00108020}, + {0x2004000C, 0x0000FE84}, + {0x2004002C, 0x00108044}, + {0x20040010, 0x00002520}, + {0x20040030, 0x00108068}, + {0x20040014, 0x00010000}, + {0x20040034, 0x0010806C}, + {0x20040018, 0x0000D79C}, + {0x20040038, 0x00108078}, + {0x2004001C, 0x0001659C}, + {0x2004003C, 0x00108108}, + {0x20040020, 0x00013B48}, + {0x20040040, 0x001081A8}, + {0x20040100, 0x0000FCC0}, + {0x20040120, 0x001081BC}, + {0x20040104, 0x00015090}, + {0x20040124, 0x001081E8}, + {0x20040108, 0x00002B24}, + {0x20040128, 0x001081F8}, + {0x2004010C, 0x00001790}, + {0x2004012C, 0x00108234}, + {0x20040110, 0x00010350}, + {0x20040130, 0x00108240}, + {0x20040114, 0x00010158}, + {0x20040134, 0x0010825C}, + {0x20040118, 0x00017518}, + {0x20040138, 0x00108270}, + {0x2004011C, 0x00011F60}, + {0x2004013C, 0x00108274}, + {0x20040000, 0x0000FFFF}, +#endif +}; + +const u8 wifi_core_patch_data_90_8[][2] = +{ + { 0x28, 0x1a} , + { 0x29, 0x0d}, + { 0x35, 0x1e}, + { 0x4c, 0x90}, + { 0x4d, 0x38}, + { 0x39, 0x07}, + { 0xe4, 0xf5}, + { 0x21, 0x00}, //default 0 + { 0x23, 0x10}, + { 0x48, 0x0e}, + { 0x25, 0x00}, + { 0x20, 0xa8}, + { 0x3f, 0x05}, + { 0x41, 0x37}, + { 0x42, 0x40}, + { 0x5b, 0xa9}, +}; + +//#define WF_PAT_CFG_2012_04_15 + + +/*if define FORCE_WF, wf is not allow of any activity, antenna switch is also forced to bt*/ +//#define FORCE_WF + +/*if define FORCE_WF_TX ,wf is not allow to do tx and pa is also disabled, but antenna is not forced*/ +//#define FORCE_WF_TX + +/*if define FORCE_WF_RX ,wf is not allow to do rx but antenna is not forced*/ +//#define FORCE_WF_RX + + +/*if define FORCE_WF_RX_TX wf is not allow to do any tx and rx , pa disabled , but antenna is not forced*/ +//#define FORCE_WF_RX_TX + +//#define WF_PAT_CFG_2012_05_19 +#define WF_PAT_CFG_2013_04_08 + +const u32 wifi_core_init_data_32_90_D[][2] = +{ +#ifdef FORCE_WF_RX_TX + {0x50000800,0xFC003E05}, + {0x50000804,0x00000000}, + {0x50000808,0xA5000013}, //no pre_active protect + {0x5000080c,0x000001C0}, + {0x50000810,0xFFCC0F01}, + {0x50000814,0x00000000}, // not grant to rx and tx + {0x50000818,0x00FF0001}, + {0x5000081C,0xFF000F00}, + {0x50000820,0x00000000}, + {0x50000824,0x0000F0FE}, + {0x50000828,0x00100F10}, + {0x50000838,0xFFFFFFFF}, + {0x5000083C,0xFFFFFFFF}, +#endif + +#ifdef FORCE_WF_RX + {0x50000800,0xFC003E05}, + {0x50000804,0x00000000}, + {0x50000808,0xA5000013}, //no pre_active protect + {0x5000080c,0x000001C0}, + {0x50000810,0xFFCC0F01}, + {0x50000814,0xFF000F00}, //wf not grant to rx + {0x50000818,0x00FF0001}, + {0x5000081C,0xFF000F00}, + {0x50000820,0xFF000F00}, + {0x50000824,0x0000F0FE}, + {0x50000828,0x00100F10}, + {0x50000838,0xFFFFFFFF}, + {0x5000083C,0xFFFFFFFF}, +#endif + +#ifdef FORCE_WF_TX + {0x50000800,0xFC003E05}, + {0x50000804,0x00000000}, + {0x50000808,0xA5000013}, //no pre_active protect + {0x5000080c,0x000001C0}, + {0x50000810,0xFFCC0F01}, + {0x50000814,0x00FF0033}, //wf not grant to tx + {0x50000818,0x00FF0001}, + {0x5000081C,0xFF000F00}, + {0x50000820,0x00000000}, + {0x50000824,0x0000F0FE}, + {0x50000828,0x00100F10}, + {0x50000838,0xFFFFFFFF}, + {0x5000083C,0xFFFFFFFF}, +#endif + +#ifdef WF_PAT_CFG_2012_05_19 + {0x50000800,0xFC003E05}, + {0x50000804,0x00000000}, + {0x50000808,0xA5000013}, //no pre_active protect + {0x5000080c,0x000001C0}, + {0x50000810,0xFFCC0F01}, + {0x50000814,0xFFFF0F03}, //0xFFFF0F33 + {0x50000818,0x00FF0001}, + {0x5000081C,0xFF000F00}, + {0x50000820,0xFF000F00}, + {0x50000824,0x0000F0FE}, + {0x50000828,0x00100F10}, + {0x50000838,0xFFFFFFFF}, + {0x5000083C,0xFFFFFFFF}, +#endif + +#ifdef WF_PAT_CFG_2013_04_08 + {0x50000800,0x00000000}, + {0x50000804,0x00200000}, //ack as high + {0x50000838,0x00101014}, + {0x5000083C,0x00333101}, + {0x50000808,0x75000013}, + {0x5000080c,0x000001C0}, + {0x50000810,0xFFFF0111}, + {0x50000814,0xFFFF0111}, + {0x50000818,0x00FF0011}, + {0x5000081C,0xFF000100}, + {0x50000820,0xFF000100}, + {0x50000824,0x0000FEEE}, + {0x50000828,0x00100F10}, + {0x50000834,0x00000000}, +#endif + +#ifdef FORCE_WF + {0x50000800,0xFC003E05}, + {0x50000804,0x00000000}, + {0x50000838,0xF8003f2A}, + {0x5000083c,0x00000003}, + {0x50000808,0xfe00001b}, + {0x50000810,0x00000000}, + {0x50000814,0x00000000}, + {0x50000818,0x00000000}, + {0x5000081C,0x00000000}, + {0x50000820,0x00000000}, + {0x50000824,0xffffffff}, + {0x50000828,0x00100F10}, +#endif + +#ifdef WF_PAT_CFG_2012_04_15 /*pta config*/ + {0x50000800,0xFC003E05}, //tx_pri hi bits ctrl&mgmt package + {0x50000804,0x00000000}, //tx_pri hi bits as hi pri + {0x50000808,0xA500001B}, //sig_mode and protect time + {0x5000080c,0x000001C0}, //sigWire mode + {0x50000810,0xFFCC0F01}, //Lut bt + {0x50000814,0xFFFF0F33}, //Lut wf + {0x50000818,0x00FF0001}, //antSel0 for wl_rx + {0x5000081C,0xFF000F00}, //antSel1 for wl_tx + {0x50000820,0xFF000F00}, //antSel2 for wl_pa + //{0x50000838,0xFFFFFFFF}, //rx_pri low bits as high pri + //{0x5000083C,0xFFFFFFFF}, //rx_pri high bits as high pri +#endif +/*end pta config*/ + { 0x00106b6c, 0x00000002 }, // scan channel 13 + { 0x30010004, 0x0000f77c }, //intn config + { 0x30010010, 0x00007dff }, //intn config + //item111:ver_b_wf_dig_2011_10_09 + { 0x30010000, 0x780369AF }, //disable tports wait 100ms; + { 0x30000010, 0x7000FFFF },//wait 500ms; + { 0x50090054, 0x00000001 },//enable update + { 0x50090200, 0x00000000 }, + { 0x50090204, 0x00000000 }, + { 0x50090208, 0x00000002 }, + { 0x5009020c, 0x00000004 }, + { 0x50090210, 0x00000006 }, + { 0x50090214, 0x00000008 }, + { 0x50090218, 0x0000000a }, + { 0x5009021c, 0x00000040 }, + { 0x50090220, 0x00000042 }, + { 0x50090224, 0x00000044 }, + { 0x50090228, 0x00000046 }, + { 0x5009022c, 0x00000048 }, + { 0x50090230, 0x0000004a }, + { 0x50090234, 0x00000080 }, + { 0x50090238, 0x00000082 }, + { 0x5009023c, 0x00000084 }, + { 0x50090240, 0x00000086 }, + { 0x50090244, 0x00000088 }, + { 0x50090248, 0x0000008a }, + { 0x5009024c, 0x000000c0 }, + { 0x50090250, 0x000000c2 }, + { 0x50090254, 0x000000c4 }, + { 0x50090258, 0x000000c6 }, + { 0x5009025c, 0x000000c8 }, + { 0x5009025c, 0x000000c8 }, + { 0x50090260, 0x000000ca }, + { 0x50090264, 0x00000100 }, + { 0x50090268, 0x00000102 }, + { 0x5009026c, 0x00000104 }, + { 0x50090270, 0x00000106 }, + { 0x50090274, 0x00000108 }, + { 0x50090278, 0x00000140 }, + { 0x5009027c, 0x00000142 },//lna =0 end + { 0x50090280, 0x00000080 }, + { 0x50090284, 0x00000082 }, + { 0x50090288, 0x00000084 }, + { 0x5009028c, 0x00000086 }, + { 0x50090290, 0x00000088 }, + { 0x50090294, 0x0000008a }, + { 0x50090298, 0x000000c0 }, + { 0x5009029c, 0x000000c2 }, + { 0x500902a0, 0x000000c4 }, + { 0x500902a4, 0x000000c6 }, + { 0x500902a8, 0x000000c8 }, + { 0x500902ac, 0x000000ca }, + { 0x500902b0, 0x00000100 }, + { 0x500902b4, 0x00000102 }, + { 0x500902b8, 0x00000104 }, + { 0x500902bc, 0x00000106 }, + { 0x500902c0, 0x00000108 }, + { 0x500902c4, 0x00000140 }, + { 0x500902c8, 0x00000142 }, + { 0x500902cc, 0x00000144 }, + { 0x500902d0, 0x00000146 }, + { 0x500902d4, 0x00000148 }, + { 0x500902d8, 0x00000180 }, + { 0x500902dc, 0x00000182 }, + { 0x500902e0, 0x00000184 }, + { 0x500902e4, 0x000001c0 }, + { 0x500902e8, 0x000001c2 }, + { 0x500902ec, 0x000001c4 }, + { 0x500902f0, 0x000001c6 }, + { 0x500902f4, 0x000001c8 }, + { 0x500902f8, 0x000001ca }, + { 0x500902fc, 0x000001cc },// lna = 01 end + { 0x50090300, 0x00000102 }, + { 0x50090304, 0x00000104 }, + { 0x50090308, 0x00000106 }, + { 0x5009030c, 0x00000108 }, + { 0x50090310, 0x00000140 }, + { 0x50090314, 0x00000142 }, + { 0x50090318, 0x00000144 }, + { 0x5009031c, 0x00000146 }, + { 0x50090320, 0x00000148 }, + { 0x50090324, 0x00000180 }, + { 0x50090328, 0x00000182 }, + { 0x5009032c, 0x00000184 }, + { 0x50090330, 0x000001c0 }, + { 0x50090334, 0x000001c2 }, + { 0x50090338, 0x000001c4 }, + { 0x5009033c, 0x000001c6 }, + { 0x50090340, 0x000001c8 }, + { 0x50090344, 0x000001c9 }, + { 0x50090348, 0x000001c9 }, + { 0x5009034c, 0x000001c9 }, + { 0x50090350, 0x000001c9 }, + { 0x50090354, 0x000001c9 }, + { 0x50090358, 0x000001c9 }, + { 0x5009035c, 0x000001c9 }, + { 0x50090360, 0x000001c9 }, + { 0x50090364, 0x000001c9 }, + { 0x50090368, 0x000001c9 }, + { 0x5009036c, 0x000001c9 }, + { 0x50090370, 0x000001c9 }, + { 0x50090374, 0x000001c9 }, + { 0x50090378, 0x000001c9 }, + { 0x5009037c, 0x000001c9 }, + { 0x50090054, 0x00000000 },//disable update + + { 0x5000050c, 0x00008000 },// for association power save + + //{ 0x50000808, 0x65000013 }, // disable prerx_priority;pta config + //{ 0x50000810, 0xFFCD0F01 }, //rx beacon priority + +}; + +const u32 wifi_core_init_data_32_90_E[][2] = +{ +#ifdef FORCE_WF_RX_TX + {0x50000800,0xFC003E05}, + {0x50000804,0x00000000}, + {0x50000808,0xA5000013}, //no pre_active protect + {0x5000080c,0x000001C0}, + {0x50000810,0xFFCC0F01}, + {0x50000814,0x00000000}, // not grant to rx and tx + {0x50000818,0x00FF0001}, + {0x5000081C,0xFF000F00}, + {0x50000820,0x00000000}, + {0x50000824,0x0000F0FE}, + {0x50000828,0x00100F10}, + {0x50000838,0xFFFFFFFF}, + {0x5000083C,0xFFFFFFFF}, +#endif + +#ifdef FORCE_WF_RX + {0x50000800,0xFC003E05}, + {0x50000804,0x00000000}, + {0x50000808,0xA5000013}, //no pre_active protect + {0x5000080c,0x000001C0}, + {0x50000810,0xFFCC0F01}, + {0x50000814,0xFF000F00}, //wf not grant to rx + {0x50000818,0x00FF0001}, + {0x5000081C,0xFF000F00}, + {0x50000820,0xFF000F00}, + {0x50000824,0x0000F0FE}, + {0x50000828,0x00100F10}, + {0x50000838,0xFFFFFFFF}, + {0x5000083C,0xFFFFFFFF}, +#endif + +#ifdef FORCE_WF_TX + {0x50000800,0xFC003E05}, + {0x50000804,0x00000000}, + {0x50000808,0xA5000013}, //no pre_active protect + {0x5000080c,0x000001C0}, + {0x50000810,0xFFCC0F01}, + {0x50000814,0x00FF0033}, //wf not grant to tx + {0x50000818,0x00FF0001}, + {0x5000081C,0xFF000F00}, + {0x50000820,0x00000000}, + {0x50000824,0x0000F0FE}, + {0x50000828,0x00100F10}, + {0x50000838,0xFFFFFFFF}, + {0x5000083C,0xFFFFFFFF}, +#endif + +#ifdef WF_PAT_CFG_2012_05_19 + {0x50000800,0xFC003E05}, + {0x50000804,0x00000000}, + {0x50000808,0xA5000013}, //no pre_active protect + {0x5000080c,0x000001C0}, + {0x50000810,0xFFCC0F01}, + {0x50000814,0xFFFF0F03}, //0xFFFF0F33 + {0x50000818,0x00FF0001}, + {0x5000081C,0xFF000F00}, + {0x50000820,0xFF000F00}, + {0x50000824,0x0000F0FE}, + {0x50000828,0x00100F10}, + {0x50000838,0xFFFFFFFF}, + {0x5000083C,0xFFFFFFFF}, +#endif + +#ifdef WF_PAT_CFG_2013_04_08 + {0x50000800,0x00000000}, + {0x50000804,0x00200000}, //ack as high + {0x50000838,0x00101014}, + {0x5000083C,0x00333101}, + {0x50000808,0x75000013}, + {0x5000080c,0x000001C0}, + {0x50000810,0xFFFF0111}, + {0x50000814,0xFFFF0111}, + {0x50000818,0x00FF0011}, + {0x5000081C,0xFF000100}, + {0x50000820,0xFF000100}, + {0x50000824,0x0000FEEE}, + {0x50000828,0x00100F10}, + {0x50000834,0x00000000}, +#endif + +#ifdef FORCE_WF + {0x50000800,0xFC003E05}, + {0x50000804,0x00000000}, + {0x50000838,0xF8003f2A}, + {0x5000083c,0x00000003}, + {0x50000808,0xfe00001b}, + {0x50000810,0x00000000}, + {0x50000814,0x00000000}, + {0x50000818,0x00000000}, + {0x5000081C,0x00000000}, + {0x50000820,0x00000000}, + {0x50000824,0xffffffff}, + {0x50000828,0x00100F10}, +#endif + +#ifdef WF_PAT_CFG_2012_04_15 /*pta config*/ + {0x50000800,0xFC003E05}, //tx_pri hi bits ctrl&mgmt package + {0x50000804,0x00000000}, //tx_pri hi bits as hi pri + {0x50000808,0xA500001B}, //sig_mode and protect time + {0x5000080c,0x000001C0}, //sigWire mode + {0x50000810,0xFFCC0F01}, //Lut bt + {0x50000814,0xFFFF0F33}, //Lut wf + {0x50000818,0x00FF0001}, //antSel0 for wl_rx + {0x5000081C,0xFF000F00}, //antSel1 for wl_tx + {0x50000820,0xFF000F00}, //antSel2 for wl_pa + //{0x50000838,0xFFFFFFFF}, //rx_pri low bits as high pri + //{0x5000083C,0xFFFFFFFF}, //rx_pri high bits as high pri +#endif + + { 0x30010004, 0x0000f77c }, //intn config + { 0x30010010, 0x00007dff }, //intn config + //item111:ver_b_wf_dig_2011_10_09 + { 0x30010000, 0x78036BAF }, //disable tports wait 100ms; + { 0x30000010, 0x7000FFFF },//wait 500ms; + { 0x5000050c, 0x00008000 },// for association power save +}; + +const u32 wifi_notch_data_90_D[][2] = +{ + //ch 1 + {0x001008d0, 0x50090040}, + {0x001008d4, 0x057213a2}, + {0x001008d8, 0x50090044}, + {0x001008dc, 0x10000000}, + //ch 2 + {0x00100910, 0x50090040}, + {0x00100914, 0x10000000}, + {0x00100918, 0x50090044}, + {0x0010091c, 0x10000000}, + //ch 3 + {0x00100950, 0x50090040}, + {0x00100954, 0x10000000}, + {0x00100958, 0x50090044}, + {0x0010095c, 0x10000000}, + //ch 4 + {0x00100990, 0x50090040}, + {0x00100994, 0x10000000}, + {0x00100998, 0x50090044}, + {0x0010099c, 0x10000000}, + //ch 5 + {0x001009d0, 0x50090040}, + {0x001009d4, 0x056794b4}, + {0x001009d8, 0x50090044}, + {0x001009dc, 0x10000000}, + //ch 6 + {0x00100a10, 0x50090040}, + {0x00100a14, 0x057c71de}, //Modified Accord To xiongzhi 0x077c71de----old + {0x00100a18, 0x50090044}, + {0x00100a1c, 0x10000000}, //Modified Accord To xiongzhi 0x046d242e----old + //ch 7 + {0x00100a50, 0x50090040}, + {0x00100a54, 0x057e7140}, + {0x00100a58, 0x50090044}, + {0x00100a5c, 0x10000000}, + //ch 8 + {0x00100a90, 0x50090040}, + {0x00100a94, 0x057c7e22}, //Modified Accord To xiongzhi 0x077c7e22----old + {0x00100a98, 0x50090044}, + {0x00100a9c, 0x10000000}, //Modified Accord To xiongzhi 0x046d2bd2----old + //ch 9 + {0x00100ad0, 0x50090040}, + {0x00100ad4, 0x10000000}, + {0x00100ad8, 0x50090044}, + {0x00100adc, 0x10000000}, + //ch 10 + {0x00100b10, 0x50090040}, + {0x00100b14, 0x10000000}, + {0x00100b18, 0x50090044}, + {0x00100b1c, 0x10000000}, + //ch 11 + {0x00100b50, 0x50090040}, + {0x00100b54, 0x10000000}, + {0x00100b58, 0x50090044}, + {0x00100b5c, 0x10000000}, + //ch 12 + {0x00100b90, 0x50090040}, + {0x00100b94, 0x05764310}, + {0x00100b98, 0x50090044}, + {0x00100b9c, 0x10000000}, + //ch 13 + {0x00100bd0, 0x50090040}, + {0x00100bd4, 0x056794b4}, + {0x00100bd8, 0x50090044}, + {0x00100bdc, 0x10000000}, + //ch 14 + {0x00100c10, 0x50090040}, + {0x00100c14, 0x0579c279}, + {0x00100c18, 0x50090044}, + {0x00100c1c, 0x0579cd87}, +}; + +const u32 wifi_notch_data_90_E[][2] = +{ + // For Verion E + //ch 1 + {0x001007CC, 0x50090040}, + {0x001007D0, 0x057213a2}, + {0x001007D4, 0x50090044}, + {0x001007D8, 0x10000000}, + //ch 2 + {0x001007FC, 0x50090040}, + {0x00100800, 0x10000000}, + {0x00100804, 0x50090044}, + {0x00100808, 0x10000000}, + //ch 3 + {0x0010082C, 0x50090040}, + {0x00100830, 0x10000000}, + {0x00100834, 0x50090044}, + {0x00100838, 0x10000000}, + //ch 4 + {0x0010085C, 0x50090040}, + {0x00100860, 0x10000000}, + {0x00100864, 0x50090044}, + {0x00100868, 0x10000000}, + //ch 5 + {0x0010088C, 0x50090040}, + {0x00100890, 0x056794b4}, + {0x00100894, 0x50090044}, + {0x00100898, 0x10000000}, + //ch 6 + {0x001008BC, 0x50090040}, + {0x001008C0, 0x057c71de}, + {0x001008C4, 0x50090044}, + {0x001008C8, 0x10000000}, + //ch 7 + {0x001008EC, 0x50090040}, + {0x001008F0, 0x057e7140}, + {0x001008F4, 0x50090044}, + {0x001008F8, 0x10000000}, + //ch 8 + {0x0010091C, 0x50090040}, + {0x00100920, 0x057c7e22}, + {0x00100924, 0x50090044}, + {0x00100928, 0x10000000}, + //ch 9 + {0x0010094C, 0x50090040}, + {0x00100950, 0x10000000}, + {0x00100954, 0x50090044}, + {0x00100958, 0x10000000}, + //ch 10 + {0x0010097C, 0x50090040}, + {0x00100980, 0x10000000}, + {0x00100984, 0x50090044}, + {0x00100988, 0x10000000}, + //ch 11 + {0x001009AC, 0x50090040}, + {0x001009B0, 0x10000000}, + {0x001009B4, 0x50090044}, + {0x001009B8, 0x10000000}, + //ch 12 + {0x001009DC, 0x50090040}, + {0x001009E0, 0x05764310}, + {0x001009E4, 0x50090044}, + {0x001009E8, 0x10000000}, + //ch 13 + {0x00100A0C, 0x50090040}, + {0x00100A10, 0x056794b4}, + {0x00100A14, 0x50090044}, + {0x00100A18, 0x10000000}, + //ch 14 + {0x00100A3C, 0x50090040}, + {0x00100A40, 0x0579c279}, + {0x00100A44, 0x50090044}, + {0x00100A4c, 0x0579cd87}, +}; + +//common sdio clock open +const u32 wifi_core_data_wake[][2] = +{ + {0x3001003c, 0x2e00a000}, +}; +//sleep sdio switch +const u32 wifi_core_data_sleep[][2] = +{ + {0x3001003c, 0x2e00a100}, +}; + +const u32 wifi_phy_timeout_cfg_90[][2] = +{ + {0x50000634, 0x00001100}, + {0x50000584, 0x00005BF8}, +}; + +static const u32 wifi_test_mode_rx_notch_32_90[][2] = +{ + //item:notch_filter_5 + {0x50090040,0x076794b4},//8m + {0x50090044,0x10000000}, + //item:notch_filter_6 + {0x50090040,0x057c71de},//3m + {0x50090044,0x10000000},//7m + //item:notch_filter_7 + {0x50090040,0x077e7ec0},//2m + {0x50090044,0x077e7140},//-2m + //item:notch_filter_8 + {0x50090040,0x057c7e22},//3m + {0x50090044,0x10000000},//7m + //item:notch_filter_c + {0x50090040,0x07764310},//5m + {0x50090044,0x10000000}, + //item:notch_filter_e + {0x50090040,0x0779c279},//4m + {0x50090044,0x0779cd87},//-4m + //item:disable_notch + {0x50090040,0x10000000}, + {0x50090044,0x10000000}, +}; + +static const u32 wifi_test_mode_agc_patch32_90[][2] = + { + {0x50000600,0x0000501a},//write 1a(52) to 28h hightolow + {0x50000600,0x0000520d},//write 0d(26) to 29h hightomid + {0x50000600,0x00006a1e},//35h reg coarse2 upper window from 0d to 1a for l + //;50000600H,32'h00009890;//4ch reg unlock upper threshold from 70 to 90 + {0x50000600,0x00009a38},//4dh reg unlock lower threshold from 78 to 38 + {0x50000600,0x00007207},//39h reg change vga gain ,9 -> 7 for big signal + {0x50000600,0x0001c8f5},//e4h reg change hpf coeff to f5 + {0x50000600,0x00004200},//21h reg add fine gain 0db + {0x50000600,0x00004610},//23h reg change maxgain index as agc table + {0x50000600,0x0000900e},//48h reg unlock lower threshold change from 0a to + {0x50000600,0x00004a00},//25h reg pecket dection threshold + {0x50000600,0x000040a8},//20h reg add fine itr2 98->a8 + {0x50000600,0x00007e05},//3f reg rssi window for fine itr2 0->5 + {0x50000600,0x00008237},//41 reg fine itr1 nextstate 4->3 + {0x50000600,0x00008440},//42 reg fine itr2 nextstate 0->4 settle time 0->d + {0x50000600,0x0000b6a9},//5b reg change GreatN rssi avg count from 1 to 8 +} ; + +static const u32 wlan_test_mode_digital32_90[][2] = +{ + //item111:ver_D_wf_dig_20120208 + {0x30010000,0x780369AF}, //disable tports + //wait 100ms; + {0x30000010,0x7000FFFF}, + //item:agc_table_20110921 + {0x50090054,0x00000001},//enable update + {0x50090200,0x00000000}, + {0x50090204,0x00000000}, + {0x50090208,0x00000002}, + {0x5009020c,0x00000004}, + {0x50090210,0x00000006}, + {0x50090214,0x00000008}, + {0x50090218,0x0000000a}, + {0x5009021c,0x00000040}, + {0x50090220,0x00000042}, + {0x50090224,0x00000044}, + {0x50090228,0x00000046}, + {0x5009022c,0x00000048}, + {0x50090230,0x0000004a}, + {0x50090234,0x00000080}, + {0x50090238,0x00000082}, + {0x5009023c,0x00000084}, + {0x50090240,0x00000086}, + {0x50090244,0x00000088}, + {0x50090248,0x0000008a}, + {0x5009024c,0x000000c0}, + {0x50090250,0x000000c2}, + {0x50090254,0x000000c4}, + {0x50090258,0x000000c6}, + {0x5009025c,0x000000c8}, + {0x50090260,0x000000ca}, + {0x50090264,0x00000100}, + {0x50090268,0x00000102}, + {0x5009026c,0x00000104}, + {0x50090270,0x00000106}, + {0x50090274,0x00000108}, + {0x50090278,0x00000140}, + {0x5009027c,0x00000142},//lna =0 end + {0x50090280,0x00000080}, + {0x50090284,0x00000082}, + {0x50090288,0x00000084}, + {0x5009028c,0x00000086}, + {0x50090290,0x00000088}, + {0x50090294,0x0000008a}, + {0x50090298,0x000000c0}, + {0x5009029c,0x000000c2}, + {0x500902a0,0x000000c4}, + {0x500902a4,0x000000c6}, + {0x500902a8,0x000000c8}, + {0x500902ac,0x000000ca}, + {0x500902b0,0x00000100}, + {0x500902b4,0x00000102}, + {0x500902b8,0x00000104}, + {0x500902bc,0x00000106}, + {0x500902c0,0x00000108}, + {0x500902c4,0x00000140}, + {0x500902c8,0x00000142}, + {0x500902cc,0x00000144}, + {0x500902d0,0x00000146}, + {0x500902d4,0x00000148}, + {0x500902d8,0x00000180}, + {0x500902dc,0x00000182}, + {0x500902e0,0x00000184}, + {0x500902e4,0x000001c0}, + {0x500902e8,0x000001c2}, + {0x500902ec,0x000001c4}, + {0x500902f0,0x000001c6}, + {0x500902f4,0x000001c8}, + {0x500902f8,0x000001ca}, + {0x500902fc,0x000001cc},// lna = 01 end + {0x50090300,0x00000102}, + {0x50090304,0x00000104}, + {0x50090308,0x00000106}, + {0x5009030c,0x00000108}, + {0x50090310,0x00000140}, + {0x50090314,0x00000142}, + {0x50090318,0x00000144}, + {0x5009031c,0x00000146}, + {0x50090320,0x00000148}, + {0x50090324,0x00000180}, + {0x50090328,0x00000182}, + {0x5009032c,0x00000184}, + {0x50090330,0x000001c0}, + {0x50090334,0x000001c2}, + {0x50090338,0x000001c4}, + {0x5009033c,0x000001c6}, + {0x50090340,0x000001c8}, + {0x50090344,0x000001c9}, + {0x50090348,0x000001c9}, + {0x5009034c,0x000001c9}, + {0x50090350,0x000001c9}, + {0x50090354,0x000001c9}, + {0x50090358,0x000001c9}, + {0x5009035c,0x000001c9}, + {0x50090360,0x000001c9}, + {0x50090364,0x000001c9}, + {0x50090368,0x000001c9}, + {0x5009036c,0x000001c9}, + {0x50090370,0x000001c9}, + {0x50090374,0x000001c9}, + {0x50090378,0x000001c9}, + {0x5009037c,0x000001c9}, + {0x50090054,0x00000000},//disable update + {0x50000808,0x65000013}, // disable prerx_prio + //pta config + {0x50000810,0xFFCD0F01}, //rx beacon priority +}; + +#endif + diff --git a/drivers/net/wireless/rda/rda_wlan/wlan_sdio_patch_91.h b/drivers/net/wireless/rda/rda_wlan/wlan_sdio_patch_91.h new file mode 100755 index 00000000..d3485916 --- /dev/null +++ b/drivers/net/wireless/rda/rda_wlan/wlan_sdio_patch_91.h @@ -0,0 +1,754 @@ +#ifndef __WLAN_SDIO_PATCH_91_H__ +#define __WLAN_SDIO_PATCH_91_H__ + +static const u32 wifi_core_patch_data_32_91[][2] = { + // add for pta + {0x50000828,0x00100FFD}, + {0x50000810,0xFFFF0F0F}, + {0x50000814,0xFFFF0F0F}, + {0x50000818,0x00FF000F}, + {0x5000081C,0xFF000F00}, + {0x50000820,0xFF000F00}, + {0x50000824,0x0000F0F0}, + // add for pta + {0x0010FFFC, 0x20131231}, + {0x00110000, 0xEA03ECE7}, + {0x00110004, 0xE59D0000}, + {0x00110008, 0xE3C01008}, + {0x0011000C, 0xE58D1000}, + {0x00110010, 0xE3A00030}, + {0x00110014, 0xEB000001}, + {0x00110018, 0xE3A0100C}, + {0x0011001C, 0xE59FF004}, + {0x00110020, 0xE51FF004}, + {0x00110024, 0x0001D33C}, + {0x00110028, 0x00014C64}, + {0x0011002C, 0xEA03E563}, + {0x00110030, 0xE3130008}, + {0x00110034, 0x159F0020}, + {0x00110038, 0x1A000002}, + {0x0011003C, 0xE3130004}, + {0x00110040, 0x059F000C}, + {0x00110044, 0x159F000C}, + {0x00110048, 0xE5840008}, + {0x0011004C, 0xE3A00010}, + {0x00110050, 0xE59FF008}, + {0x00110054, 0x00010140}, + {0x00110058, 0x00010141}, + {0x0011005C, 0x00010142}, + {0x00110060, 0x00016AA0}, + {0x00110064, 0xEA03CB40}, + {0x00110068, 0xE1A02004}, + {0x0011006C, 0xE1A02822}, + {0x00110070, 0xE202207F}, + {0x00110074, 0xE3520029}, + {0x00110078, 0x1A000010}, + {0x0011007C, 0xE1A04804}, + {0x00110080, 0xE1A04824}, + {0x00110084, 0xE59F003C}, + {0x00110088, 0xE1540000}, + {0x0011008C, 0x059F1040}, + {0x00110090, 0xE59F0034}, + {0x00110094, 0xE1540000}, + {0x00110098, 0x059F1038}, + {0x0011009C, 0xE59F002C}, + {0x001100A0, 0xE1540000}, + {0x001100A4, 0x059F1030}, + {0x001100A8, 0xE3A027C0}, + {0x001100AC, 0xE3A04028}, + {0x001100B0, 0xE1A04804}, + {0x001100B4, 0xE1824004}, + {0x001100B8, 0xE1844001}, + {0x001100BC, 0xE59F101C}, + {0x001100C0, 0xE5814034}, + {0x001100C4, 0xE59FF018}, + {0x001100C8, 0x00009468}, + {0x001100CC, 0x0000D468}, + {0x001100D0, 0x00001468}, + {0x001100D4, 0x00001F20}, + {0x001100D8, 0x00001320}, + {0x001100DC, 0x00001320}, + {0x001100E0, 0x50090000}, + {0x001100E4, 0x0001D364}, + {0x001100E8, 0xEA03D7EB}, + {0x001100EC, 0xE59F0010}, + {0x001100F0, 0xE3A04003}, + {0x001100F4, 0xE5804000}, + {0x001100F8, 0xE59F4008}, + {0x001100FC, 0xE5940000}, + {0x00110100, 0xE59FF004}, + {0x00110104, 0x50000228}, + {0x00110108, 0x00100B08}, + {0x0011010C, 0x0001A13C}, + {0x00110110, 0xEA03ED23}, + {0x00110114, 0xE3510000}, + {0x00110118, 0xE51FF004}, + {0x0011011C, 0x00014C84}, + {0x00110120, 0xEA03FC88}, + {0x00110124, 0xE1C510B8}, + {0x00110128, 0xE3510015}, + {0x0011012C, 0xBA00001D}, + {0x00110130, 0xE59F2074}, + {0x00110134, 0xE3A01020}, + {0x00110138, 0xE5C21000}, + {0x0011013C, 0xEB000019}, + {0x00110140, 0xE59F2068}, + {0x00110144, 0xE5921020}, + {0x00110148, 0xE3110A80}, + {0x0011014C, 0x1AFFFFFC}, + {0x00110150, 0xE1D510B8}, + {0x00110154, 0xE1A01221}, + {0x00110158, 0xE2811030}, + {0x0011015C, 0xE5C21000}, + {0x00110160, 0xE5921020}, + {0x00110164, 0xE3110A80}, + {0x00110168, 0x1AFFFFFC}, + {0x0011016C, 0xE1D510B8}, + {0x00110170, 0xE201100F}, + {0x00110174, 0xE351000A}, + {0x00110178, 0xA2811037}, + {0x0011017C, 0xB2811030}, + {0x00110180, 0xE5C21000}, + {0x00110184, 0xE5921020}, + {0x00110188, 0xE3110A80}, + {0x0011018C, 0x1AFFFFFC}, + {0x00110190, 0xE3A0100D}, + {0x00110194, 0xE5C21000}, + {0x00110198, 0xE5921020}, + {0x0011019C, 0xE3110A80}, + {0x001101A0, 0x1AFFFFFC}, + {0x001101A4, 0xE3A0100A}, + {0x001101A8, 0xE59FF004}, + {0x001101AC, 0x50300038}, + {0x001101B0, 0x50060000}, + {0x001101B4, 0x00010F00}, + {0x001101B8, 0xEA040A9C}, + {0x001101BC, 0xE59F2038}, + {0x001101C0, 0xE1D210B0}, + {0x001101C4, 0xE3510020}, + {0x001101C8, 0xCA000002}, + {0x001101CC, 0xE51F2028}, + {0x001101D0, 0xE3A01010}, + {0x001101D4, 0xE5C21000}, + {0x001101D8, 0xE3560000}, + {0x001101DC, 0xE59FF01C}, + {0x001101E0, 0xE1A00000}, + {0x001101E4, 0xE1A00000}, + {0x001101E8, 0xE1A00000}, + {0x001101EC, 0xE1A00000}, + {0x001101F0, 0xE1A00000}, + {0x001101F4, 0xE1A00000}, + {0x001101F8, 0xE1A00000}, + {0x001101FC, 0x00106310}, + {0x00110200, 0x0000D748}, + {0x00110204, 0xEA0403F6}, + {0x00110208, 0xE5CD0018}, + {0x0011020C, 0xE51F0018}, + {0x00110210, 0xE1D010B0}, + {0x00110214, 0xE3510020}, + {0x00110218, 0xCA000002}, + {0x0011021C, 0xE51F0078}, + {0x00110220, 0xE3A01010}, + {0x00110224, 0xE5C01000}, + {0x00110228, 0xE59FF01C}, + {0x0011022C, 0xE1A00000}, + {0x00110230, 0xE1A00000}, + {0x00110234, 0xE1A00000}, + {0x00110238, 0xE1A00000}, + {0x0011023C, 0xE1A00000}, + {0x00110240, 0xE1A00000}, + {0x00110244, 0xE1A00000}, + {0x00110248, 0x50060000}, + {0x0011024C, 0x0000F22C}, + {0x00110250, 0xEA03FB4F}, + {0x00110254, 0xE59F2014}, + {0x00110258, 0xE3500000}, + {0x0011025C, 0x03A01000}, + {0x00110260, 0x13A01001}, + {0x00110264, 0xE5C21000}, + {0x00110268, 0xE3500000}, + {0x0011026C, 0xE59FF000}, + {0x00110270, 0x001102C0}, + {0x00110274, 0x00011514}, + {0x00110278, 0xEA03ED3C}, + {0x0011027C, 0xE59D0000}, + {0x00110280, 0xE3C01008}, + {0x00110284, 0xE58D1000}, + {0x00110288, 0xE3A00030}, + {0x0011028C, 0xEBFFFF63}, + {0x00110290, 0xE3A0100C}, + {0x00110294, 0xE51FF004}, + {0x00110298, 0x00014D88}, + {0x0011029C, 0xEA03ED77}, + {0x001102A0, 0xE3500000}, + {0x001102A4, 0xE59FF00C}, + {0x001102A8, 0xE1A00000}, + {0x001102AC, 0xE1A00000}, + {0x001102B0, 0xE1A00000}, + {0x001102B4, 0xE1A00000}, + {0x001102B8, 0x00014CC0}, + {0x001102BC, 0xEA03EDDF}, + {0x001102C0, 0xE59D0000}, + {0x001102C4, 0xE3C01008}, + {0x001102C8, 0xE58D1000}, + {0x001102CC, 0xE3A00030}, + {0x001102D0, 0xEBFFFF52}, + {0x001102D4, 0xE3A0100C}, + {0x001102D8, 0xE51FF004}, + {0x001102DC, 0x00014B40}, + {0x001102E0, 0xEA043462}, + {0x001102E4, 0xE1A00000}, + {0x001102E8, 0xE1A00000}, + {0x001102EC, 0xE51FF004}, + {0x001102F0, 0x00003158}, + {0x001102F4, 0xEA041567}, + {0x001102F8, 0xE5940004}, + {0x001102FC, 0xE3800850}, + {0x00110300, 0xE5840004}, + {0x00110304, 0xE3A00000}, + {0x00110308, 0xE51FF004}, + {0x0011030C, 0x0000AD58}, + {0x00110310, 0xEA04300D}, + {0x00110314, 0xE59F0028}, + {0x00110318, 0xE5840584}, + {0x0011031C, 0xE59F0024}, + {0x00110320, 0xE59F1024}, + {0x00110324, 0xE5810000}, + {0x00110328, 0xE59F1020}, + {0x0011032C, 0xE3A00003}, + {0x00110330, 0xE5810000}, + {0x00110334, 0xE59F001C}, + {0x00110338, 0xE59F1014}, + {0x0011033C, 0xE5810000}, + {0x00110340, 0xE59FF014}, + {0x00110344, 0x0000FFFB}, + {0x00110348, 0x00000030}, + {0x0011034C, 0x5000020C}, + {0x00110350, 0x50000200}, + {0x00110354, 0x30000014}, + {0x00110358, 0x25801B0A}, + {0x0011035C, 0x000042DC}, + {0x00110360, 0xEA040074}, + {0x00110364, 0xE1A00000}, + {0x00110368, 0xE51FF004}, + {0x0011036C, 0x000101E0}, + {0x00110370, 0xEA03EE04}, + {0x00110374, 0xE3510000}, + {0x00110378, 0xE51FF004}, + {0x0011037C, 0x00014B60}, + {0x00110380, 0xEA03ED76}, + {0x00110384, 0xE3510000}, + {0x00110388, 0xE51FF004}, + {0x0011038C, 0x00014DA8}, + {0x00110390, 0xEA03EDFD}, + {0x00110394, 0xE3500000}, + {0x00110398, 0xE51FF004}, + {0x0011039C, 0x00014B9C}, + {0x001103A0, 0xEA03ED6F}, + {0x001103A4, 0xE3500000}, + {0x001103A8, 0xE51FF004}, + {0x001103AC, 0x00014DE4}, + {0x001103B0, 0xEA03FEA3}, + {0x001103B4, 0xE1A00000}, + {0x001103B8, 0xE51FF004}, + {0x001103BC, 0x00010924}, + {0x001103C0, 0xEA0420C9}, + {0x001103C4, 0xE59F103C}, + {0x001103C8, 0x03A00000}, + {0x001103CC, 0x05810000}, + {0x001103D0, 0x0A000007}, + {0x001103D4, 0xE5910000}, + {0x001103D8, 0xE2800001}, + {0x001103DC, 0xE3500002}, + {0x001103E0, 0x35810000}, + {0x001103E4, 0x3A000004}, + {0x001103E8, 0xE3A00000}, + {0x001103EC, 0xE5810000}, + {0x001103F0, 0xEAFFFFFF}, + {0x001103F4, 0xE51FF004}, + {0x001103F8, 0x0000809C}, + {0x001103FC, 0xE51FF004}, + {0x00110400, 0x000080E0}, + {0x00110404, 0x00000000}, + {0x00110408, 0x00110404}, + {0x0011040C, 0xEA03D8AA}, + {0x00110410, 0xE5C51000}, + {0x00110414, 0xE1A00001}, + {0x00110418, 0xE3A01032}, + {0x0011041C, 0xE1500001}, + {0x00110420, 0x3A000003}, + {0x00110424, 0xE3A00001}, + {0x00110428, 0xE3A02000}, + {0x0011042C, 0xE3A01000}, + {0x00110430, 0xE59FF004}, + {0x00110434, 0xE51FF004}, + {0x00110438, 0x0001A1AC}, + {0x0011043C, 0x0001A1A4}, + {0x00110440, 0xEA0438AC}, + {0x00110444, 0xE1A000A0}, + {0x00110448, 0xE51FF004}, + {0x0011044C, 0x00002190}, + {0x00110450, 0xEA04389C}, + {0x00110454, 0xE3A00002}, + {0x00110458, 0xE51FF004}, + {0x0011045C, 0x000021E0}, + {0x00110460, 0xEA041C47}, + {0x00110464, 0xE3A03000}, + {0x00110468, 0xE5D11000}, + {0x0011046C, 0xE5802010}, + {0x00110470, 0xE5803044}, + {0x00110474, 0xE3510001}, + {0x00110478, 0x13A01003}, + {0x0011047C, 0x03A01009}, + {0x00110480, 0xE5A01014}, + {0x00110484, 0xE5803034}, + {0x00110488, 0xE51FF004}, + {0x0011048C, 0x00009364}, + {0x20040004, 0x00014C60}, + {0x20040024, 0x00110000}, + {0x20040008, 0x00016A9C}, + {0x20040028, 0x0011002C}, + {0x2004000C, 0x0001D360}, + {0x2004002C, 0x00110064}, + {0x20040010, 0x0001A138}, + {0x20040030, 0x001100E8}, + {0x20040014, 0x00014C80}, + {0x20040034, 0x00110110}, + {0x20040018, 0x00010EFC}, + {0x20040038, 0x00110120}, + {0x2004001C, 0x0000D744}, + {0x2004003C, 0x001101B8}, + {0x20040020, 0x0000F228}, + {0x20040040, 0x00110204}, + {0x20040100, 0x00011510}, + {0x20040120, 0x00110250}, + {0x20040104, 0x00014D84}, + {0x20040124, 0x00110278}, + {0x20040108, 0x00014CBC}, + {0x20040128, 0x0011029C}, + {0x2004010C, 0x00014B3C}, + {0x2004012C, 0x001102BC}, + {0x20040110, 0x00003154}, + {0x20040130, 0x001102E0}, + {0x20040114, 0x0000AD54}, + {0x20040134, 0x001102F4}, + {0x20040118, 0x000042D8}, + {0x20040138, 0x00110310}, + {0x2004011C, 0x0001018C}, + {0x2004013C, 0x00110360}, + {0x20040140, 0x00014B5C}, + {0x20040180, 0x00110370}, + {0x20040144, 0x00014DA4}, + {0x20040184, 0x00110380}, + {0x20040148, 0x00014B98}, + {0x20040188, 0x00110390}, + {0x2004014C, 0x00014DE0}, + {0x2004018C, 0x001103A0}, + {0x20040150, 0x00010920}, + {0x20040190, 0x001103B0}, + {0x20040154, 0x00008098}, + {0x20040194, 0x001103C0}, + {0x20040158, 0x0001A160}, + {0x20040198, 0x0011040C}, + {0x2004015C, 0x0000218C}, + {0x2004019C, 0x00110440}, + {0x20040160, 0x000021DC}, + {0x200401A0, 0x00110450}, + {0x20040164, 0x00009340}, + {0x200401A4, 0x00110460}, + {0x20040000, 0x03FFFEFF}, +}; +#define SET_CHANNEL_MEM_TABLE_BASE 0x00107C98 +#define SET_CHANNEL_RF_TABLE_BASE 0x00107F38 +static const u32 wifi_clock_switch_91[][2] = { + //channel 1 + {SET_CHANNEL_MEM_TABLE_BASE, 0x50090048}, + {SET_CHANNEL_MEM_TABLE_BASE + 0x04, 0x604199C4}, + {SET_CHANNEL_MEM_TABLE_BASE + 0x08, 0x50000654}, + {SET_CHANNEL_MEM_TABLE_BASE + 0x0C, 0x2222CFCF}, + + //channel 2 + {SET_CHANNEL_MEM_TABLE_BASE + 0x30, 0x50090048}, + {SET_CHANNEL_MEM_TABLE_BASE + 0x34, 0x604199C4}, + {SET_CHANNEL_MEM_TABLE_BASE + 0x38, 0x50000654}, + {SET_CHANNEL_MEM_TABLE_BASE + 0x3C, 0x2222CFCF}, + + //channel 3 + {SET_CHANNEL_MEM_TABLE_BASE + 0x60, 0x50090048}, + {SET_CHANNEL_MEM_TABLE_BASE + 0x64, 0x604199C4}, + {SET_CHANNEL_MEM_TABLE_BASE + 0x68, 0x50000654}, + {SET_CHANNEL_MEM_TABLE_BASE + 0x6C, 0x2222CFCF}, + + //channel 4 + {SET_CHANNEL_MEM_TABLE_BASE + 0x90, 0x50090048}, + {SET_CHANNEL_MEM_TABLE_BASE + 0x94, 0x604199C4}, + {SET_CHANNEL_MEM_TABLE_BASE + 0x98, 0x50000654}, + {SET_CHANNEL_MEM_TABLE_BASE + 0x9C, 0x2222CFCF}, + + //channel 5 + {SET_CHANNEL_MEM_TABLE_BASE + 0xC0, 0x50090048}, + {SET_CHANNEL_MEM_TABLE_BASE + 0xC4, 0x204199C4}, + {SET_CHANNEL_MEM_TABLE_BASE + 0xC8, 0x50000654}, + {SET_CHANNEL_MEM_TABLE_BASE + 0xCC, 0x2222CFCF}, + + //channel 6 + {SET_CHANNEL_MEM_TABLE_BASE + 0xF0, 0x50090048}, + {SET_CHANNEL_MEM_TABLE_BASE + 0xF4, 0x204199C4}, + {SET_CHANNEL_MEM_TABLE_BASE + 0xF8, 0x50000654}, + {SET_CHANNEL_MEM_TABLE_BASE + 0xFC, 0x2222CFCF}, + + //channel 7 + {SET_CHANNEL_MEM_TABLE_BASE + 0x120, 0x50090048}, + {SET_CHANNEL_MEM_TABLE_BASE + 0x124, 0x204199C4}, + {SET_CHANNEL_MEM_TABLE_BASE + 0x128, 0x50000654}, + {SET_CHANNEL_MEM_TABLE_BASE + 0x12C, 0x2222CFCF}, + + //channel 8 + {SET_CHANNEL_MEM_TABLE_BASE + 0x150, 0x50090048}, + {SET_CHANNEL_MEM_TABLE_BASE + 0x154, 0x204199C4}, + {SET_CHANNEL_MEM_TABLE_BASE + 0x158, 0x50000654}, + {SET_CHANNEL_MEM_TABLE_BASE + 0x15C, 0x2222CFCF}, + + //channel 9 + {SET_CHANNEL_MEM_TABLE_BASE + 0x180, 0x50090048}, + {SET_CHANNEL_MEM_TABLE_BASE + 0x184, 0x604199C4}, + {SET_CHANNEL_MEM_TABLE_BASE + 0x188, 0x50000654}, + {SET_CHANNEL_MEM_TABLE_BASE + 0x18C, 0x2222CFCF}, + + //channel 10 + {SET_CHANNEL_MEM_TABLE_BASE + 0x1B0, 0x50090048}, + {SET_CHANNEL_MEM_TABLE_BASE + 0x1B4, 0x604199C4}, + {SET_CHANNEL_MEM_TABLE_BASE + 0x1B8, 0x50000654}, + {SET_CHANNEL_MEM_TABLE_BASE + 0x1BC, 0x2222CFCF}, + + //channel 11 + {SET_CHANNEL_MEM_TABLE_BASE + 0x1E0, 0x50090048}, + {SET_CHANNEL_MEM_TABLE_BASE + 0x1E4, 0x604199C4}, + {SET_CHANNEL_MEM_TABLE_BASE + 0x1E8, 0x50000654}, + {SET_CHANNEL_MEM_TABLE_BASE + 0x1EC, 0x2222CFCF}, + + //channel 12 + {SET_CHANNEL_MEM_TABLE_BASE + 0x210, 0x50090048}, + {SET_CHANNEL_MEM_TABLE_BASE + 0x214, 0x604199C4}, + {SET_CHANNEL_MEM_TABLE_BASE + 0x218, 0x50000654}, + {SET_CHANNEL_MEM_TABLE_BASE + 0x21C, 0x2222CFCF}, + + //channel 13 + {SET_CHANNEL_MEM_TABLE_BASE + 0x240, 0x50090048}, + {SET_CHANNEL_MEM_TABLE_BASE + 0x244, 0x304199C4}, + {SET_CHANNEL_MEM_TABLE_BASE + 0x248, 0x50000654}, + {SET_CHANNEL_MEM_TABLE_BASE + 0x24C, 0x2222CFCF}, + + //channel 1 + {SET_CHANNEL_RF_TABLE_BASE, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE + 0x04, 0x00000001}, + {SET_CHANNEL_RF_TABLE_BASE + 0x08, 0x00000038}, + {SET_CHANNEL_RF_TABLE_BASE + 0x0C, 0x00000808}, + {SET_CHANNEL_RF_TABLE_BASE + 0x10, 0x0000003E}, + {SET_CHANNEL_RF_TABLE_BASE + 0x14, 0x0000AA00}, + {SET_CHANNEL_RF_TABLE_BASE + 0x18, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE + 0x1C, 0x00000000}, + + //channel 2 + {SET_CHANNEL_RF_TABLE_BASE + 0x40, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE + 0x44, 0x00000001}, + {SET_CHANNEL_RF_TABLE_BASE + 0x48, 0x00000038}, + {SET_CHANNEL_RF_TABLE_BASE + 0x4C, 0x00000808}, + {SET_CHANNEL_RF_TABLE_BASE + 0x50, 0x0000003E}, + {SET_CHANNEL_RF_TABLE_BASE + 0x54, 0x0000AA00}, + {SET_CHANNEL_RF_TABLE_BASE + 0x58, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE + 0x5C, 0x00000000}, + + //channel 3 + {SET_CHANNEL_RF_TABLE_BASE + 0x80, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE + 0x84, 0x00000001}, + {SET_CHANNEL_RF_TABLE_BASE + 0x88, 0x00000038}, + {SET_CHANNEL_RF_TABLE_BASE + 0x8C, 0x00000808}, + {SET_CHANNEL_RF_TABLE_BASE + 0x90, 0x0000003E}, + {SET_CHANNEL_RF_TABLE_BASE + 0x94, 0x0000AA00}, + {SET_CHANNEL_RF_TABLE_BASE + 0x98, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE + 0x9C, 0x00000000}, + + //channel 4 + {SET_CHANNEL_RF_TABLE_BASE + 0xC0, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE + 0xC4, 0x00000001}, + {SET_CHANNEL_RF_TABLE_BASE + 0xC8, 0x00000038}, + {SET_CHANNEL_RF_TABLE_BASE + 0xCC, 0x00000808}, + {SET_CHANNEL_RF_TABLE_BASE + 0xD0, 0x0000003E}, + {SET_CHANNEL_RF_TABLE_BASE + 0xD4, 0x0000AA00}, + {SET_CHANNEL_RF_TABLE_BASE + 0xD8, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE + 0xDC, 0x00000000}, + + //channel 5 + {SET_CHANNEL_RF_TABLE_BASE + 0x100, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE + 0x104, 0x00000001}, + {SET_CHANNEL_RF_TABLE_BASE + 0x108, 0x00000038}, + {SET_CHANNEL_RF_TABLE_BASE + 0x10C, 0x00000908}, + {SET_CHANNEL_RF_TABLE_BASE + 0x110, 0x0000003E}, + {SET_CHANNEL_RF_TABLE_BASE + 0x114, 0x0000AA00}, + {SET_CHANNEL_RF_TABLE_BASE + 0x118, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE + 0x11C, 0x00000000}, + + //channel 6 + {SET_CHANNEL_RF_TABLE_BASE + 0x140, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE + 0x144, 0x00000001}, + {SET_CHANNEL_RF_TABLE_BASE + 0x148, 0x00000038}, + {SET_CHANNEL_RF_TABLE_BASE + 0x14C, 0x00000908}, + {SET_CHANNEL_RF_TABLE_BASE + 0x150, 0x0000003E}, + {SET_CHANNEL_RF_TABLE_BASE + 0x154, 0x0000AA00}, + {SET_CHANNEL_RF_TABLE_BASE + 0x158, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE + 0x15C, 0x00000000}, + + //channel 7 + {SET_CHANNEL_RF_TABLE_BASE + 0x180, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE + 0x184, 0x00000001}, + {SET_CHANNEL_RF_TABLE_BASE + 0x188, 0x00000038}, + {SET_CHANNEL_RF_TABLE_BASE + 0x18C, 0x00000908}, + {SET_CHANNEL_RF_TABLE_BASE + 0x190, 0x0000003E}, + {SET_CHANNEL_RF_TABLE_BASE + 0x194, 0x0000AA00}, + {SET_CHANNEL_RF_TABLE_BASE + 0x198, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE + 0x19C, 0x00000000}, + + //channel 8 + {SET_CHANNEL_RF_TABLE_BASE + 0x1C0, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE + 0x1C4, 0x00000001}, + {SET_CHANNEL_RF_TABLE_BASE + 0x1C8, 0x00000038}, + {SET_CHANNEL_RF_TABLE_BASE + 0x1CC, 0x00000908}, + {SET_CHANNEL_RF_TABLE_BASE + 0x1D0, 0x0000003E}, + {SET_CHANNEL_RF_TABLE_BASE + 0x1D4, 0x0000AA00}, + {SET_CHANNEL_RF_TABLE_BASE + 0x1D8, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE + 0x1DC, 0x00000000}, + + //channel 9 + {SET_CHANNEL_RF_TABLE_BASE + 0x200, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE + 0x204, 0x00000001}, + {SET_CHANNEL_RF_TABLE_BASE + 0x208, 0x00000038}, + {SET_CHANNEL_RF_TABLE_BASE + 0x20C, 0x00000808}, + {SET_CHANNEL_RF_TABLE_BASE + 0x210, 0x0000003E}, + {SET_CHANNEL_RF_TABLE_BASE + 0x214, 0x0000AA00}, + {SET_CHANNEL_RF_TABLE_BASE + 0x218, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE + 0x21C, 0x00000000}, + + //channel 10 + {SET_CHANNEL_RF_TABLE_BASE + 0x240, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE + 0x244, 0x00000001}, + {SET_CHANNEL_RF_TABLE_BASE + 0x248, 0x00000038}, + {SET_CHANNEL_RF_TABLE_BASE + 0x24C, 0x00000808}, + {SET_CHANNEL_RF_TABLE_BASE + 0x250, 0x0000003E}, + {SET_CHANNEL_RF_TABLE_BASE + 0x254, 0x0000AA00}, + {SET_CHANNEL_RF_TABLE_BASE + 0x258, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE + 0x25C, 0x00000000}, + + //channel 11 + {SET_CHANNEL_RF_TABLE_BASE + 0x280, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE + 0x284, 0x00000001}, + {SET_CHANNEL_RF_TABLE_BASE + 0x288, 0x00000038}, + {SET_CHANNEL_RF_TABLE_BASE + 0x28C, 0x00000808}, + {SET_CHANNEL_RF_TABLE_BASE + 0x290, 0x0000003E}, + {SET_CHANNEL_RF_TABLE_BASE + 0x294, 0x0000AA00}, + {SET_CHANNEL_RF_TABLE_BASE + 0x298, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE + 0x29C, 0x00000000}, + + //channel 12 + {SET_CHANNEL_RF_TABLE_BASE + 0x2C0, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE + 0x2C4, 0x00000001}, + {SET_CHANNEL_RF_TABLE_BASE + 0x2C8, 0x00000038}, + {SET_CHANNEL_RF_TABLE_BASE + 0x2CC, 0x00000808}, + {SET_CHANNEL_RF_TABLE_BASE + 0x2D0, 0x0000003E}, + {SET_CHANNEL_RF_TABLE_BASE + 0x2D4, 0x0000AA00}, + {SET_CHANNEL_RF_TABLE_BASE + 0x2D8, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE + 0x2DC, 0x00000000}, + + //channel 13 + {SET_CHANNEL_RF_TABLE_BASE + 0x300, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE + 0x304, 0x00000001}, + {SET_CHANNEL_RF_TABLE_BASE + 0x308, 0x00000038}, + {SET_CHANNEL_RF_TABLE_BASE + 0x30C, 0x00000B08}, + {SET_CHANNEL_RF_TABLE_BASE + 0x310, 0x0000003E}, + {SET_CHANNEL_RF_TABLE_BASE + 0x314, 0x0000AA12}, + {SET_CHANNEL_RF_TABLE_BASE + 0x318, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE + 0x31C, 0x00000000}, +}; + +static const u8 wifi_core_patch_data_91_8[][2] = { + {0x28, 0x1a}, + {0x29, 0x0d}, + {0x25, 0x07}, + {0x08, 0x43}, + {0x26, 0x35}, + {0x3e, 0x64}, + {0x3f, 0x00}, + {0x45, 0x75}, + {0x46, 0x73}, + {0x50, 0x58}, + + {0x30, 0xf6}, + + {0x74, 0x01}, + {0x75, 0x40}, + + {0x74, 0xD4}, + {0x75, 0x47}, + + {0x74, 0xff}, + {0x75, 0x4b}, + + {0x74, 0x3D}, + {0x75, 0x4c}, + + {0x74, 0x01}, + {0x75, 0x50}, + + {0x74, 0x99}, + {0x75, 0x57}, + + {0x74, 0xff}, + {0x75, 0x5b}, + + {0x74, 0x33}, + {0x75, 0x5D}, + + {0x74, 0xE4}, + {0x75, 0x61}, + + {0x30, 0xF7}, + +}; + +static const u32 wifi_core_init_data_32_91[][2] = { + {0x500002a8, 0x00000001}, + {0x50000080, 0x0003FEF7}, + {0x5000050c, 0x00003900}, + {0x30010010, 0x00007DFF}, + + {0x50090060, 0x000001B4}, + {0x50090068, 0xEB3FF7FF}, + {0x50090070, 0x1403DBFF}, + {0x500900B0, 0x00400000}, + + {0x500900AC, 0x00000A00}, + {0x50090054, 0x00000001}, + {0x50090200, 0x00000180}, + {0x50090204, 0x00000180}, + {0x50090208, 0x00000180}, + {0x5009020c, 0x00000180}, + {0x50090210, 0x00000180}, + {0x50090214, 0x00000180}, + {0x50090218, 0x00000188}, + {0x5009021c, 0x00000190}, + {0x50090220, 0x00000200}, + {0x50090224, 0x00000208}, + {0x50090228, 0x00000210}, + {0x5009022c, 0x00000280}, + {0x50090230, 0x00000288}, + {0x50090234, 0x00000290}, + {0x50090238, 0x00000300}, + {0x5009023c, 0x00000308}, + {0x50090240, 0x00000310}, + {0x50090244, 0x00000380}, + {0x50090248, 0x00000388}, + {0x5009024c, 0x00000390}, + {0x50090250, 0x00000400}, + {0x50090254, 0x00000408}, + {0x50090258, 0x00000410}, + {0x5009025c, 0x00000480}, + {0x50090260, 0x00000488}, + {0x50090264, 0x00000490}, + {0x50090268, 0x00000500}, + {0x5009026c, 0x00000508}, + {0x50090270, 0x00000510}, + {0x50090274, 0x00000580}, + {0x50090278, 0x00000588}, + {0x5009027c, 0x00000590}, + {0x50090280, 0x00000290}, + {0x50090284, 0x00000300}, + {0x50090288, 0x00000308}, + {0x5009028c, 0x00000310}, + {0x50090290, 0x00000380}, + {0x50090294, 0x00000388}, + {0x50090298, 0x00000390}, + {0x5009029c, 0x00000400}, + {0x500902a0, 0x00000408}, + {0x500902a4, 0x00000410}, + {0x500902a8, 0x00000480}, + {0x500902ac, 0x00000488}, + {0x500902b0, 0x00000490}, + {0x500902b4, 0x00000500}, + {0x500902b8, 0x00000508}, + {0x500902bc, 0x00000510}, + {0x500902c0, 0x00000580}, + {0x500902c4, 0x00000588}, + {0x500902c8, 0x00000590}, + {0x500902cc, 0x00000600}, + {0x500902d0, 0x00000608}, + {0x500902d4, 0x00000610}, + {0x500902d8, 0x00000680}, + {0x500902dc, 0x00000688}, + {0x500902e0, 0x00000690}, + {0x500902e4, 0x00000700}, + {0x500902e8, 0x00000708}, + {0x500902ec, 0x00000710}, + {0x500902f0, 0x00000780}, + {0x500902f4, 0x00000788}, + {0x500902f8, 0x00000790}, + {0x500902fc, 0x00000798}, + {0x50090300, 0x00000500}, + {0x50090304, 0x00000508}, + {0x50090308, 0x00000510}, + {0x5009030c, 0x00000580}, + {0x50090310, 0x00000588}, + {0x50090314, 0x00000590}, + {0x50090318, 0x00000600}, + {0x5009031c, 0x00000608}, + {0x50090320, 0x00000610}, + {0x50090324, 0x00000680}, + {0x50090328, 0x00000688}, + {0x5009032c, 0x00000690}, + {0x50090330, 0x00000700}, + {0x50090334, 0x00000708}, + {0x50090338, 0x00000710}, + {0x5009033c, 0x00000780}, + {0x50090340, 0x00000780}, + {0x50090344, 0x00000780}, + {0x50090348, 0x00000780}, + {0x5009034c, 0x00000780}, + {0x50090350, 0x00000780}, + {0x50090354, 0x00000780}, + {0x50090358, 0x00000780}, + {0x5009035c, 0x00000780}, + {0x50090360, 0x00000780}, + {0x50090364, 0x00000780}, + {0x50090368, 0x00000780}, + {0x5009036c, 0x00000780}, + {0x50090370, 0x00000780}, + {0x50090374, 0x00000780}, + {0x50090378, 0x00000780}, + {0x5009037c, 0x00000780}, + {0x50090054, 0x00000000}, +}; + +static const u32 wifi_core_AM_PM_data_32_91[][2] = { + {0x50090054, 0x00000000}, + {0x50090068, 0xEB3FF7FF}, + {0x50090070, 0x1403DBFF}, + {0x500900B0, 0x00400000}, + {0x50090090, 0x00000000}, //item0:theta0=7_B=0_r0=2 + {0x50090094, 0x00A01401}, + {0x50090098, 0x02907412}, + {0x5009009C, 0x05D12438}, + {0x500900A0, 0x0A522872}, + {0x500900A4, 0xFFF380C1}, + {0x50090078, 0x02B05400}, //item0:G0=-3.5_r0=2.5 + {0x5009007C, 0x06D15840}, + {0x50090080, 0x0B927885}, + {0x50090084, 0x11A3DCD7}, + {0x50090088, 0x1975A540}, + {0x5009008C, 0xFFF7FDC9}, + {0x500900A8, 0x9C4001A7}, +}; +static const u32 wifi_assoc_power_save_data_32_91[][2] = { + {0x5000050c, 0x00003900}// for association power save +}; + + +#endif diff --git a/drivers/net/wireless/rda/rda_wlan/wlan_sdio_patch_91e.h b/drivers/net/wireless/rda/rda_wlan/wlan_sdio_patch_91e.h new file mode 100755 index 00000000..d55f1f55 --- /dev/null +++ b/drivers/net/wireless/rda/rda_wlan/wlan_sdio_patch_91e.h @@ -0,0 +1,675 @@ +#ifndef __WLAN_SDIO_PATCH_91_E_H__ +#define __WLAN_SDIO_PATCH_91_E_H__ + +static const u32 wifi_core_patch_data_32_91e[][2] = { + // add for pta + {0x50000828,0x00100FFD}, + {0x50000810,0xFFFF0F0F}, + {0x50000814,0xFFFF0F0F}, + {0x50000818,0x00FF000F}, + {0x5000081C,0xFF000F00}, + {0x50000820,0xFF000F00}, + {0x50000824,0x0000F0F0}, + {0x50090044,0xE6AD6CB0},//mode + {0x50090040,0xBA9D5EC4},//agc value + {0x001075EC,0x00000002},//disable ht + // add for pta +#if 1 + {0x0010FFFC, 0x20140527}, + {0x00110000, 0xEA03FA67}, + {0x00110004, 0xE51FF004}, + {0x00110008, 0x000116B4}, + {0x0011000C, 0xEA03C0BF}, + {0x00110010, 0xE200007F}, + {0x00110014, 0xE3500028}, + {0x00110018, 0x1A00000B}, + {0x0011001C, 0xE1A01801}, + {0x00110020, 0xE1A01821}, + {0x00110024, 0xE59F0024}, + {0x00110028, 0xE1510000}, + {0x0011002C, 0x059F1024}, + {0x00110030, 0x03A00028}, + {0x00110034, 0x059FF028}, + {0x00110038, 0xE59F0014}, + {0x0011003C, 0xE1510000}, + {0x00110040, 0x059F1014}, + {0x00110044, 0x03A00028}, + {0x00110048, 0x059FF014}, + {0x0011004C, 0xE59FF00C}, + {0x00110050, 0x00001F20}, + {0x00110054, 0x00001320}, + {0x00110058, 0x00004F20}, + {0x0011005C, 0x00004320}, + {0x00110060, 0x0001FD10}, + {0x00110064, 0x0001FD18}, + {0x00110068, 0xEA0410ED}, + {0x0011006C, 0xE5940004}, + {0x00110070, 0xE3800850}, + {0x00110074, 0xE5840004}, + {0x00110078, 0xE3A00D44}, + {0x0011007C, 0xE5840634}, + {0x00110080, 0xE59F0004}, + {0x00110084, 0xE5840584}, + {0x00110088, 0xE59FF000}, + {0x0011008C, 0x00007BF8}, + {0x00110090, 0x0000BCB4}, + {0x00110094, 0xEA040607}, + {0x00110098, 0xE59F2020}, + {0x0011009C, 0xE1D210B0}, + {0x001100A0, 0xE1A00000}, + {0x001100A4, 0xE1A00000}, + {0x001100A8, 0xE59F200C}, + {0x001100AC, 0xE3A01010}, + {0x001100B0, 0xE5C21000}, + {0x001100B4, 0xE3560000}, + {0x001100B8, 0xE59FF004}, + {0x001100BC, 0x50300038}, + {0x001100C0, 0x00106B1C}, + {0x001100C4, 0x0000E878}, + {0x001100C8, 0xEA03FE7A}, + {0x001100CC, 0xE5CD0018}, + {0x001100D0, 0xE51F0018}, + {0x001100D4, 0xE1D010B0}, + {0x001100D8, 0xE1A00000}, + {0x001100DC, 0xE1A00000}, + {0x001100E0, 0xE51F002C}, + {0x001100E4, 0xE3A01010}, + {0x001100E8, 0xE5C01000}, + {0x001100EC, 0xE59FF000}, + {0x001100F0, 0x50060000}, + {0x001100F4, 0x000106E0}, + {0x001100F8, 0xEA042EFA}, + {0x001100FC, 0xE59F0028}, + {0x00110100, 0xE5840584}, + {0x00110104, 0xE59F0024}, + {0x00110108, 0xE59F1024}, + {0x0011010C, 0xE5810000}, + {0x00110110, 0xE59F1020}, + {0x00110114, 0xE3A00003}, + {0x00110118, 0xE5810000}, + {0x0011011C, 0xE59F001C}, + {0x00110120, 0xE59F1014}, + {0x00110124, 0xE5810000}, + {0x00110128, 0xE59FF014}, + {0x0011012C, 0x0000FFFB}, + {0x00110130, 0x00000030}, + {0x00110134, 0x5000020C}, + {0x00110138, 0x50000200}, + {0x0011013C, 0x30000014}, + {0x00110140, 0x25801B0A}, + {0x00110144, 0x00004510}, + {0x00110148, 0xEA041E5A}, + {0x0011014C, 0xE59F103C}, + {0x00110150, 0x03A00000}, + {0x00110154, 0x05810000}, + {0x00110158, 0x0A000007}, + {0x0011015C, 0xE5910000}, + {0x00110160, 0xE2800001}, + {0x00110164, 0xE3500002}, + {0x00110168, 0x35810000}, + {0x0011016C, 0x3A000004}, + {0x00110170, 0xE3A00000}, + {0x00110174, 0xE5810000}, + {0x00110178, 0xEAFFFFFF}, + {0x0011017C, 0xE51FF004}, + {0x00110180, 0x000087E0}, + {0x00110184, 0xE51FF004}, + {0x00110188, 0x00008824}, + {0x0011018C, 0x00000000}, + {0x00110190, 0x0011018C}, + {0x00110194, 0xEA0437F6}, + {0x00110198, 0xE1A000A0}, + {0x0011019C, 0xE51FF004}, + {0x001101A0, 0x000021BC}, + {0x001101A4, 0xEA0437E3}, + {0x001101A8, 0xE3A00002}, + {0x001101AC, 0xE51FF004}, + {0x001101B0, 0x00002218}, + {0x001101B4, 0xEA0418DC}, + {0x001101B8, 0xE3A03000}, + {0x001101BC, 0xE5D11000}, + {0x001101C0, 0xE5802010}, + {0x001101C4, 0xE5803044}, + {0x001101C8, 0xE3510001}, + {0x001101CC, 0x13A01003}, + {0x001101D0, 0x03A01009}, + {0x001101D4, 0xE5A01014}, + {0x001101D8, 0xE5803034}, + {0x001101DC, 0xE51FF004}, + {0x001101E0, 0x00009E64}, + {0x001101E4, 0xEA03F8FC}, + {0x001101E8, 0xE51FF004}, + {0x001101EC, 0x00011DF4}, + {0x001101F0, 0xEA041F1D}, + {0x001101F4, 0xE3A015C0}, + {0x001101F8, 0xE3E00007}, + {0x001101FC, 0xE5810000}, + {0x00110200, 0xE3A01001}, + {0x00110204, 0xE3A0003F}, + {0x00110208, 0xEB000007}, + {0x0011020C, 0xE59F105C}, + {0x00110210, 0xE3A00026}, + {0x00110214, 0xEB000004}, + {0x00110218, 0xE3A01000}, + {0x0011021C, 0xE3A0003F}, + {0x00110220, 0xEB000001}, + {0x00110224, 0xE59F4008}, + {0x00110228, 0xE59FF008}, + {0x0011022C, 0xE51FF004}, + {0x00110230, 0x0001FD08}, + {0x00110234, 0x001077D4}, + {0x00110238, 0x0000857C}, + {0x0011023C, 0xEA042E03}, + {0x00110240, 0xE3A01001}, + {0x00110244, 0xE3A0003F}, + {0x00110248, 0xEBFFFFF7}, + {0x0011024C, 0xE59F1018}, + {0x00110250, 0xE3A00026}, + {0x00110254, 0xEBFFFFF4}, + {0x00110258, 0xE3A01000}, + {0x0011025C, 0xE3A0003F}, + {0x00110260, 0xEBFFFFF1}, + {0x00110264, 0xE59F0008}, + {0x00110268, 0xE59FF008}, + {0x0011026C, 0x0000808B}, + {0x00110270, 0x000080BB}, + {0x00110274, 0xFFFFFC09}, + {0x00110278, 0x00004A30}, + {0x0011027C, 0xEA042F4C}, + {0x00110280, 0xE3A01001}, + {0x00110284, 0xE3A0003F}, + {0x00110288, 0xEBFFFFE7}, + {0x0011028C, 0xE51F1028}, + {0x00110290, 0xE3A00026}, + {0x00110294, 0xEBFFFFE4}, + {0x00110298, 0xE3A01000}, + {0x0011029C, 0xE3A0003F}, + {0x001102A0, 0xEBFFFFE1}, + {0x001102A4, 0xE51F0038}, + {0x001102A8, 0xE51FF004}, + {0x001102AC, 0x0000454C}, + {0x001102B0, 0xEA03EFF1}, + {0x001102B4, 0xE3A01001}, + {0x001102B8, 0xE3A0003F}, + {0x001102BC, 0xEBFFFFDA}, + {0x001102C0, 0xE51F1058}, + {0x001102C4, 0xE3A00026}, + {0x001102C8, 0xEBFFFFD7}, + {0x001102CC, 0xE3A01000}, + {0x001102D0, 0xE3A0003F}, + {0x001102D4, 0xEBFFFFD4}, + {0x001102D8, 0xE3A015C0}, + {0x001102DC, 0xE3E00007}, + {0x001102E0, 0xE5810000}, + {0x001102E4, 0xE3A01003}, + {0x001102E8, 0xE51FF004}, + {0x001102EC, 0x000142EC}, + {0x001102F0, 0xEA041316}, + {0x001102F4, 0xE3A01002}, + {0x001102F8, 0xE5C41000}, + {0x001102FC, 0xE3A01001}, + {0x00110300, 0xE51FF004}, + {0x00110304, 0x0000B69C}, + {0x00110308, 0xEA03F8E0}, + {0x0011030C, 0xE5951828}, + {0x00110310, 0xE1A01821}, + {0x00110314, 0xE3C11CF0}, + {0x00110318, 0xE51FF004}, + {0x0011031C, 0x00011F88}, + {0x00110320, 0xEA03E1E3}, + {0x00110324, 0xE2800002}, + {0x00110328, 0xE5D01000}, + {0x0011032C, 0xE51FF004}, + {0x00110330, 0x00017B94}, + {0x20040004, 0x00011660}, + {0x20040024, 0x00110000}, + {0x20040008, 0x0001FD0C}, + {0x20040028, 0x0011000C}, + {0x2004000C, 0x0000BCB0}, + {0x2004002C, 0x00110068}, + {0x20040010, 0x0000E874}, + {0x20040030, 0x00110094}, + {0x20040014, 0x000106DC}, + {0x20040034, 0x001100C8}, + {0x20040018, 0x0000450C}, + {0x20040038, 0x001100F8}, + {0x2004001C, 0x000087DC}, + {0x2004003C, 0x00110148}, + {0x20040020, 0x000021B8}, + {0x20040040, 0x00110194}, + {0x20040100, 0x00002214}, + {0x20040120, 0x001101A4}, + {0x20040104, 0x00009E40}, + {0x20040124, 0x001101B4}, + {0x20040108, 0x00011DF0}, + {0x20040128, 0x001101E4}, + {0x2004010C, 0x00008578}, + {0x2004012C, 0x001101F0}, + {0x20040110, 0x00004A2C}, + {0x20040130, 0x0011023C}, + {0x20040114, 0x00004548}, + {0x20040134, 0x0011027C}, + {0x20040118, 0x000142E8}, + {0x20040138, 0x001102B0}, + {0x2004011C, 0x0000B694}, + {0x2004013C, 0x001102F0}, + {0x20040140, 0x00011F84}, + {0x20040180, 0x00110308}, + {0x20040144, 0x00017B90}, + {0x20040184, 0x00110320}, + {0x20040000, 0x0003FFFF}, + +#endif +}; + +#define SET_CHANNEL_MEM_TABLE_BASE_91E 0x001086AC +#define SET_CHANNEL_RF_TABLE_BASE_91E 0x0010894C +static const u32 wifi_clock_switch_91e[][2] = { + //channel 1 + {SET_CHANNEL_MEM_TABLE_BASE_91E, 0x50090048}, + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0x04, 0x604199C4}, + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0x08, 0x50000654}, + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0x0C, 0x2222CFCF}, + + //channel 2 + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0x30, 0x50090048}, + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0x34, 0x604199C4}, + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0x38, 0x50000654}, + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0x3C, 0x2222CFCF}, + + //channel 3 + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0x60, 0x50090048}, + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0x64, 0x604199C4}, + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0x68, 0x50000654}, + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0x6C, 0x2222CFCF}, + + //channel 4 + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0x90, 0x50090048}, + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0x94, 0x604199C4}, + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0x98, 0x50000654}, + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0x9C, 0x2222CFCF}, + + //channel 5 + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0xC0, 0x50090048}, + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0xC4, 0x204199C4}, + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0xC8, 0x50000654}, + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0xCC, 0x2222CFCF}, + + //channel 6 + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0xF0, 0x50090048}, + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0xF4, 0x204199C4}, + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0xF8, 0x50000654}, + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0xFC, 0x2222CFCF}, + + //channel 7 + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0x120, 0x50090048}, + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0x124, 0x204199C4}, + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0x128, 0x50000654}, + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0x12C, 0x2222CFCF}, + + //channel 8 + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0x150, 0x50090048}, + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0x154, 0x204199C4}, + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0x158, 0x50000654}, + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0x15C, 0x2222CFCF}, + + //channel 9 + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0x180, 0x50090048}, + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0x184, 0x604199C4}, + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0x188, 0x50000654}, + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0x18C, 0x2222CFCF}, + + //channel 10 + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0x1B0, 0x50090048}, + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0x1B4, 0x604199C4}, + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0x1B8, 0x50000654}, + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0x1BC, 0x2222CFCF}, + + //channel 11 + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0x1E0, 0x50090048}, + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0x1E4, 0x604199C4}, + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0x1E8, 0x50000654}, + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0x1EC, 0x2222CFCF}, + + //channel 12 + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0x210, 0x50090048}, + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0x214, 0x604199C4}, + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0x218, 0x50000654}, + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0x21C, 0x2222CFCF}, + + //channel 13 + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0x240, 0x50090048}, + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0x244, 0x304199C4}, + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0x248, 0x50000654}, + {SET_CHANNEL_MEM_TABLE_BASE_91E + 0x24C, 0x2222CFCF}, + + //channel 1 + {SET_CHANNEL_RF_TABLE_BASE_91E, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x04, 0x00000001}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x08, 0x00000038}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x0C, 0x00000808}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x10, 0x0000003E}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x14, 0x0000AA00}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x18, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x1C, 0x00000000}, + + //channel 2 + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x40, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x44, 0x00000001}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x48, 0x00000038}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x4C, 0x00000808}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x50, 0x0000003E}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x54, 0x0000AA00}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x58, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x5C, 0x00000000}, + + //channel 3 + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x80, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x84, 0x00000001}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x88, 0x00000038}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x8C, 0x00000808}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x90, 0x0000003E}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x94, 0x0000AA00}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x98, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x9C, 0x00000000}, + + //channel 4 + {SET_CHANNEL_RF_TABLE_BASE_91E + 0xC0, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0xC4, 0x00000001}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0xC8, 0x00000038}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0xCC, 0x00000808}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0xD0, 0x0000003E}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0xD4, 0x0000AA00}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0xD8, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0xDC, 0x00000000}, + + //channel 5 + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x100, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x104, 0x00000001}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x108, 0x00000038}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x10C, 0x00000908}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x110, 0x0000003E}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x114, 0x0000AA00}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x118, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x11C, 0x00000000}, + + //channel 6 + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x140, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x144, 0x00000001}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x148, 0x00000038}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x14C, 0x00000908}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x150, 0x0000003E}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x154, 0x0000AA00}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x158, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x15C, 0x00000000}, + + //channel 7 + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x180, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x184, 0x00000001}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x188, 0x00000038}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x18C, 0x00000908}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x190, 0x0000003E}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x194, 0x0000AA00}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x198, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x19C, 0x00000000}, + + //channel 8 + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x1C0, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x1C4, 0x00000001}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x1C8, 0x00000038}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x1CC, 0x00000908}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x1D0, 0x0000003E}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x1D4, 0x0000AA00}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x1D8, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x1DC, 0x00000000}, + + //channel 9 + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x200, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x204, 0x00000001}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x208, 0x00000038}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x20C, 0x00000808}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x210, 0x0000003E}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x214, 0x0000AA00}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x218, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x21C, 0x00000000}, + + //channel 10 + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x240, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x244, 0x00000001}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x248, 0x00000038}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x24C, 0x00000808}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x250, 0x0000003E}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x254, 0x0000AA00}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x258, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x25C, 0x00000000}, + + //channel 11 + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x280, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x284, 0x00000001}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x288, 0x00000038}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x28C, 0x00000808}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x290, 0x0000003E}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x294, 0x0000AA00}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x298, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x29C, 0x00000000}, + + //channel 12 + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x2C0, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x2C4, 0x00000001}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x2C8, 0x00000038}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x2CC, 0x00000808}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x2D0, 0x0000003E}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x2D4, 0x0000AA00}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x2D8, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x2DC, 0x00000000}, + + //channel 13 + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x300, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x304, 0x00000001}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x308, 0x00000038}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x30C, 0x00000B08}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x310, 0x0000003E}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x314, 0x0000AA12}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x318, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91E + 0x31C, 0x00000000}, +}; + +static const u8 wifi_core_patch_data_91e_8[][2] = { + {0x28, 0x1a}, + {0x29, 0x0d}, + {0x25, 0x00}, + {0x08, 0x43}, + //rx patch + {0x26, 0x35}, + {0x3e, 0x64}, + {0x3f, 0x00}, + {0x45, 0x75}, + {0x46, 0x73}, + {0x50, 0x58}, + {0x30, 0xf6}, + + {0xA0, 0x7f}, + {0x74, 0x01}, + {0x75, 0x40}, + + {0x12, 0x04}, + {0x1C, 0x2D}, + {0x0D, 0x59}, + {0x17, 0x75}, + {0x74, 0xD4}, + {0x75, 0x47}, + + {0x74, 0xFF}, + {0x75, 0x4B}, + + {0x74, 0x3D}, + {0x75, 0x4C}, + + {0x74, 0x01}, + {0x75, 0x50}, + + {0x74, 0x99}, + {0x75, 0x57}, + + {0x74, 0xFF}, + {0x75, 0x5B}, + + {0x74, 0x33}, + {0x75, 0x5D}, + + {0x74, 0xE4}, + {0x75, 0x61}, + + {0x30, 0xF7}, +}; + +static const u32 wifi_core_init_data_32_91e[][2] = { + {0x500002a8, 0x00000001}, + {0x50000080, 0x0003FEF7}, + {0x00100018, 0x000A3243}, // flow ctrl , WPS supported, proakis + {0x0010001C, 0xFFFF0001}, + {0x30010010, 0x00007DFF}, + + {0x50090060, 0x000001B4}, + //item:rda5991_verE_wf_tx_pn9 + {0x50090068, 0xEB3FF7FF}, + {0x50090070, 0x1403DBFF}, + {0x500900B0, 0x00400000}, + {0x500900A8, 0x9c400180}, + {0x5009008C, 0xFc07fdc9}, + //PHY:phy rx timeout enable + {0x0010216c, 0x50000634}, + {0x00102170, 0x00001100}, + {0x00102174, 0x50000584}, + {0x00102178, 0x00007bf8}, + //new agc table 20140419 + {0x50090054, 0x00000001}, + {0x50090200, 0x00000100}, + {0x50090204, 0x00000100}, + {0x50090208, 0x00000100}, + {0x5009020c, 0x00000100}, + {0x50090210, 0x00000108}, + {0x50090214, 0x00000110}, + {0x50090218, 0x00000180}, + {0x5009021c, 0x00000188}, + {0x50090220, 0x00000190}, + {0x50090224, 0x00000200}, + {0x50090228, 0x00000208}, + {0x5009022c, 0x00000210}, + {0x50090230, 0x00000280}, + {0x50090234, 0x00000288}, + {0x50090238, 0x00000304}, + {0x5009023c, 0x0000030C}, + {0x50090240, 0x00000314}, + {0x50090244, 0x00000384}, + {0x50090248, 0x0000038C}, + {0x5009024c, 0x00000394}, + {0x50090250, 0x00000404}, + {0x50090254, 0x0000040C}, + {0x50090258, 0x00000414}, + {0x5009025c, 0x00000484}, + {0x50090260, 0x0000048C}, + {0x50090264, 0x00000500}, + {0x50090268, 0x00000508}, + {0x5009026c, 0x00000510}, + {0x50090270, 0x00000580}, + {0x50090274, 0x00000588}, + {0x50090278, 0x00000590}, + {0x5009027c, 0x00000600}, + {0x50090280, 0x00000288}, + {0x50090284, 0x00000290}, + {0x50090288, 0x00000304}, + {0x5009028c, 0x0000030C}, + {0x50090290, 0x00000314}, + {0x50090294, 0x00000384}, + {0x50090298, 0x0000038C}, + {0x5009029c, 0x00000394}, + {0x500902a0, 0x00000404}, + {0x500902a4, 0x0000040C}, + {0x500902a8, 0x00000414}, + {0x500902ac, 0x00000484}, + {0x500902b0, 0x0000048C}, + {0x500902b4, 0x00000500}, + {0x500902b8, 0x00000508}, + {0x500902bc, 0x00000510}, + {0x500902c0, 0x00000580}, + {0x500902c4, 0x00000588}, + {0x500902c8, 0x00000590}, + {0x500902cc, 0x00000600}, + {0x500902d0, 0x00000608}, + {0x500902d4, 0x00000610}, + {0x500902d8, 0x00000680}, + {0x500902dc, 0x00000688}, + {0x500902e0, 0x00000690}, + {0x500902e4, 0x00000700}, + {0x500902e8, 0x00000708}, + {0x500902ec, 0x00000710}, + {0x500902f0, 0x00000780}, + {0x500902f4, 0x00000780}, + {0x500902f8, 0x00000780}, + {0x500902fc, 0x00000780}, + {0x50090300, 0x00000500}, + {0x50090304, 0x00000508}, + {0x50090308, 0x00000510}, + {0x5009030c, 0x00000580}, + {0x50090310, 0x00000588}, + {0x50090314, 0x00000590}, + {0x50090318, 0x00000600}, + {0x5009031c, 0x00000608}, + {0x50090320, 0x00000610}, + {0x50090324, 0x00000680}, + {0x50090328, 0x00000688}, + {0x5009032c, 0x00000690}, + {0x50090330, 0x00000700}, + {0x50090334, 0x00000708}, + {0x50090338, 0x00000710}, + {0x5009033c, 0x00000780}, + {0x50090340, 0x00000780}, + {0x50090344, 0x00000780}, + {0x50090348, 0x00000780}, + {0x5009034c, 0x00000780}, + {0x50090350, 0x00000780}, + {0x50090354, 0x00000780}, + {0x50090358, 0x00000780}, + {0x5009035c, 0x00000780}, + {0x50090360, 0x00000780}, + {0x50090364, 0x00000780}, + {0x50090368, 0x00000780}, + {0x5009036c, 0x00000780}, + {0x50090370, 0x00000780}, + {0x50090374, 0x00000780}, + {0x50090378, 0x00000780}, + {0x5009037c, 0x00000780}, + {0x50090054, 0x00000000}, +}; + +static const u32 wifi_core_AM_PM_data_32_91e[][2] = { + {0x50090054, 0x00000000}, + {0x50090068, 0xEB3FF7FF}, + {0x50090070, 0x1403DBFF}, + {0x500900B0, 0x00400000}, + //item0:theta0=7_B=0_r0=2_for_verE + {0x50090090, 0x00000000}, + {0x50090094, 0x00A01401}, + {0x50090098, 0x02907412}, + {0x5009009C, 0x05D12438}, + {0x500900A0, 0x0A522872}, + {0x500900A4, 0xFFF380C1}, + //item0:G0=-3.5_r0=2.5_for_verE + {0x50090078, 0x02B05400}, + {0x5009007C, 0x06D15840}, + {0x50090080, 0x0B927885}, + {0x50090084, 0x11A3DCD7}, + {0x50090088, 0x1975A540}, + {0x5009008C, 0xFc07fdc9}, + {0x500900A8, 0x9c400180}, + +}; +const u32 wifi_phy_timeout_cfg_91e[][2] = +{ + {0x50000634, 0x00001100}, + {0x50000584, 0x00007BF8}, +}; + +#endif + diff --git a/drivers/net/wireless/rda/rda_wlan/wlan_sdio_patch_91f.h b/drivers/net/wireless/rda/rda_wlan/wlan_sdio_patch_91f.h new file mode 100755 index 00000000..1c88d3e5 --- /dev/null +++ b/drivers/net/wireless/rda/rda_wlan/wlan_sdio_patch_91f.h @@ -0,0 +1,583 @@ +#ifndef __WLAN_SDIO_PATCH_91_F_H__ +#define __WLAN_SDIO_PATCH_91_F_H__ + +static const u32 wifi_core_patch_data_32_91f[][2] = { + // add for pta + {0x50000828,0x00100FFD}, + {0x50000810,0xFFFF0F0F}, + {0x50000814,0xFFFF0F0F}, + {0x50000818,0x00FF000F}, + {0x5000081C,0xFF000F00}, + {0x50000820,0xFF000F00}, + {0x50000824,0x0000F0F0}, + {0x50090044,0xE6AD6CB0},//mode + {0x50090040,0xBA9D5EC4},//agc value +#if 0 + // add for pta + {0x0010FFFC, 0x20140304}, + {0x00110000, 0xEA03FA67}, + {0x00110004, 0xE51FF004}, + {0x00110008, 0x000116B4}, + {0x0011000C, 0xEA03C0BF}, + {0x00110010, 0xE200007F}, + {0x00110014, 0xE3500028}, + {0x00110018, 0x1A00000B}, + {0x0011001C, 0xE1A01801}, + {0x00110020, 0xE1A01821}, + {0x00110024, 0xE59F0024}, + {0x00110028, 0xE1510000}, + {0x0011002C, 0x059F1024}, + {0x00110030, 0x03A00028}, + {0x00110034, 0x059FF028}, + {0x00110038, 0xE59F0014}, + {0x0011003C, 0xE1510000}, + {0x00110040, 0x059F1014}, + {0x00110044, 0x03A00028}, + {0x00110048, 0x059FF014}, + {0x0011004C, 0xE59FF00C}, + {0x00110050, 0x00001F20}, + {0x00110054, 0x00001320}, + {0x00110058, 0x00004F20}, + {0x0011005C, 0x00004320}, + {0x00110060, 0x0001FD10}, + {0x00110064, 0x0001FD18}, + {0x00110068, 0xEA0410ED}, + {0x0011006C, 0xE5940004}, + {0x00110070, 0xE3800850}, + {0x00110074, 0xE5840004}, + {0x00110078, 0xE3A00D44}, + {0x0011007C, 0xE5840634}, + {0x00110080, 0xE59F0004}, + {0x00110084, 0xE5840584}, + {0x00110088, 0xE59FF000}, + {0x0011008C, 0x00007BF8}, + {0x00110090, 0x0000BCB4}, + {0x00110094, 0xEA040607}, + {0x00110098, 0xE59F2020}, + {0x0011009C, 0xE1D210B0}, + {0x001100A0, 0xE1A00000}, + {0x001100A4, 0xE1A00000}, + {0x001100A8, 0xE59F200C}, + {0x001100AC, 0xE3A01010}, + {0x001100B0, 0xE5C21000}, + {0x001100B4, 0xE3560000}, + {0x001100B8, 0xE59FF004}, + {0x001100BC, 0x50300038}, + {0x001100C0, 0x00106B1C}, + {0x001100C4, 0x0000E878}, + {0x001100C8, 0xEA03FE7A}, + {0x001100CC, 0xE5CD0018}, + {0x001100D0, 0xE51F0018}, + {0x001100D4, 0xE1D010B0}, + {0x001100D8, 0xE1A00000}, + {0x001100DC, 0xE1A00000}, + {0x001100E0, 0xE51F002C}, + {0x001100E4, 0xE3A01010}, + {0x001100E8, 0xE5C01000}, + {0x001100EC, 0xE59FF000}, + {0x001100F0, 0x50060000}, + {0x001100F4, 0x000106E0}, + {0x001100F8, 0xEA042EFA}, + {0x001100FC, 0xE59F0028}, + {0x00110100, 0xE5840584}, + {0x00110104, 0xE59F0024}, + {0x00110108, 0xE59F1024}, + {0x0011010C, 0xE5810000}, + {0x00110110, 0xE59F1020}, + {0x00110114, 0xE3A00003}, + {0x00110118, 0xE5810000}, + {0x0011011C, 0xE59F001C}, + {0x00110120, 0xE59F1014}, + {0x00110124, 0xE5810000}, + {0x00110128, 0xE59FF014}, + {0x0011012C, 0x0000FFFB}, + {0x00110130, 0x00000030}, + {0x00110134, 0x5000020C}, + {0x00110138, 0x50000200}, + {0x0011013C, 0x30000014}, + {0x00110140, 0x25801B0A}, + {0x00110144, 0x00004510}, + {0x00110148, 0xEA041E5A}, + {0x0011014C, 0xE59F103C}, + {0x00110150, 0x03A00000}, + {0x00110154, 0x05810000}, + {0x00110158, 0x0A000007}, + {0x0011015C, 0xE5910000}, + {0x00110160, 0xE2800001}, + {0x00110164, 0xE3500002}, + {0x00110168, 0x35810000}, + {0x0011016C, 0x3A000004}, + {0x00110170, 0xE3A00000}, + {0x00110174, 0xE5810000}, + {0x00110178, 0xEAFFFFFF}, + {0x0011017C, 0xE51FF004}, + {0x00110180, 0x000087E0}, + {0x00110184, 0xE51FF004}, + {0x00110188, 0x00008824}, + {0x0011018C, 0x00000000}, + {0x00110190, 0x0011018C}, + {0x00110194, 0xEA0437F6}, + {0x00110198, 0xE1A000A0}, + {0x0011019C, 0xE51FF004}, + {0x001101A0, 0x000021BC}, + {0x001101A4, 0xEA0437E3}, + {0x001101A8, 0xE3A00002}, + {0x001101AC, 0xE51FF004}, + {0x001101B0, 0x00002218}, + {0x001101B4, 0xEA0418DC}, + {0x001101B8, 0xE3A03000}, + {0x001101BC, 0xE5D11000}, + {0x001101C0, 0xE5802010}, + {0x001101C4, 0xE5803044}, + {0x001101C8, 0xE3510001}, + {0x001101CC, 0x13A01003}, + {0x001101D0, 0x03A01009}, + {0x001101D4, 0xE5A01014}, + {0x001101D8, 0xE5803034}, + {0x001101DC, 0xE51FF004}, + {0x001101E0, 0x00009E64}, + {0x001101E4, 0xEA042DED}, + {0x001101E8, 0xE59F1010}, + {0x001101EC, 0xE3A00007}, + {0x001101F0, 0xEB000001}, + {0x001101F4, 0xE3E00006}, + {0x001101F8, 0xE59FF008}, + {0x001101FC, 0xE59FF000}, + {0x00110200, 0x00000E2E}, + {0x00110204, 0x0001FD08}, + {0x00110208, 0x00004A30}, + {0x0011020C, 0xEA042DEC}, + {0x00110210, 0xE59F1080}, + {0x00110214, 0xE3A00007}, + {0x00110218, 0xEBFFFFF7}, + {0x0011021C, 0xE3A00007}, + {0x00110220, 0xE59F1078}, + {0x00110224, 0xEB00001A}, + {0x00110228, 0xE59F1070}, + {0x0011022C, 0xE5910000}, + {0x00110230, 0xE3100C80}, + {0x00110234, 0x1A000006}, + {0x00110238, 0xE59F1068}, + {0x0011023C, 0xE3A00000}, + {0x00110240, 0xE5810000}, + {0x00110244, 0xE51F104C}, + {0x00110248, 0xE3A00007}, + {0x0011024C, 0xEBFFFFEA}, + {0x00110250, 0xEAFFFFEE}, + {0x00110254, 0xE59F104C}, + {0x00110258, 0xE5910000}, + {0x0011025C, 0xE2800001}, + {0x00110260, 0xE5810000}, + {0x00110264, 0xE3500010}, + {0x00110268, 0xBAFFFFEB}, + {0x0011026C, 0xE59F103C}, + {0x00110270, 0xE3A00003}, + {0x00110274, 0xEBFFFFE0}, + {0x00110278, 0xE59F1034}, + {0x0011027C, 0xE3A00003}, + {0x00110280, 0xEBFFFFDD}, + {0x00110284, 0xE3A00000}, + {0x00110288, 0xE5810000}, + {0x0011028C, 0xE51F1238}, + {0x00110290, 0xE59FF020}, + {0x00110294, 0xE59FF010}, + {0x00110298, 0x0000082E}, + {0x0011029C, 0x00000000}, + {0x001102A0, 0x0011029C}, + {0x001102A4, 0x00000000}, + {0x001102A8, 0x001102A4}, + {0x001102AC, 0x00013750}, + {0x001102B0, 0x00002627}, + {0x001102B4, 0x00000627}, + {0x001102B8, 0x00004A5C}, + {0x001102BC, 0xEA042F5C}, + {0x001102C0, 0xE51F10C8}, + {0x001102C4, 0xE3A00007}, + {0x001102C8, 0xEBFFFFCB}, + {0x001102CC, 0xE3E00006}, + {0x001102D0, 0xE51FF004}, + {0x001102D4, 0x0000454C}, + {0x001102D8, 0xEA042F59}, + {0x001102DC, 0xE51F104C}, + {0x001102E0, 0xE3A00007}, + {0x001102E4, 0xEBFFFFC4}, + {0x001102E8, 0xE3A00007}, + {0x001102EC, 0xE51F1054}, + {0x001102F0, 0xEBFFFFE7}, + {0x001102F4, 0xE51F105C}, + {0x001102F8, 0xE5910000}, + {0x001102FC, 0xE3100C80}, + {0x00110300, 0x1A000006}, + {0x00110304, 0xE51F1064}, + {0x00110308, 0xE3A00000}, + {0x0011030C, 0xE5810000}, + {0x00110310, 0xE51F1118}, + {0x00110314, 0xE3A00007}, + {0x00110318, 0xEBFFFFB7}, + {0x0011031C, 0xEAFFFFEE}, + {0x00110320, 0xE51F1080}, + {0x00110324, 0xE5910000}, + {0x00110328, 0xE2800001}, + {0x0011032C, 0xE5810000}, + {0x00110330, 0xE3500010}, + {0x00110334, 0xBAFFFFEB}, + {0x00110338, 0xE51F1090}, + {0x0011033C, 0xE3A00003}, + {0x00110340, 0xEBFFFFAD}, + {0x00110344, 0xE51F1098}, + {0x00110348, 0xE3A00003}, + {0x0011034C, 0xEBFFFFAA}, + {0x00110350, 0xE3A00000}, + {0x00110354, 0xE5810000}, + {0x00110358, 0xE51F1304}, + {0x0011035C, 0xE51FF004}, + {0x00110360, 0x00004574}, + {0x20040004, 0x00011660}, + {0x20040024, 0x00110000}, + {0x20040008, 0x0001FD0C}, + {0x20040028, 0x0011000C}, + {0x2004000C, 0x0000BCB0}, + {0x2004002C, 0x00110068}, + {0x20040010, 0x0000E874}, + {0x20040030, 0x00110094}, + {0x20040014, 0x000106DC}, + {0x20040034, 0x001100C8}, + {0x20040018, 0x0000450C}, + {0x20040038, 0x001100F8}, + {0x2004001C, 0x000087DC}, + {0x2004003C, 0x00110148}, + {0x20040020, 0x000021B8}, + {0x20040040, 0x00110194}, + {0x20040100, 0x00002214}, + {0x20040120, 0x001101A4}, + {0x20040104, 0x00009E40}, + {0x20040124, 0x001101B4}, + {0x20040108, 0x00004A2C}, + {0x20040128, 0x001101E4}, + {0x2004010C, 0x00004A58}, + {0x2004012C, 0x0011020C}, + {0x20040110, 0x00004548}, + {0x20040130, 0x001102BC}, + {0x20040114, 0x00004570}, + {0x20040134, 0x001102D8}, + {0x20040000, 0x00003FFF}, +#endif +}; +#define SET_CHANNEL_MEM_TABLE_BASE_91F 0x0010D7B0 +#define SET_CHANNEL_RF_TABLE_BASE_91F 0x0010DA50 +static const u32 wifi_clock_switch_91f[][2] = { + + //channel 1 + {SET_CHANNEL_MEM_TABLE_BASE_91F, 0x50090048}, + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0x04, 0x604199C4}, + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0x08, 0x50000654}, + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0x0C, 0x2222CFCF}, + + //channel 2 + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0x30, 0x50090048}, + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0x34, 0x604199C4}, + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0x38, 0x50000654}, + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0x3C, 0x2222CFCF}, + + //channel 3 + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0x60, 0x50090048}, + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0x64, 0x604199C4}, + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0x68, 0x50000654}, + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0x6C, 0x2222CFCF}, + + //channel 4 + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0x90, 0x50090048}, + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0x94, 0x604199C4}, + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0x98, 0x50000654}, + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0x9C, 0x2222CFCF}, + + //channel 5 + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0xC0, 0x50090048}, + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0xC4, 0x304199C4},//diffrent with 91e + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0xC8, 0x50000654}, + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0xCC, 0x2222CFCF}, + + //channel 6 + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0xF0, 0x50090048}, + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0xF4, 0x204199C4}, + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0xF8, 0x50000654}, + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0xFC, 0x2222CFCF}, + + //channel 7 + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0x120, 0x50090048}, + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0x124, 0x204199C4}, + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0x128, 0x50000654}, + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0x12C, 0x2222CFCF}, + + //channel 8 + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0x150, 0x50090048}, + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0x154, 0x204199C4}, + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0x158, 0x50000654}, + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0x15C, 0x2222CFCF}, + + //channel 9 + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0x180, 0x50090048}, + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0x184, 0x604199C4}, + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0x188, 0x50000654}, + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0x18C, 0x2222CFCF}, + + //channel 10 + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0x1B0, 0x50090048}, + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0x1B4, 0x604199C4}, + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0x1B8, 0x50000654}, + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0x1BC, 0x2222CFCF}, + + //channel 11 + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0x1E0, 0x50090048}, + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0x1E4, 0x604199C4}, + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0x1E8, 0x50000654}, + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0x1EC, 0x2222CFCF}, + + //channel 12 + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0x210, 0x50090048}, + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0x214, 0x604199C4}, + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0x218, 0x50000654}, + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0x21C, 0x2222CFCF}, + + //channel 13 + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0x240, 0x50090048}, + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0x244, 0x304199C4}, + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0x248, 0x50000654}, + {SET_CHANNEL_MEM_TABLE_BASE_91F + 0x24C, 0x2222CFCF}, + + //channel 1 + {SET_CHANNEL_RF_TABLE_BASE_91F, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x04, 0x00000001}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x08, 0x00000038}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x0C, 0x00000808}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x10, 0x0000003E}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x14, 0x0000AA00}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x18, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x1C, 0x00000000}, + + //channel 2 + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x40, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x44, 0x00000001}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x48, 0x00000038}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x4C, 0x00000808}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x50, 0x0000003E}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x54, 0x0000AA00}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x58, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x5C, 0x00000000}, + + //channel 3 + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x80, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x84, 0x00000001}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x88, 0x00000038}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x8C, 0x00000808}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x90, 0x0000003E}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x94, 0x0000AA00}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x98, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x9C, 0x00000000}, + + //channel 4 + {SET_CHANNEL_RF_TABLE_BASE_91F + 0xC0, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0xC4, 0x00000001}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0xC8, 0x00000038}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0xCC, 0x00000808}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0xD0, 0x0000003E}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0xD4, 0x0000AA00}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0xD8, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0xDC, 0x00000000}, + + //channel 5 + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x100, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x104, 0x00000001}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x108, 0x00000038}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x10C, 0x00000B08},//diff with 91e + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x110, 0x0000003E}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x114, 0x0000AA12}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x118, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x11C, 0x00000000}, + + //channel 6 + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x140, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x144, 0x00000001}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x148, 0x00000038}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x14C, 0x00000908}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x150, 0x0000003E}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x154, 0x0000AA00}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x158, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x15C, 0x00000000}, + + //channel 7 + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x180, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x184, 0x00000001}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x188, 0x00000038}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x18C, 0x00000908}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x190, 0x0000003E}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x194, 0x0000AA00}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x198, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x19C, 0x00000000}, + + //channel 8 + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x1C0, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x1C4, 0x00000001}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x1C8, 0x00000038}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x1CC, 0x00000908}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x1D0, 0x0000003E}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x1D4, 0x0000AA00}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x1D8, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x1DC, 0x00000000}, + + //channel 9 + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x200, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x204, 0x00000001}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x208, 0x00000038}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x20C, 0x00000808}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x210, 0x0000003E}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x214, 0x0000AA00}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x218, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x21C, 0x00000000}, + + //channel 10 + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x240, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x244, 0x00000001}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x248, 0x00000038}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x24C, 0x00000808}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x250, 0x0000003E}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x254, 0x0000AA00}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x258, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x25C, 0x00000000}, + + //channel 11 + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x280, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x284, 0x00000001}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x288, 0x00000038}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x28C, 0x00000808}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x290, 0x0000003E}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x294, 0x0000AA00}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x298, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x29C, 0x00000000}, + + //channel 12 + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x2C0, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x2C4, 0x00000001}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x2C8, 0x00000038}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x2CC, 0x00000808}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x2D0, 0x0000003E}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x2D4, 0x0000AA00}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x2D8, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x2DC, 0x00000000}, + + //channel 13 + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x300, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x304, 0x00000001}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x308, 0x00000038}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x30C, 0x00000B08}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x310, 0x0000003E}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x314, 0x0000AA12}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x318, 0x0000003F}, + {SET_CHANNEL_RF_TABLE_BASE_91F + 0x31C, 0x00000000}, + +}; + +static const u8 wifi_core_patch_data_91f_8[][2] = { + {0x28, 0x1a}, + {0x29, 0x0d}, + {0x25, 0x00}, + {0x08, 0x43}, + //rx patch + {0x26, 0x35}, + {0x3e, 0x64}, + {0x3f, 0x00}, + {0x45, 0x75}, + {0x46, 0x73}, + {0x50, 0x58}, + {0x30, 0xf6}, + + {0xA0, 0x7f}, + {0x74, 0x01}, + {0x75, 0x40}, + + {0x12, 0x04}, + {0x1C, 0x2D}, + {0x0D, 0x59}, + {0x17, 0x75}, + {0x74, 0xD4}, + {0x75, 0x47}, + + {0x74, 0xFF}, + {0x75, 0x4B}, + + {0x74, 0x3D}, + {0x75, 0x4C}, + + {0x74, 0x01}, + {0x75, 0x50}, + + {0x74, 0x99}, + {0x75, 0x57}, + + {0x74, 0xFF}, + {0x75, 0x5B}, + + {0x74, 0x33}, + {0x75, 0x5D}, + + {0x74, 0xE4}, + {0x75, 0x61}, + + {0x30, 0xF7}, +}; + +static const u32 wifi_core_init_data_32_91f[][2] = { + {0x500002a8, 0x00000001}, + {0x50000080, 0x0003FEF7}, +#if 0 + {0x00100018, 0x000A3243}, // flow ctrl , WPS supported, proakis + {0x0010001C, 0xFFFF0001}, +#endif + {0x30010010, 0x00007DFF}, + + {0x50090060, 0x000001B4}, + //item:rda5991_verE_wf_tx_pn9 + {0x50090068, 0xEB3FF7FF}, + {0x50090070, 0x1403DBFF}, + {0x500900B0, 0x00400000}, + {0x500900A8, 0xE0400048}, + {0x5009008C, 0xF6700000}, + //PHY:phy rx timeout enable +#if 0 + {0x0010216c, 0x50000634}, + {0x00102170, 0x00001100}, + {0x00102174, 0x50000584}, + {0x00102178, 0x00007bf8}, +#endif +}; + +static const u32 wifi_core_AM_PM_data_32_91f[][2] = { + {0x50090054, 0x00000000}, + {0x50090068, 0xEB3FF7FF}, + {0x50090070, 0x1403DBFF}, + {0x500900B0, 0x00400000}, + //item0:theta0=7_B=0_r0=2_for_verE + {0x50090090, 0x00000000}, + {0x50090094, 0x00A01401}, + {0x50090098, 0x02907412}, + {0x5009009C, 0x05D12438}, + {0x500900A0, 0x0A522872}, + {0x500900A4, 0xFFF380C1}, + //item0:G0=-3.5_r0=2.5_for_verE + {0x50090078, 0x02B05400}, + {0x5009007C, 0x06D15840}, + {0x50090080, 0x0B927885}, + {0x50090084, 0x11A3DCD7}, + {0x50090088, 0x1975A540}, + {0x5009008C, 0xFFF7FDC9}, + {0x500900A8, 0x9C4001A0}, + +}; +const u32 wifi_phy_timeout_cfg_91f[][2] = +{ + {0x50000634, 0x00001100}, + {0x50000584, 0x00007BF8}, +}; + +#endif + diff --git a/drivers/net/wireless/rda/rda_wlan/wlan_wext.c b/drivers/net/wireless/rda/rda_wlan/wlan_wext.c new file mode 100755 index 00000000..cd32c542 --- /dev/null +++ b/drivers/net/wireless/rda/rda_wlan/wlan_wext.c @@ -0,0 +1,1870 @@ +#include "wlan_includes.h" + +static int wlan_get_name(struct net_device *dev, struct iw_request_info *info, + char *cwrq, char *extra) +{ + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + /* We could add support for 802.11n here as needed. Jean II */ + snprintf(cwrq, IFNAMSIZ, "IEEE 802.11b/g"); + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return 0; +} + +static int wlan_get_freq(struct net_device *dev, struct iw_request_info *info, + struct iw_freq *fwrq, char *extra) +{ + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + fwrq->m = (long)2437 *100000; + fwrq->e = 1; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return 0; +} + +static int wlan_get_wap(struct net_device *dev, struct iw_request_info *info, + struct sockaddr *awrq, char *extra) +{ + wlan_private *priv = (wlan_private *) netdev_priv(dev); + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + if (priv->connect_status == MAC_CONNECTED) { + memcpy(awrq->sa_data, priv->curbssparams.bssid, ETH_ALEN); + } else { + memset(awrq->sa_data, 0, ETH_ALEN); + } + awrq->sa_family = ARPHRD_ETHER; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return 0; +} + +static int wlan_set_nick(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return 0; +} + +static int wlan_get_nick(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return 0; +} + +static int wlan_set_rts(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return 0; +} + +static int wlan_get_rts(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + int ret = 0; + u16 val = 0; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + val = 600; + + vwrq->value = val; + vwrq->disabled = val > WLAN_RTS_MAX_VALUE; /* min rts value is 0 */ + vwrq->fixed = 1; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return ret; +} + +static int wlan_set_frag(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return 0; +} + +static int wlan_get_frag(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + int ret = 0; + u16 val = 0; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + val = 1460; + + vwrq->value = val; + vwrq->disabled = ((val < WLAN_FRAG_MIN_VALUE) + || (val > WLAN_FRAG_MAX_VALUE)); + vwrq->fixed = 1; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return ret; +} + +static int wlan_get_mode(struct net_device *dev, + struct iw_request_info *info, u32 * uwrq, char *extra) +{ + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + *uwrq = IW_MODE_INFRA; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return 0; +} + +static int wlan_get_txpow(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + vwrq->value = 20; // in dbm + vwrq->fixed = 1; + vwrq->disabled = 0; + vwrq->flags = IW_TXPOW_DBM; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return 0; +} + +static int wlan_set_retry(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return 0; +} + +static int wlan_get_retry(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + int ret = 0; + u16 val = 0; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + vwrq->disabled = 0; + + if (vwrq->flags & IW_RETRY_LONG) { + val = 7; + + /* Subtract 1 to convert try count to retry count */ + vwrq->value = val - 1; + vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG; + } else { + val = 6; + + /* Subtract 1 to convert try count to retry count */ + vwrq->value = val - 1; + vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_SHORT; + } + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return ret; +} + +/** + * 802.11b/g supported bitrates (in 500Kb/s units) + */ +u8 wlan_bg_rates[MAX_RATES] = { 0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18, + 0x24, 0x30, 0x48, 0x60, 0x6c, 0x00, 0x00 +}; + +u16 wlan_nr_chan = 11; + +/** + * @brief Get Range Info + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return 0 --success, otherwise fail + */ +static int wlan_get_range(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + struct iw_range *range = (struct iw_range *)extra; + int i; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + dwrq->length = sizeof(struct iw_range); + memset(range, 0, sizeof(struct iw_range)); + + range->min_nwid = 0; + range->max_nwid = 0; + + range->num_bitrates = sizeof(wlan_bg_rates); + for (i = 0; i < range->num_bitrates; i++) + range->bitrate[i] = wlan_bg_rates[i] * 500000; + range->num_bitrates = i; + + range->num_frequency = 0; + + range->scan_capa = IW_SCAN_CAPA_ESSID; + + for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES) + && (i < wlan_nr_chan); i++) { + range->freq[range->num_frequency].i = (long)(i + 1); + range->freq[range->num_frequency].m = + (long)((2412 + 5 * i) * 100000); + range->freq[range->num_frequency].e = 1; + range->num_frequency++; + } + + range->num_channels = range->num_frequency; + + /* + * Set an indication of the max TCP throughput in bit/s that we can + * expect using this interface + */ + range->throughput = 5000 * 1000; + + range->min_rts = WLAN_RTS_MIN_VALUE; + range->max_rts = WLAN_RTS_MAX_VALUE; + range->min_frag = WLAN_FRAG_MIN_VALUE; + range->max_frag = WLAN_FRAG_MAX_VALUE; + + range->encoding_size[0] = 5; + range->encoding_size[1] = 13; + range->num_encoding_sizes = 2; + range->max_encoding_tokens = 4; + + /* + * Right now we support only "iwconfig ethX power on|off" + */ + range->pm_capa = IW_POWER_ON; + + /* + * Minimum version we recommend + */ + range->we_version_source = 15; + + /* + * Version we are compiled with + */ + range->we_version_compiled = WIRELESS_EXT; + + range->retry_capa = IW_RETRY_LIMIT; + range->retry_flags = IW_RETRY_LIMIT | IW_RETRY_MAX; + + range->min_retry = 0; + range->max_retry = 14; + + /* + * Set the qual, level and noise range values + */ + range->max_qual.qual = 100; + range->max_qual.level = 0; + range->max_qual.noise = 0; + range->max_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; + + range->avg_qual.qual = 70; + /* TODO: Find real 'good' to 'bad' threshold value for RSSI */ + range->avg_qual.level = 0; + range->avg_qual.noise = 0; + range->avg_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; + + range->sensitivity = 0; + + /* Setup the supported power level ranges */ + memset(range->txpower, 0, sizeof(range->txpower)); + range->txpower_capa = IW_TXPOW_DBM | IW_TXPOW_RANGE; + range->txpower[0] = 0; + range->txpower[1] = 20; + range->num_txpower = 2; + + range->event_capa[0] = (IW_EVENT_CAPA_K_0 | + IW_EVENT_CAPA_MASK(SIOCGIWAP) | + IW_EVENT_CAPA_MASK(SIOCGIWSCAN)); + range->event_capa[1] = IW_EVENT_CAPA_K_1; + + range->enc_capa = IW_ENC_CAPA_WPA + | IW_ENC_CAPA_WPA2 + | IW_ENC_CAPA_CIPHER_TKIP + | IW_ENC_CAPA_CIPHER_CCMP; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return 0; +} + +static int wlan_set_power(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return 0; +} + +static int wlan_get_power(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + vwrq->value = 0; + vwrq->flags = 0; + vwrq->disabled = 0; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return 0; +} + +static int wlan_update_bss_stats(wlan_private * priv) +{ + int ret = -1; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + memcpy(priv->curbssparams.ssid, + priv->assoc_ssid, sizeof(priv->curbssparams.ssid)); + + if (priv->scan_running == WLAN_SCAN_RUNNING) + return 0; + + ret = wlan_get_bssid(priv, priv->curbssparams.bssid); + if (ret) { + WLAN_ERRP("wlan_get_bssid, ret = %d\n", ret); + goto out; + } + + ret = wlan_get_rssi(priv, &priv->curbssparams.rssi); + if (ret) { + WLAN_ERRP("wlan_get_rssi, ret = %d\n", ret); + goto out; + } + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<< ch = %d rssi = %d\n", + __func__, priv->curbssparams.channel, + priv->curbssparams.rssi); + +out: + return ret; +} + +static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev) +{ + wlan_private *priv = (wlan_private *) netdev_priv(dev); + int stats_valid = 0; + u8 snr; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + if (priv->connect_status != MAC_CONNECTED) + goto out; + + wlan_update_bss_stats(priv); + + priv->wstats.miss.beacon = 0; + priv->wstats.discard.retries = 0; + priv->wstats.qual.level = 0x100 + (s8)priv->curbssparams.rssi; + + snr = priv->wstats.qual.level - WLAN_NF_DEFAULT_SCAN_VALUE; + priv->wstats.qual.qual = + (100 * RSSI_DIFF * RSSI_DIFF - (PERFECT_RSSI - snr) * + (15 * (RSSI_DIFF) + 62 * (PERFECT_RSSI - snr))) / + (RSSI_DIFF * RSSI_DIFF); + if (priv->wstats.qual.qual > 100) + priv->wstats.qual.qual = 100; + priv->wstats.qual.noise = WLAN_NF_DEFAULT_SCAN_VALUE; + priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; + + stats_valid = 1; + +out: + if (!stats_valid) { + priv->wstats.miss.beacon = 0; + priv->wstats.discard.retries = 0; + priv->wstats.qual.qual = 0; + priv->wstats.qual.level = 0; + priv->wstats.qual.noise = 0; + priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED; + priv->wstats.qual.updated |= IW_QUAL_NOISE_INVALID | + IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID; + } + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return &priv->wstats; +} + +static int wlan_set_freq(struct net_device *dev, struct iw_request_info *info, + struct iw_freq *fwrq, char *extra) +{ + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return 0; +} + +static int wlan_set_rate(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return 0; +} + +static int wlan_get_rate(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + int ret = 0; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + vwrq->fixed = 0; + vwrq->value = 54*1000; + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return ret; +} + +static int wlan_set_mode(struct net_device *dev, + struct iw_request_info *info, u32 * uwrq, char *extra) +{ + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return 0; +} + +/** + * @brief Get Encryption key + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return 0 --success, otherwise fail + */ +static int wlan_get_encode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, u8 * extra) +{ + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return 0; +} + +/** + * @brief Set Encryption key + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return 0 --success, otherwise fail + */ +static int wlan_set_encode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return 0; +} + +/** + * @brief Set Encryption key (internal) + * + * @param priv A pointer to private card structure + * @param key_material A pointer to key material + * @param key_length length of key material + * @param index key index to set + * @param set_tx_key Force set TX key (1 = yes, 0 = no) + * @return 0 --success, otherwise fail + */ +static int copy_wep_key(wlan_private * priv, + const char *key_material, + u16 key_length, u16 index, int set_tx_key) +{ + int ret = 0; + struct enc_key *pkey; + + /* Paranoid validation of key index */ + if (index > 3) { + ret = -EINVAL; + goto out; + } + + /* validate max key length */ + if (key_length > KEY_LEN_WEP_104) { + ret = -EINVAL; + goto out; + } + + if (key_length == KEY_LEN_WEP_40) { + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "WEP40 : %02x%02x%02x%02x%02x\n", + key_material[0], key_material[1], key_material[2], + key_material[3], key_material[4]); + } else if (key_length == KEY_LEN_WEP_104) { + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "WEP104 : %02x%02x%02x%02x%02x" + " %02x%02x%02x%02x%02x" + " %02x%02x%02x\n", + key_material[0], key_material[1], key_material[2], + key_material[3], key_material[4], key_material[5], + key_material[6], key_material[7], key_material[8], + key_material[9], key_material[10], key_material[11], + key_material[12]); + } else { + WLAN_ERRP("Error in WEP Key length %d\n", key_length); + } + + pkey = &priv->wep_keys[index]; + + if (key_length > 0) { + memset(pkey, 0, sizeof(struct enc_key)); + pkey->type = KEY_TYPE_ID_WEP; + + /* Standardize the key length */ + pkey->len = (key_length > KEY_LEN_WEP_40) ? + KEY_LEN_WEP_104 : KEY_LEN_WEP_40; + memcpy(pkey->key, key_material, key_length); + } + + if (set_tx_key) { + /* Ensure the chosen key is valid */ + if (!pkey->len) { + WLAN_ERRP("key not set, so cannot enable it\n"); + ret = -EINVAL; + goto out; + } + priv->wep_tx_keyidx = index; + } + + priv->secinfo.wep_enabled = 1; + +out: + return ret; +} + +static int validate_key_index(u16 def_index, u16 raw_index, + u16 * out_index, u16 * is_default) +{ + if (!out_index || !is_default) + return -EINVAL; + + /* Verify index if present, otherwise use default TX key index */ + if (raw_index > 0) { + if (raw_index > 4) + return -EINVAL; + *out_index = raw_index - 1; + } else { + *out_index = def_index; + *is_default = 1; + } + return 0; +} + +static void disable_wep(wlan_private * priv) +{ + int i; + + /* Set Open System auth mode */ + priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; + + /* Clear WEP keys and mark WEP as disabled */ + priv->secinfo.wep_enabled = 0; + for (i = 0; i < 4; i++) + priv->wep_keys[i].len = 0; +} + +static void disable_wpa(wlan_private * priv) +{ + memset(&priv->wpa_mcast_key, 0, sizeof(struct enc_key)); + priv->wpa_mcast_key.flags = KEY_INFO_WPA_MCAST; + + memset(&priv->wpa_unicast_key, 0, sizeof(struct enc_key)); + priv->wpa_unicast_key.flags = KEY_INFO_WPA_UNICAST; + + priv->secinfo.WPAenabled = 0; + priv->secinfo.WPA2enabled = 0; + priv->secinfo.cipther_type = 0; + priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; +} + +/** + * @brief Get Extended Encryption key (WPA/802.1x and WEP) + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return 0 on success, otherwise failure + */ +static int wlan_get_encodeext(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + wlan_private *priv = (wlan_private *) netdev_priv(dev); + int ret = -EINVAL; + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; + int index, max_key_len; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + max_key_len = dwrq->length - sizeof(*ext); + if (max_key_len < 0) + goto out; + + index = dwrq->flags & IW_ENCODE_INDEX; + if (index) { + if (index < 1 || index > 4) + goto out; + index--; + } else { + index = priv->wep_tx_keyidx; + } + + if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) && + ext->alg != IW_ENCODE_ALG_WEP) { + if (index != 0) + goto out; + } + + dwrq->flags = index + 1; + memset(ext, 0, sizeof(*ext)); + + if (!priv->secinfo.wep_enabled + && !priv->secinfo.WPAenabled + && !priv->secinfo.WPA2enabled) { + ext->alg = IW_ENCODE_ALG_NONE; + ext->key_len = 0; + dwrq->flags |= IW_ENCODE_DISABLED; + } else { + u8 *key = NULL; + + if (priv->secinfo.wep_enabled + && !priv->secinfo.WPAenabled + && !priv->secinfo.WPA2enabled) { + /* WEP */ + ext->alg = IW_ENCODE_ALG_WEP; + ext->key_len = priv->wep_keys[index].len; + key = &priv->wep_keys[index].key[0]; + } else if (!priv->secinfo.wep_enabled + && (priv->secinfo.WPAenabled || + priv->secinfo.WPA2enabled)) { + /* WPA */ + struct enc_key *pkey = NULL; + + if (priv->wpa_mcast_key.len + && (priv->wpa_mcast_key. + flags & KEY_INFO_WPA_ENABLED)) + pkey = &priv->wpa_mcast_key; + else if (priv->wpa_unicast_key.len + && (priv->wpa_unicast_key. + flags & KEY_INFO_WPA_ENABLED)) + pkey = &priv->wpa_unicast_key; + + if (pkey) { + if (pkey->type == KEY_TYPE_ID_AES) { + ext->alg = IW_ENCODE_ALG_CCMP; + } else { + ext->alg = IW_ENCODE_ALG_TKIP; + } + ext->key_len = pkey->len; + key = &pkey->key[0]; + } else { + ext->alg = IW_ENCODE_ALG_TKIP; + ext->key_len = 0; + } + } else { + goto out; + } + + if (ext->key_len > max_key_len) { + ret = -E2BIG; + goto out; + } + + if (ext->key_len) + memcpy(ext->key, key, ext->key_len); + else + dwrq->flags |= IW_ENCODE_NOKEY; + dwrq->flags |= IW_ENCODE_ENABLED; + } + ret = 0; + +out: + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return 0; +} + +/** + * @brief Set Encryption key Extended (WPA/802.1x and WEP) + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return 0 --success, otherwise fail + */ +static int wlan_set_encodeext(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + wlan_private *priv = (wlan_private *) netdev_priv(dev); + int ret = 0; + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; + int alg = ext->alg; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + if ((alg == IW_ENCODE_ALG_NONE) || (dwrq->flags & IW_ENCODE_DISABLED)) { + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "NO SEC\n"); + + if (priv->imode != 3 && priv->imode != 5) + disable_wep(priv); + disable_wpa(priv); + } else if (alg == IW_ENCODE_ALG_WEP) { + u16 is_default = 0, index, set_tx_key = 0; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "WEP, flags = 0x%04x\n", dwrq->flags); + + ret = validate_key_index(priv->wep_tx_keyidx, + (dwrq->flags & IW_ENCODE_INDEX), + &index, &is_default); + if (ret) + goto out; + + /* If WEP isn't enabled, or if there is no key data but a valid + * index, or if the set-TX-key flag was passed, set the TX key. + */ + if (!priv->secinfo.wep_enabled + || (dwrq->length == 0 && !is_default) + || (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)) + set_tx_key = 1; + + /* Copy key to driver */ + ret = copy_wep_key(priv, ext->key, ext->key_len, index, set_tx_key); + if (ret) + goto out; + + if (dwrq->flags & IW_ENCODE_RESTRICTED) { + priv->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY; + } else if (dwrq->flags & IW_ENCODE_OPEN) { + priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; + } + + } else if ((alg == IW_ENCODE_ALG_TKIP) || (alg == IW_ENCODE_ALG_CCMP)) { + struct enc_key *pkey; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "TKIP or CCMP, flags = 0x%04x, alg = %d\n", + dwrq->flags, alg); + + /* validate key length */ + if (((alg == IW_ENCODE_ALG_TKIP) + && (ext->key_len != KEY_LEN_WPA_TKIP)) + || ((alg == IW_ENCODE_ALG_CCMP) + && (ext->key_len != KEY_LEN_WPA_AES))) { + WLAN_ERRP("invalid size %d for key of alg, type %d\n", + ext->key_len, alg); + ret = -EINVAL; + goto out; + } + + /* Copy key to driver */ + if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { + pkey = &priv->wpa_mcast_key; + } else { + pkey = &priv->wpa_unicast_key; + } + + memset(pkey, 0, sizeof(struct enc_key)); + memcpy(pkey->key, ext->key, ext->key_len); + pkey->len = ext->key_len; + if (pkey->len) + pkey->flags |= KEY_INFO_WPA_ENABLED; + + /* Do this after zeroing key structure */ + if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { + pkey->flags |= KEY_INFO_WPA_MCAST; + } else { + pkey->flags |= KEY_INFO_WPA_UNICAST; + } + + if (alg == IW_ENCODE_ALG_TKIP) { + pkey->type = KEY_TYPE_ID_TKIP; + if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) + && !(priv->imode & (BIT6))) { + WLAN_ERRP("imode [0x%x] not match with cipher alg TKIP\n", + priv->imode); + } + } else if (alg == IW_ENCODE_ALG_CCMP) { + pkey->type = KEY_TYPE_ID_AES; + if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) + && !(priv->imode & (BIT5))) { + WLAN_ERRP("imode [0x%x] not match with cipher alg CCMP\n", + priv->imode); + } + } + + /* If WPA isn't enabled yet, do that now */ + if (priv->secinfo.WPAenabled == 0 + && priv->secinfo.WPA2enabled == 0) { + priv->secinfo.WPAenabled = 1; + priv->secinfo.WPA2enabled = 1; + } + + /* Set Keys to MAC */ + if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { + /* Set GTK */ + ret = wlan_set_gtk(priv, (dwrq->flags & IW_ENCODE_INDEX) - 1, ext->tx_seq, IW_ENCODE_SEQ_MAX_SIZE, pkey->key, pkey->len); + if (ret) + goto out; + } else { + pkey->flags |= KEY_INFO_WPA_UNICAST; + /* Set PTK */ + ret = wlan_set_ptk(priv, pkey->key, pkey->len); + if (ret) + goto out; + } + + /* Only disable wep if necessary: can't waste time here. */ + disable_wep(priv); + } else if (alg == IW_ENCODE_ALG_SM4) { //wapi + if (ext->key_len != 32) + goto out; + + priv->is_wapi = 1; + + /* Set Keys to MAC */ + if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { + unsigned char tmp[8]; + /* Set GTK */ + /* + * + * need to toggle among 1, 2, 3 + */ + ret = wlan_set_gtk(priv, (dwrq->flags & IW_ENCODE_INDEX) - 1, tmp, IW_ENCODE_SEQ_MAX_SIZE, ext->key, ext->key_len); + if (ret) + goto out; + } else { + /* Set PTK */ + ret = wlan_set_ptk(priv, ext->key, ext->key_len); + if (ret) + goto out; + } + } + +out: + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return 0; +} + +/** + * @brief PMKSA cache operation (WPA/802.1x and WEP) + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return 0 on success, otherwise failure + */ +static int wlan_set_pmksa(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return 0; +} + +static int wlan_set_genie(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + wlan_private *priv = (wlan_private *) netdev_priv(dev); + int ret = 0; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + if(priv->version == WLAN_VERSION_91_E|| priv->version == WLAN_VERSION_91_F){ + unsigned char ie_len; + //huanglei add wps + ie_len = extra[1] + 2; + wlan_generic_set_str(priv, WID_GEN_ASSOC_IE, extra ,ie_len); + } + + if (extra[0] == 0x44) //wapi ie + { + unsigned char ie_len = extra[1] + 2; + wlan_generic_set_str(priv, WID_WAPI_ASSOC_IE, extra, ie_len); + goto out; + } + + if (dwrq->length > MAX_WPA_IE_LEN || (dwrq->length && extra == NULL)) { + ret = -EINVAL; + goto out; + } + + if (dwrq->length) { + memcpy(&priv->wpa_ie[0], extra, dwrq->length); + priv->wpa_ie_len = dwrq->length; + } else { + memset(&priv->wpa_ie[0], 0, sizeof(priv->wpa_ie)); + priv->wpa_ie_len = 0; + } + +out: + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return ret; +} + +static int wlan_get_genie(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + wlan_private *priv = (wlan_private *) netdev_priv(dev); + int ret = 0; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + if (priv->wpa_ie_len == 0) { + dwrq->length = 0; + goto out; + } + + if (dwrq->length < priv->wpa_ie_len) { + ret = -E2BIG; + goto out; + } + + dwrq->length = priv->wpa_ie_len; + memcpy(extra, &priv->wpa_ie[0], priv->wpa_ie_len); + +out: + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return ret; +} + +static int wlan_set_auth(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *dwrq, char *extra) +{ + wlan_private *priv = (wlan_private *) netdev_priv(dev); + int ret = 0; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "flags = 0x%04x, value = 0x%x\n", dwrq->flags, dwrq->value); + + switch (dwrq->flags & IW_AUTH_INDEX) { + case IW_AUTH_CIPHER_PAIRWISE: + if (dwrq->value & (IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_WEP40)) { + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "WEP Selected \n"); + priv->secinfo.wep_enabled = 1; + if (dwrq->value & IW_AUTH_CIPHER_WEP104) + priv->secinfo.cipther_type |= IW_AUTH_CIPHER_WEP104; + else if (dwrq->value & IW_AUTH_CIPHER_WEP40) + priv->secinfo.cipther_type |= IW_AUTH_CIPHER_WEP40; + } + if (dwrq->value & IW_AUTH_CIPHER_TKIP) { + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "IW_AUTH_CIPHER_TKIP \n"); + priv->secinfo.cipther_type |= IW_AUTH_CIPHER_TKIP; + } + if (dwrq->value & IW_AUTH_CIPHER_CCMP) { + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "IW_AUTH_CIPHER_CCMP \n"); + priv->secinfo.cipther_type |= IW_AUTH_CIPHER_CCMP; + } + if (dwrq->value & IW_AUTH_CIPHER_NONE) { + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "OPEN System \n"); + priv->secinfo.cipther_type = IW_AUTH_CIPHER_NONE; + } + break; + + case IW_AUTH_TKIP_COUNTERMEASURES: + case IW_AUTH_CIPHER_GROUP: + case IW_AUTH_DROP_UNENCRYPTED: + /* + * wlan does not use these parameters + */ + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "DO NOT USE\n"); + break; + + case IW_AUTH_KEY_MGMT: + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "KEY_MGMT, val = %d\n", dwrq->value); + priv->secinfo.key_mgmt = dwrq->value; + break; + + case IW_AUTH_WPA_VERSION: + if (dwrq->value & IW_AUTH_WPA_VERSION_DISABLED) { + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "WPA_VERSION, DISABLED\n"); + priv->secinfo.WPAenabled = 0; + priv->secinfo.WPA2enabled = 0; + disable_wpa(priv); + } + if (dwrq->value & IW_AUTH_WPA_VERSION_WPA) { + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "WPA_VERSION, WPA\n"); + priv->secinfo.WPAenabled = 1; + priv->secinfo.wep_enabled = 0; + priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; + } + if (dwrq->value & IW_AUTH_WPA_VERSION_WPA2) { + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "WPA_VERSION, WPA2\n"); + priv->secinfo.WPA2enabled = 1; + priv->secinfo.wep_enabled = 0; + priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; + } + break; + + case IW_AUTH_80211_AUTH_ALG: + if (dwrq->value & IW_AUTH_ALG_SHARED_KEY || + dwrq->value & IW_AUTH_ALG_OPEN_SYSTEM) { + if (dwrq->value & IW_AUTH_ALG_SHARED_KEY) { + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "80211_AUTH_ALG, SHARED_KEY\n"); + priv->secinfo.auth_mode |= IW_AUTH_ALG_SHARED_KEY; + } + if (dwrq->value & IW_AUTH_ALG_OPEN_SYSTEM) { + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "80211_AUTH_ALG, OPEN\n"); + priv->secinfo.auth_mode |= IW_AUTH_ALG_OPEN_SYSTEM; + } + } else if (dwrq->value & IW_AUTH_ALG_LEAP) { + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "80211_AUTH_ALG, LEAP\n"); + priv->secinfo.auth_mode = IW_AUTH_ALG_LEAP; + } else if (dwrq->value & IW_AUTH_ALG_WAPI) { + priv->secinfo.auth_mode = IW_AUTH_ALG_WAPI; + } else { + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "80211_AUTH_ALG, unknown\n"); + ret = -EINVAL; + } + break; + + case IW_AUTH_WPA_ENABLED: + if (dwrq->value) { + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "WPA_ENABLED, value = 0x%x\n", dwrq->value); + if (!priv->secinfo.WPAenabled && + !priv->secinfo.WPA2enabled) { + priv->secinfo.WPAenabled = 1; + priv->secinfo.WPA2enabled = 1; + priv->secinfo.wep_enabled = 0; + priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; + } + } else { + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "WPA_ENABLED, value = ZERO\n"); + priv->secinfo.WPAenabled = 0; + priv->secinfo.WPA2enabled = 0; + disable_wpa(priv); + } + break; + + case IW_AUTH_WAPI_ENABLED: + if (dwrq->value & BIT1) { + disable_wpa(priv); + disable_wep(priv); + priv->secinfo.auth_mode = IW_AUTH_ALG_WAPI; + } else if (dwrq->value & BIT2) { + disable_wpa(priv); + disable_wep(priv); + priv->secinfo.auth_mode = IW_AUTH_ALG_WAPI; + } + break; + + default: + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "NOT SUPPORT\n"); + ret = -EOPNOTSUPP; + break; + } + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return ret; +} + +static int wlan_get_auth(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *dwrq, char *extra) +{ + wlan_private *priv = (wlan_private *) netdev_priv(dev); + int ret = 0; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + + switch (dwrq->flags & IW_AUTH_INDEX) { + case IW_AUTH_KEY_MGMT: + dwrq->value = priv->secinfo.key_mgmt; + break; + + case IW_AUTH_WPA_VERSION: + dwrq->value = 0; + if (priv->secinfo.WPAenabled) + dwrq->value |= IW_AUTH_WPA_VERSION_WPA; + if (priv->secinfo.WPA2enabled) + dwrq->value |= IW_AUTH_WPA_VERSION_WPA2; + if (!dwrq->value) + dwrq->value |= IW_AUTH_WPA_VERSION_DISABLED; + break; + + case IW_AUTH_80211_AUTH_ALG: + dwrq->value = priv->secinfo.auth_mode; + break; + + case IW_AUTH_WPA_ENABLED: + if (priv->secinfo.WPAenabled && priv->secinfo.WPA2enabled) + dwrq->value = 1; + break; + + default: + ret = -EOPNOTSUPP; + } + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + return ret; +} + +static int wlan_set_txpow(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + return 0; +} + +static int wlan_get_essid(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + wlan_private *priv = (wlan_private *) netdev_priv(dev); + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + + memcpy(extra, priv->curbssparams.ssid, strlen(priv->curbssparams.ssid)); + dwrq->length = strlen(priv->curbssparams.ssid); + extra[dwrq->length] = '\0'; + + /* + * If none, we may want to get the one that was set + */ + + dwrq->flags = 1; /* active */ + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>> \n", __func__); + return 0; +} + +void wlan_indicate_disconnected(wlan_private * priv) +{ + union iwreq_data wrqu; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_NORM, "%s <<<\n", __func__); + + memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + wireless_send_event(priv->netDev, SIOCGIWAP, &wrqu, NULL); + + /*report disconnect to upper layer */ + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_NORM, "%s >>>\n", __func__); +} + +void wlan_indicate_connected(wlan_private * priv) +{ + union iwreq_data wrqu; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_NORM, "%s <<<\n", __func__); + + memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + wireless_send_event(priv->netDev, SIOCGIWAP, &wrqu, NULL); + + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_NORM, "%s >>> \n connect mac: %2x:%2x:%2x:%2x:%2x:%2x \n", + __func__, priv->curbssparams.bssid[0], + priv->curbssparams.bssid[1], priv->curbssparams.bssid[2], + priv->curbssparams.bssid[3], priv->curbssparams.bssid[4], + priv->curbssparams.bssid[5]); +} + +struct bss_descriptor *get_bss_desc_from_scanlist(wlan_private * priv, + unsigned char *bssid) +{ + struct bss_descriptor *iter_bss; + struct bss_descriptor *ret_bss = NULL; + + spin_lock(&priv->ScanListLock); + /* report all bss to upper layer */ + list_for_each_entry(iter_bss, &priv->network_list, list) { + if (memcmp(iter_bss->bssid, bssid, 6) == 0) { + ret_bss = iter_bss; + break; + } + } + spin_unlock(&priv->ScanListLock); + return ret_bss; +} + +static int wlan_set_essid(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + wlan_private *priv = (wlan_private *) netdev_priv(dev); + int ret = 0; + u8 ssid[IW_ESSID_MAX_SIZE + 1]; + u8 ssid_len = 0; + int in_ssid_len = dwrq->length; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + /* Check the size of the string */ + if (in_ssid_len > IW_ESSID_MAX_SIZE) { + ret = -E2BIG; + goto out; + } + + memset(&ssid, 0, sizeof(ssid)); + + if (!dwrq->flags || !in_ssid_len) { + /* "any" SSID requested; leave SSID blank */ + } else { + /* Specific SSID requested */ + memcpy(&ssid, extra, in_ssid_len); + ssid[in_ssid_len] = '\0'; + ssid_len = in_ssid_len; + } + + if (!ssid_len) { + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "requested any SSID\n"); + } else { + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "requested SSID len = %d ssid:%s\n", + ssid_len, ssid); + } + + if (ssid_len) { + memcpy(&priv->assoc_ssid[0], ssid, sizeof(ssid)); + priv->assoc_ssid_len = ssid_len; +#if 0 + priv->ToggalAssociation = FALSE; + + if (priv->StartAssociationTimeOut.timer_is_canceled) + wlan_mod_timer(&priv->StartAssociationTimeOut, 100); + priv->assoc_ongoing = TRUE; +#endif + } + +out: + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return 0; +} + + +/** + * @brief Connect to the AP or Ad-hoc Network with specific bssid + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param awrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return 0 --success, otherwise fail + */ + +static int wlan_set_wap(struct net_device *dev, struct iw_request_info *info, + struct sockaddr *awrq, char *extra) +{ + unsigned char *ap_addr = NULL; + wlan_private *priv = (wlan_private *) netdev_priv(dev); + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<< \n", __func__); + + ap_addr = awrq->sa_data; + if (!is_zero_eth_addr(ap_addr)) { + priv->reassoc_count = 0; + if (memcmp(priv->assoc_bssid, ap_addr, 6)) { + memcpy(priv->assoc_bssid, ap_addr, 6); + priv->ToggalAssociation = FALSE; + if (!priv->ReAssociationTimeOut.timer_is_canceled) { + wlan_cancel_timer(&priv->ReAssociationTimeOut); + } + if (priv->StartAssociationTimeOut.timer_is_canceled) + wlan_mod_timer(&priv->StartAssociationTimeOut, 100); + } else { + if (priv->ReAssociationTimeOut.timer_is_canceled) { + wlan_mod_timer(&priv->StartAssociationTimeOut, 100); + } + } + priv->assoc_ongoing = TRUE; + } else { + memcpy(priv->assoc_bssid, ap_addr, 6); + wlan_cancel_timer(&priv->ReAssociationTimeOut); + wlan_cancel_timer(&priv->StartAssociationTimeOut); + + disable_wep(priv); + disable_wpa(priv); + } + + WLAN_ERRP("%s <<< \n connect mac: %2x:%2x:%2x:%2x:%2x:%2x \n", __func__, + ap_addr[0], ap_addr[1], ap_addr[2], ap_addr[3], ap_addr[4], ap_addr[5]); + + return 0; +} + +unsigned char num_2_char(unsigned char num) +{ + if (num >= 0 && num <= 9) { + return '0' + num; + } else + return 'a' + (num - 0x0a); +} + +void num_2_str(unsigned char num, unsigned char *str) +{ + *str = num_2_char((num >> 4) & 0x0f); + *(str + 1) = num_2_char(num & 0x0f); +} + +static char *translate_scan(wlan_private * priv, + struct iw_request_info *info, + char *start, char *stop, + struct bss_descriptor *bss_desc) +{ + + struct iw_event iwe; /* Temporary buffer */ + u8 snr; + struct bss_descriptor *bss = bss_desc; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "translate_scan, ssid = %s ssi=%d ssid_len=%d \n", bss->ssid, bss->rssi, bss->ssid_len); + + /* First entry *MUST* be the BSSID */ + iwe.cmd = SIOCGIWAP; + iwe.u.ap_addr.sa_family = ARPHRD_ETHER; + memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN); + start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN); + + /* SSID */ + iwe.cmd = SIOCGIWESSID; + iwe.u.data.flags = 1; + iwe.u.data.length = bss->ssid_len; + start = iwe_stream_add_point(info, start, stop, &iwe, bss->ssid); + + /* Mode */ + iwe.cmd = SIOCGIWMODE; + iwe.u.mode = bss->mode; + start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_UINT_LEN); + + /* Frequency */ + iwe.cmd = SIOCGIWFREQ; + iwe.u.freq.m = (2412 + 5 * (bss->channel - 1)) * 100000; + iwe.u.freq.e = 1; + start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN); + + /* Add quality statistics */ + iwe.cmd = IWEVQUAL; + iwe.u.qual.updated = IW_QUAL_ALL_UPDATED; + iwe.u.qual.level = 0x100 + wlan_get_aver_rssi(priv, bss->bssid); + + snr = iwe.u.qual.level - WLAN_NF_DEFAULT_SCAN_VALUE; + iwe.u.qual.qual = + (100 * RSSI_DIFF * RSSI_DIFF - (PERFECT_RSSI - snr) * + (15 * (RSSI_DIFF) + 62 * (PERFECT_RSSI - snr))) / + (RSSI_DIFF * RSSI_DIFF); + if (iwe.u.qual.qual > 100) + iwe.u.qual.qual = 100; + iwe.u.qual.noise = WLAN_NF_DEFAULT_SCAN_VALUE; + start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN); + + /* Add encryption capability */ + iwe.cmd = SIOCGIWENCODE; + if (bss->capability & WLAN_CAPABILITY_PRIVACY) { + iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; + } else { + iwe.u.data.flags = IW_ENCODE_DISABLED; + } + iwe.u.data.length = 0; + start = iwe_stream_add_point(info, start, stop, &iwe, bss->ssid); + + memset(&iwe, 0, sizeof(iwe)); + if (bss_desc->wpa_ie_len && !bss_desc->wapi_ie_len) { + char buf[MAX_WPA_IE_LEN]; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "translate_scan, wpa_ie, len %d\n", + bss_desc->wpa_ie_len); + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "%02x %02x %02x %02x ... ... %02x %02x %02x %02x\n", + bss_desc->wpa_ie[0], bss_desc->wpa_ie[1], + bss_desc->wpa_ie[2], bss_desc->wpa_ie[3], + bss_desc->wpa_ie[bss_desc->wpa_ie_len - 4], + bss_desc->wpa_ie[bss_desc->wpa_ie_len - 3], + bss_desc->wpa_ie[bss_desc->wpa_ie_len - 2], + bss_desc->wpa_ie[bss_desc->wpa_ie_len - 1]); + + memcpy(buf, bss->wpa_ie, bss->wpa_ie_len); + iwe.cmd = IWEVGENIE; + iwe.u.data.length = bss_desc->wpa_ie_len; + start = iwe_stream_add_point(info, start, stop, &iwe, buf); + } + + memset(&iwe, 0, sizeof(iwe)); + if (bss_desc->rsn_ie_len) { + char buf[MAX_WPA_IE_LEN]; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "translate_scan, rsn_ie, len %d\n", + bss_desc->rsn_ie_len); + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "%02x %02x %02x %02x ... ... %02x %02x %02x %02x\n", + bss_desc->rsn_ie[0], bss_desc->rsn_ie[1], + bss_desc->rsn_ie[2], bss_desc->rsn_ie[3], + bss_desc->rsn_ie[bss_desc->rsn_ie_len - 4], + bss_desc->rsn_ie[bss_desc->rsn_ie_len - 3], + bss_desc->rsn_ie[bss_desc->rsn_ie_len - 2], + bss_desc->rsn_ie[bss_desc->rsn_ie_len - 1]); + + memcpy(buf, bss->rsn_ie, bss->rsn_ie_len); + iwe.cmd = IWEVGENIE; + iwe.u.data.length = bss_desc->rsn_ie_len; + start = iwe_stream_add_point(info, start, stop, &iwe, buf); + } + if(priv->version == WLAN_VERSION_91_E|| priv->version == WLAN_VERSION_91_F){ + /* huanglei add for wps */ + memset(&iwe, 0, sizeof(iwe)); + if (bss_desc->wps_ie_len ) { + char buf[MAX_WPS_IE_LEN]; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "translate_scan, wps_ie, len %d\n", bss_desc->wps_ie_len); + + memcpy(buf, bss->wps_ie, bss->wps_ie_len); + iwe.cmd = IWEVGENIE; + iwe.u.data.length = bss_desc->wps_ie_len; + start = iwe_stream_add_point(info, start, stop, &iwe, buf); + } + } + if (bss_desc->wapi_ie_len) { + char buf[200]; + unsigned char pos = 0; + + memset(&iwe, 0, sizeof(iwe)); + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "translate_scan, wapi_len %d\n", + bss_desc->wapi_ie_len); + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "%02x %02x %02x %02x ... ... %02x %02x %02x %02x\n", + bss_desc->wapi_ie[0], bss_desc->wapi_ie[1], + bss_desc->wapi_ie[2], bss_desc->wapi_ie[3], + bss_desc->wapi_ie[bss_desc->wapi_ie_len - 4], + bss_desc->wapi_ie[bss_desc->wapi_ie_len - 3], + bss_desc->wapi_ie[bss_desc->wapi_ie_len - 2], + bss_desc->wapi_ie[bss_desc->wapi_ie_len - 1]); + + memcpy(buf, "wapi_ie=", 8); + + while (pos < bss_desc->wapi_ie_len) { + //transfer hex to ascii string because wpa_supplicant need do so + num_2_str(bss_desc->wapi_ie[pos], + (unsigned char *)(buf + 8 + 2 * pos)); + pos++; + } + + iwe.cmd = IWEVCUSTOM; + iwe.u.data.length = bss_desc->wapi_ie_len * 2 + 8; + start = iwe_stream_add_point(info, start, stop, &iwe, buf); + } + + return start; +} + +/** + * @brief Handle Scan Network ioctl + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * + * @return 0 --success, otherwise fail + */ +int wlan_set_scan(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + wlan_private *priv = (wlan_private *) netdev_priv(dev); + int ret = 0; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s scan:%d assoc:%d <<< \n", + __func__, priv->scan_running, priv->assoc_ongoing); + + if (!is_sdio_init_complete() || priv->scan_running == WLAN_SCAN_RUNNING + || priv->assoc_ongoing || priv->sdio_need_reset) + goto out; + + if (wrqu->data.length == sizeof(struct iw_scan_req) && + wrqu->data.flags & IW_SCAN_THIS_ESSID) { + struct iw_scan_req *req = (struct iw_scan_req *)extra; + priv->scan_ssid_len = req->essid_len > 32 ? 32 : req->essid_len; + memcpy(priv->scan_ssid, req->essid, priv->scan_ssid_len); + priv->scan_ssid[priv->scan_ssid_len] = '\0'; + } else { + priv->scan_ssid_len = 0; + memset(priv->scan_ssid, '\0', sizeof(priv->scan_ssid)); + } + + wlan_set_rssi_dirty(priv); + priv->scan_running = WLAN_SCAN_RUNNING; + ret = wlan_start_scan_enable_network_info(priv); + if (!ret) { + wlan_mod_timer(&priv->ScanResultsTimeout, 1500); + } else { + priv->scan_running = WLAN_SCAN_IDLE; + } +out: + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s ret %d >>> \n", __func__, ret); + return 0; +} + + +void wlan_set_scan_by_driver(wlan_private *priv) +{ + int ret = 0; + priv->scan_ssid_len = 0; + memset(priv->scan_ssid, '\0', sizeof(priv->scan_ssid)); + priv->scan_running = WLAN_SCAN_RUNNING; + ret = wlan_start_scan_enable_network_info(priv); + if (!ret) { + wlan_mod_timer(&priv->ScanResultsTimeout, 1500); + } else { + priv->scan_running = WLAN_SCAN_IDLE; + } +} + + +static inline unsigned int elapsed_jiffies_msecs(unsigned long start) +{ + unsigned long end = jiffies; + + if (end >= start) + return jiffies_to_msecs(end - start); + + return jiffies_to_msecs(end + (MAX_JIFFY_OFFSET - start) + 1); +} + +/** + * @brief Handle Retrieve scan table ioctl + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param dwrq A pointer to iw_point structure + * @param extra A pointer to extra data buf + * + * @return 0 --success, otherwise fail + */ +int wlan_get_scan(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ +#define SCAN_ITEM_SIZE 128 + wlan_private *priv = (wlan_private *) netdev_priv(dev); + int ret = 0; + struct bss_descriptor *iter_bss; + struct bss_descriptor *safe; + char *ev = extra; + char *stop = ev + dwrq->length; + u8 items = 0; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_DEBUG, "%s >>>\n", __func__); + + /* iwlist should wait until the current scan is finished */ + if (priv->scan_running == WLAN_SCAN_RUNNING) { + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "Scan is Running, return AGAIN\n"); + return -EAGAIN; + } + + spin_lock(&priv->ScanListLock); + /* report all bss to upper layer */ + list_for_each_entry_safe(iter_bss, safe, &priv->network_list, list) { + char *next_ev; + unsigned long stale_time; + + + if (stop - ev < SCAN_ITEM_SIZE) { + ret = -E2BIG; + break; + } + + if (!iter_bss->ssid_len){ + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE,"No valid AP here\n"); + continue; + } + + /* Prune old an old scan result */ + stale_time = iter_bss->last_scanned + DEFAULT_MAX_SCAN_AGE; + if (time_before(stale_time, jiffies)) { + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "Not show %s, due to age (%ums).\n", iter_bss->ssid, + elapsed_jiffies_msecs(iter_bss->last_scanned)); + clear_bss_descriptor(iter_bss); + continue; + } + +#ifdef WIFI_SELECT_CHANNEL + if (iter_bss->channel > channel_nums) { + clear_bss_descriptor(iter_bss); + continue; + } +#endif + /* Translate to WE format this entry */ + next_ev = translate_scan(priv, info, ev, stop, iter_bss); + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "Report BSS %s\n", iter_bss->ssid); + + if (next_ev == NULL) + continue; + ev = next_ev; + items++; + } + spin_unlock(&priv->ScanListLock); + dwrq->length = (ev - extra); + dwrq->flags = 0; + + if (priv->scan_running != WLAN_SCAN_RUNNING) + priv->scan_running = WLAN_SCAN_IDLE; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s ap:%d< <<\n", __func__, items); + return ret; +} + +int wlan_set_mlme(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct iw_mlme *mlme = (struct iw_mlme *)extra; + wlan_private *priv = netdev_priv(dev); + int ret = 0; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + switch (mlme->cmd) { + case IW_MLME_DEAUTH: + case IW_MLME_DISASSOC: + { + unsigned char null_data[6]; + memset(null_data, 0, 6); + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "DISASSOC\n"); + + wlan_cancel_timer(&priv->AssociationTimeOut); + wlan_cancel_timer(&priv->ReAssociationTimeOut); + priv->assoc_ongoing = FALSE; + + /* silently ignore */ + if(priv->version >= WLAN_VERSION_91){ + //wlan_set_bssid(priv, null_data); + //wlan_disconnect(priv); + ret = wlan_disconnect_silent(priv); + } + else + ret = wlan_set_ssid((wlan_private *) netdev_priv(dev), null_data, 6); + + } + break; + default: + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "Not supported cmd %d\n", mlme->cmd); + ret = -EOPNOTSUPP; + break; + } + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return ret; +} + +#define MAX_WX_STRING 80 +static int wl_iw_get_macaddr(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int error; + char *p = extra; + char buf[ETH_ALEN] = { 0 }; + wlan_private *priv = netdev_priv(dev); + + error = wlan_get_mac_addr(priv, buf); + p += snprintf(p, MAX_WX_STRING, + "Macaddr = %02X:%02X:%02X:%02X:%02X:%02X\n", buf[0], + buf[1], buf[2], buf[3], buf[4], buf[5]); + + wrqu->data.length = p - extra + 1; + + return error; +} + +static int wlan_set_priv(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *ext) +{ + int ret = 0; + char *extra; + + if (!(extra = kmalloc(dwrq->length, GFP_KERNEL))) + return -ENOMEM; + + if (copy_from_user(extra, dwrq->pointer, dwrq->length)) { + kfree(extra); + return -EFAULT; + } + + if (dwrq->length && extra) { + if (strnicmp(extra, "MACADDR", strlen("MACADDR")) == 0) { + ret = + wl_iw_get_macaddr(dev, info, + (union iwreq_data *)dwrq, extra); + } else if (strnicmp(extra, "CSCAN", strlen("CSCAN")) == 0) { + } + } + + if (extra) { + if (copy_to_user(dwrq->pointer, extra, dwrq->length)) { + kfree(extra); + return -EFAULT; + } + kfree(extra); + } + + return ret; +} + +static int wlan_wext_get_wireless_stats(struct net_device *dev, + struct iw_request_info *info, + u32 * uwrq, char *extra) +{ + struct iw_statistics *wstats = (struct iw_statistics *)extra; + wlan_private *priv = netdev_priv(dev); + int ret = 0; + int stats_valid = 0; + u8 snr; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + ret = wlan_update_bss_stats(priv); + if (ret) + goto out; + + wstats->miss.beacon = 0; + wstats->discard.retries = 0; + wstats->qual.level = 0x100 + (s8)priv->curbssparams.rssi; + + snr = wstats->qual.level - WLAN_NF_DEFAULT_SCAN_VALUE; + wstats->qual.qual = + (100 * RSSI_DIFF * RSSI_DIFF - (PERFECT_RSSI - snr) * + (15 * (RSSI_DIFF) + 62 * (PERFECT_RSSI - snr))) / + (RSSI_DIFF * RSSI_DIFF); + if (wstats->qual.qual > 100) + wstats->qual.qual = 100; + wstats->qual.noise = WLAN_NF_DEFAULT_SCAN_VALUE; + wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; + + stats_valid = 1; + +out: + if (!stats_valid) { + wstats->miss.beacon = 0; + wstats->discard.retries = 0; + wstats->qual.qual = 0; + wstats->qual.level = 0; + wstats->qual.noise = 0; + wstats->qual.updated = IW_QUAL_ALL_UPDATED; + wstats->qual.updated |= IW_QUAL_NOISE_INVALID | + IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID; + } + return ret; +} + +/* + * iwconfig settable callbacks + */ +static const iw_handler wlan_wext_handler[] = { + (iw_handler) NULL, /* SIOCSIWCOMMIT */ + (iw_handler) wlan_get_name, /* SIOCGIWNAME */ + (iw_handler) NULL, /* SIOCSIWNWID */ + (iw_handler) NULL, /* SIOCGIWNWID */ + (iw_handler) wlan_set_freq, /* SIOCSIWFREQ */ + (iw_handler) wlan_get_freq, /* SIOCGIWFREQ */ + (iw_handler) wlan_set_mode, /* SIOCSIWMODE */ + (iw_handler) wlan_get_mode, /* SIOCGIWMODE */ + (iw_handler) NULL, /* SIOCSIWSENS */ + (iw_handler) NULL, /* SIOCGIWSENS */ + (iw_handler) NULL, /* SIOCSIWRANGE */ + (iw_handler) wlan_get_range, /* SIOCGIWRANGE */ + (iw_handler) wlan_set_priv, /* SIOCSIWPRIV */ + (iw_handler) NULL, /* SIOCGIWPRIV */ + (iw_handler) NULL, /* SIOCSIWSTATS */ + (iw_handler) wlan_wext_get_wireless_stats, /* SIOCGIWSTATS */ + (iw_handler) NULL, /* SIOCSIWSPY */ + (iw_handler) NULL, /* SIOCGIWSPY */ + (iw_handler) NULL, /* SIOCSIWTHRSPY */ + (iw_handler) NULL, /* SIOCGIWTHRSPY */ + (iw_handler) wlan_set_wap, /* SIOCSIWAP */ + (iw_handler) wlan_get_wap, /* SIOCGIWAP */ + (iw_handler) wlan_set_mlme, /* SIOCSIWMLME */ + (iw_handler) NULL, /* SIOCGIWAPLIST - deprecated */ + (iw_handler) wlan_set_scan, /* SIOCSIWSCAN */ + (iw_handler) wlan_get_scan, /* SIOCGIWSCAN */ + (iw_handler) wlan_set_essid, /* SIOCSIWESSID */ + (iw_handler) wlan_get_essid, /* SIOCGIWESSID */ + (iw_handler) wlan_set_nick, /* SIOCSIWNICKN */ + (iw_handler) wlan_get_nick, /* SIOCGIWNICKN */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) wlan_set_rate, /* SIOCSIWRATE */ + (iw_handler) wlan_get_rate, /* SIOCGIWRATE */ + (iw_handler) wlan_set_rts, /* SIOCSIWRTS */ + (iw_handler) wlan_get_rts, /* SIOCGIWRTS */ + (iw_handler) wlan_set_frag, /* SIOCSIWFRAG */ + (iw_handler) wlan_get_frag, /* SIOCGIWFRAG */ + (iw_handler) wlan_set_txpow, /* SIOCSIWTXPOW */ + (iw_handler) wlan_get_txpow, /* SIOCGIWTXPOW */ + (iw_handler) wlan_set_retry, /* SIOCSIWRETRY */ + (iw_handler) wlan_get_retry, /* SIOCGIWRETRY */ + (iw_handler) wlan_set_encode, /* SIOCSIWENCODE */ + (iw_handler) wlan_get_encode, /* SIOCGIWENCODE */ + (iw_handler) wlan_set_power, /* SIOCSIWPOWER */ + (iw_handler) wlan_get_power, /* SIOCGIWPOWER */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) wlan_set_genie, /* SIOCSIWGENIE */ + (iw_handler) wlan_get_genie, /* SIOCGIWGENIE */ + (iw_handler) wlan_set_auth, /* SIOCSIWAUTH */ + (iw_handler) wlan_get_auth, /* SIOCGIWAUTH */ + (iw_handler) wlan_set_encodeext, /* SIOCSIWENCODEEXT */ + (iw_handler) wlan_get_encodeext, /* SIOCGIWENCODEEXT */ + (iw_handler) wlan_set_pmksa, /* SIOCSIWPMKSA */ +}; + +struct iw_handler_def wlan_wext_handler_def = { + .num_standard = ARRAY_SIZE(wlan_wext_handler), + .standard = (iw_handler *) wlan_wext_handler, + .get_wireless_stats = wlan_get_wireless_stats, +}; diff --git a/drivers/net/wireless/rda/rda_wlan/wlan_wid.c b/drivers/net/wireless/rda/rda_wlan/wlan_wid.c new file mode 100755 index 00000000..e653accd --- /dev/null +++ b/drivers/net/wireless/rda/rda_wlan/wlan_wid.c @@ -0,0 +1,1771 @@ +#include "wlan_includes.h" + +void wlan_clean_wid_node(wlan_wid_packet_node * widNode) +{ + if (!widNode) + return; + + if (widNode->Buf) + kfree(widNode->Buf); + + if (widNode->RspBuf) + kfree(widNode->RspBuf); + + widNode->Buf = NULL; + widNode->BufLen = 0; + widNode->RspBuf = NULL; + widNode->RspLen = 0; + widNode->WidWaitOption = FALSE; + widNode->WidCmd = 0; + widNode->WidMsgId = 0; +} + +wlan_wid_packet_node *wlan_get_wid_node_in_freeQ(wlan_private * priv) +{ + wlan_wid_packet_node *widNode = NULL; + + ENTER(); + + if (priv->Suspend || priv->CardRemoved) + return NULL; + + spin_lock(&priv->WidLock); + if (!list_empty(&priv->WidFreeQ)) { + widNode = (wlan_wid_packet_node *) priv->WidFreeQ.next; + list_del(&widNode->List); + } + spin_unlock(&priv->WidLock); + + if (widNode) + wlan_clean_wid_node(widNode); + else + WLAN_ERRP("no free wid node \n"); + + LEAVE(); + return widNode; +} + +void wlan_put_wid_node_in_freeQ(wlan_private * priv, + wlan_wid_packet_node * widNode) +{ + if (!widNode || priv->CardRemoved) + return; + + ENTER(); + spin_lock(&priv->WidLock); + list_add_tail(&widNode->List, &priv->WidFreeQ); + spin_unlock(&priv->WidLock); + LEAVE(); +} + +int wlan_put_wid_node_in_pendingQ(wlan_private * priv, + wlan_wid_packet_node * widNode) +{ + int ret = 0; + wlan_tx_packet_node *txPacketNode = NULL; + + if (!widNode || priv->CardRemoved) + return -1; + + txPacketNode = (wlan_tx_packet_node *)kzalloc(sizeof(wlan_tx_packet_node), GFP_KERNEL); + if (!txPacketNode) { + WLAN_ERRP("no memory \n"); + return -ENOMEM; + } + + ENTER(); + + txPacketNode->type = WLAN_CMD; + txPacketNode->wid_node = widNode; + + //add to pending queue + widNode->WidWaitOption = FALSE; + + //add to pending queue + spin_lock(&priv->WidLock); + list_add_tail(&widNode->List, &priv->WidPendingQ); + spin_unlock(&priv->WidLock); + + //add to tx queue , send to card + spin_lock(&priv->TxLock); + list_add_tail(&txPacketNode->List, &priv->TxQueue); + spin_unlock(&priv->TxLock); + + complete(&priv->TxThread.comp); + ret = wait_event_timeout(widNode->WidDone, widNode->WidWaitOption, HZ * 5); + if (!ret) { + WLAN_ERRP("wait event timeout \n"); + priv->EventErrorCount++; + } else if (ret == -ERESTARTSYS) { + WLAN_ERRP("wait event was interrupt by signal \n"); + priv->EventErrorCount++; + } else { + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_TRACE, "wlan_put_wid_node_in_pendingQ received event success!! \n"); + priv->EventErrorCount=0; + } + + //delete from pending queue do not add to freeQ now because we should get wid response + spin_lock(&priv->WidLock); + widNode->BufLen = 0; + list_del(&widNode->List); + spin_unlock(&priv->WidLock); + +#ifdef CHECK_SDIO_STAUTS + if (!rda_combo_wifi_in_test_mode() && is_sdio_init_complete() && priv->EventErrorCount > WLAN_EVENT_MAX_ERR) { + WLAN_ERRP("Wait event timeout, push event : WLAN_EVENT_CHECK_SDIO \n"); + wlan_push_event(priv, WLAN_EVENT_CHECK_SDIO, priv, FALSE); + priv->EventErrorCount = 0; + priv->sdio_need_reset = 1; + } +#endif + + if (ret > 0) + ret = 0; + else if (!ret) + ret = -1; + + LEAVE(); + + return ret; +} + +//do not del wid node in this, after wid complete it will be delete +wlan_wid_packet_node *wlan_get_wid_node_in_pendingQ(wlan_private * priv) +{ + wlan_wid_packet_node *widNode = NULL; + + if (priv->Suspend || priv->CardRemoved) + return NULL; + + spin_lock(&priv->WidLock); + if (!list_empty(&priv->WidPendingQ)) { + widNode = (wlan_wid_packet_node *) priv->WidPendingQ.next; + } + spin_unlock(&priv->WidLock); + if (!widNode) + WLAN_ERRP("no wid pendingQ \n"); + return widNode; +} + +int wlan_alloc_wid_queue(wlan_private * priv) +{ + int ret = -1; + u32 i = 0; + wlan_wid_packet_node *widNode; + + for (i = 0; i < WLAN_CMD_QUEUE_NUM; i++) { + widNode = kzalloc(sizeof(wlan_wid_packet_node), GFP_KERNEL); + if (widNode) { + init_waitqueue_head(&widNode->WidDone); + spin_lock(&priv->WidLock); + list_add_tail(&widNode->List, &priv->WidFreeQ); + spin_unlock(&priv->WidLock); + ret = 0; + } else { + WLAN_ERRP("kzalloc wlan_wid_packet_node memory failed!\n"); + ret =-1; + break; + } + } + return ret; +} + +int wlan_release_wid_pending_queue(wlan_private * priv) +{ + wlan_wid_packet_node *widNode; + struct list_head *qe, *qen; + ENTER(); + + spin_lock(&priv->WidLock); + if (!list_empty(&priv->WidPendingQ)) { + list_for_each_safe(qe, qen, &priv->WidPendingQ) { + widNode = (wlan_wid_packet_node *) qe; + list_del(&widNode->List); + + wake_up(&widNode->WidDone); + } + } + spin_unlock(&priv->WidLock); + LEAVE(); + return 0; +} + +int wlan_free_wid_queue(wlan_private * priv) +{ + struct list_head *qe = NULL, *qen = NULL; + wlan_wid_packet_node *widNode; + + ENTER(); + + spin_lock(&priv->WidLock); + if (!list_empty(&priv->WidFreeQ)) { + list_for_each_safe(qe, qen, &priv->WidFreeQ) { + widNode = (wlan_wid_packet_node *) qe; + list_del(&widNode->List); + + if (widNode->Buf) + kfree(widNode->Buf); + widNode->Buf = NULL; + + if (widNode->RspBuf) + kfree(widNode->RspBuf); + widNode->RspBuf = NULL; + + kfree(widNode); + } + } + spin_unlock(&priv->WidLock); + LEAVE(); + return 0; +} + +int wlan_read_wid_rsp_polling(wlan_private * priv) +{ + u8 status; + int ret = 0; + u8 size_l = 0, size_h = 0; + u16 size = 0, rx_len = 0; + struct sk_buff *skb = NULL; + s16 count = 1000; + u8 *payload = NULL, rx_type = 0, msg_type = 0; + wlan_sdio_card *card = (wlan_sdio_card *) priv->card; + + ENTER(); + while (!is_sdio_init_complete() && !priv->CardRemoved && count--) { + sdio_claim_host(card->func); + ret = wlan_read_byte(priv, IF_SDIO_FUN1_INT_STAT, &status); + if (!ret) { + if (status & IF_SDIO_INT_AHB2SDIO) { + ret = wlan_read_byte(priv, IF_SDIO_AHB2SDIO_PKTLEN_L, &size_l); + if (ret) { + sdio_release_host(card->func); + break; + } + + ret = wlan_read_byte(priv, IF_SDIO_AHB2SDIO_PKTLEN_H, &size_h); + if (ret) { + sdio_release_host(card->func); + break; + } + + size = (size_l | ((size_h & 0x7f) << 8)) * 4; + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_NORM, "size = %d \n", size); + + skb = dev_alloc_skb(size + NET_IP_ALIGN + 3); + if (!skb) { + sdio_release_host(card->func); + ret = -1; + break; + } + + skb_reserve(skb, NET_IP_ALIGN); + skb_align(skb, 4); + + if (wlan_read_bytes(priv, IF_SDIO_FUN1_FIFO_RD, skb->data, size) + || priv->CardRemoved) { + dev_kfree_skb(skb); + sdio_release_host(card->func); + ret = -1; + goto out; + } + sdio_release_host(card->func); + skb_put(skb, size); + + payload = skb->data; + + rx_type = payload[1] & 0xf0; + rx_len = (u16) (payload[0] + ((payload[1] & 0x0f) << 8)); + if (rx_type == HOST_MSG_CONFIGRSP) { + msg_type = payload[2]; + if (msg_type == 'R') { + wlan_wid_response(priv, payload + 2, rx_len - 2); + dev_kfree_skb(skb); + ret = 0; + break; + } else if (msg_type == 'I') { + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_NORM, "received a mac status \n"); + } + } + dev_kfree_skb(skb); + } else + sdio_release_host(card->func); + } else + sdio_release_host(card->func); + udelay(10); + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_NORM, "IF_SDIO_FUN1_INT_STAT count:%d stats:0x%x\n", count, status); + } + + if (count < 0) { + ret = -1; + WLAN_ERRP("polling wid rsp failed \n"); + } else { + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_NORM, "polling wid rsp success \n"); + } + +out: + LEAVE(); + return ret; +} + +//return 0 success +int wlan_generic_get(wlan_private * priv, + u16 wid, u8 * val, u16 val_len, u32 * rspLen, + WID_TYPE_T type) +{ + int ret; + u8 wid_msg_id; + wlan_wid_packet_node *widNode = NULL; + u8 *wid_req = NULL; + u8 wid_req_len = 6; + + ENTER(); + + if(priv->sdio_need_reset == 1) + return -ENOMEM; + + widNode = wlan_get_wid_node_in_freeQ(priv); + + if (!widNode) + return -ENOMEM; + + wid_msg_id = priv->wid_msg_id++; + + widNode->Buf = kmalloc(wid_req_len + WID_HEADER_LEN, GFP_KERNEL); + widNode->BufLen = wid_req_len; + + widNode->RspBuf = kmalloc(val_len, GFP_KERNEL); + widNode->RspLen = val_len; + widNode->WidMsgId = wid_msg_id; + widNode->WidCmd = wid; + widNode->BufType = type; + + wid_req = widNode->Buf + WID_HEADER_LEN; + + wid_req[0] = 'Q'; + wid_req[1] = wid_msg_id; + + wid_req[2] = (char)(wid_req_len & 0x00FF); + wid_req[3] = (char)((wid_req_len & 0xFF00) >> 8); + + wid_req[4] = (char)(wid & 0x00FF); + wid_req[5] = (char)((wid & 0xFF00) >> 8); + + ret = wlan_put_wid_node_in_pendingQ(priv, widNode); + + if (!ret) { + memcpy(val, widNode->RspBuf, widNode->RspLen); + if (rspLen) + *rspLen = widNode->RspLen; + } + + wlan_put_wid_node_in_freeQ(priv, widNode); + LEAVE(); + return ret; +} + +int wlan_generic_get_uchar(wlan_private * priv, u16 wid, u8 * val) +{ + int ret; + ENTER(); + + ret = wlan_generic_get(priv, wid, val, 1, NULL, WID_CHAR); + + LEAVE(); + return ret; +} + +int wlan_generic_get_ushort(wlan_private * priv, u16 wid, u8 * val) +{ + int ret; + ENTER(); + + ret = wlan_generic_get(priv, wid, val, 2, NULL, WID_SHORT); + + LEAVE(); + return ret; +} + +int wlan_generic_get_ulong(wlan_private * priv, u16 wid, u8 * val) +{ + int ret; + ENTER(); + + ret = wlan_generic_get(priv, wid, (u8 *) val, 4, NULL, WID_INT); + + LEAVE(); + return ret; +} + +int wlan_generic_get_str(wlan_private * priv, + u16 wid, u8 * val, u32 len, u32 * rspLen) +{ + int ret; + ENTER(); + + ret = wlan_generic_get(priv, wid, val, len, rspLen, WID_STR); + + LEAVE(); + return ret; +} + +//return 0 success +int wlan_send_wid_packet(wlan_private * priv, u8 * val, u16 val_len, + u8 wid_msg_id) +{ + int ret = 0; + wlan_wid_packet_node *widNode = NULL; + u8 *wid_req = NULL; + u16 wid_req_len = val_len; + + ENTER(); + + if(priv->sdio_need_reset == 1) + return -ENOMEM; + + widNode = wlan_get_wid_node_in_freeQ(priv); + if (!widNode) + return -ENOMEM; + + widNode->Buf = kmalloc(wid_req_len + WID_HEADER_LEN, GFP_KERNEL); + widNode->BufLen = wid_req_len; + + widNode->RspBuf = kmalloc(4, GFP_KERNEL); + widNode->RspLen = 4; + widNode->WidMsgId = wid_msg_id; + widNode->WidCmd = WID_STATUS; + widNode->BufType = WID_STR; + + wid_req = widNode->Buf + WID_HEADER_LEN; + memcpy(wid_req, val, val_len); + + ret = wlan_put_wid_node_in_pendingQ(priv, widNode); + //check wid status + if (!ret) { + if (widNode->RspBuf[0] != WID_STATUS_SUCCESS) + ret = -EINVAL; + } + + wlan_put_wid_node_in_freeQ(priv, widNode); + LEAVE(); + return ret; +} + +int wlan_generic_set(wlan_private * priv, + u16 wid, u8 * val, u16 val_len, WID_TYPE_T type) +{ + int ret; + u8 wid_msg_id; + wlan_wid_packet_node *widNode = NULL; + u8 *wid_req = NULL; + u8 wid_req_len = 7 + val_len; + + ENTER(); + + if(priv->sdio_need_reset == 1) + return -ENOMEM; + + widNode = wlan_get_wid_node_in_freeQ(priv); + if (!widNode) + return -ENOMEM; + + wid_msg_id = priv->wid_msg_id++; + + if(type == WID_BIN_DATA) + wid_req_len += 2; //1for length feild, 1 for crc + + widNode->Buf = kmalloc(wid_req_len + WID_HEADER_LEN, GFP_KERNEL); + widNode->BufLen = wid_req_len; + + widNode->RspBuf = kmalloc(4, GFP_KERNEL); + widNode->RspLen = 4; + widNode->WidMsgId = wid_msg_id; + widNode->WidCmd = wid; + widNode->BufType = type; + + wid_req = widNode->Buf + WID_HEADER_LEN; + + wid_req[0] = 'W'; + wid_req[1] = wid_msg_id; + + wid_req[2] = (char)(wid_req_len & 0x00FF); + wid_req[3] = (char)((wid_req_len & 0xFF00) >> 8); + + wid_req[4] = (char)(wid & 0x00FF); + wid_req[5] = (char)((wid & 0xFF00) >> 8); + + if(type != WID_BIN_DATA){ + wid_req[6] = val_len; + memcpy(&wid_req[7], val, val_len); + }else{ + wid_req[6] = val_len & 0xff; + wid_req[7] = (val_len & 0xff00) >> 8; + memcpy(&wid_req[8], val, val_len); + } + + ret = wlan_put_wid_node_in_pendingQ(priv, widNode); + //check wid status + if (!ret) { + if (widNode->RspBuf[0] != WID_STATUS_SUCCESS) + ret = -EINVAL; + } + + wlan_put_wid_node_in_freeQ(priv, widNode); + LEAVE(); + return ret; +} + +int wlan_generic_set_uchar(wlan_private * priv, u16 wid, u8 val) +{ + int ret; + u8 tPara = val; + ENTER(); + + ret = wlan_generic_set(priv, wid, &tPara, 1, WID_CHAR); + + LEAVE(); + return ret; +} + +int wlan_generic_set_ushort(wlan_private * priv, u16 wid, u16 val) +{ + int ret; + u16 tPara = val; + ENTER(); + + ret = wlan_generic_set(priv, wid, (u8 *) & tPara, 2, WID_SHORT); + + LEAVE(); + return ret; +} + +int wlan_generic_set_ulong(wlan_private * priv, u16 wid, u32 val) +{ + int ret; + u32 tPara = val; + ENTER(); + + ret = wlan_generic_set(priv, wid, (u8 *) & tPara, 4, WID_INT); + + LEAVE(); + return ret; +} + +int wlan_generic_set_str(wlan_private * priv, u16 wid, u8 * val, u32 val_len) +{ + int ret; + ENTER(); + + ret = wlan_generic_set(priv, wid, val, val_len, WID_STR); + + LEAVE(); + return ret; +} + +int wlan_generic_set_bin(wlan_private * priv, u16 wid, u8 * val, u32 val_len) +{ + int ret; + ENTER(); + + ret = wlan_generic_set(priv, wid, val, val_len, WID_BIN_DATA); + + LEAVE(); + return ret; +} + +int wlan_set_core_init_patch(wlan_private * priv, const u32(*data)[2], u8 num) +{ + int ret, count = 0; + u8 wid_msg_id; + wlan_wid_packet_node *widNode = NULL; + u8 *wid_req = NULL, *p_wid_req; + u8 wid_req_len = 4 + 14 * num; + u16 wid = WID_STATUS; + + ENTER(); + + widNode = wlan_get_wid_node_in_freeQ(priv); + + if (!widNode) + return -ENOMEM; + + wid_msg_id = priv->wid_msg_id++; + + widNode->Buf = kmalloc(wid_req_len + WID_HEADER_LEN + 4, GFP_KERNEL); + widNode->BufLen = wid_req_len; + + widNode->RspBuf = kmalloc(4, GFP_KERNEL); + widNode->RspLen = 4; + widNode->WidMsgId = wid_msg_id; + widNode->WidCmd = wid; + widNode->BufType = WID_STR; + wid_req = widNode->Buf + WID_HEADER_LEN; + + wid_req[0] = 'W'; + wid_req[1] = wid_msg_id; + + wid_req[2] = (char)(wid_req_len & 0x00FF); + wid_req[3] = (char)((wid_req_len & 0xFF00) >> 8); + + p_wid_req = wid_req + 4; + for (count = 0; count < num; count++) { + wid = WID_MEMORY_ADDRESS; + p_wid_req[0] = (char)(wid & 0x00FF); + p_wid_req[1] = (char)((wid & 0xFF00) >> 8); + + p_wid_req[2] = (char)4; + memcpy((u8 *) (p_wid_req + 3), (u8 *) (&data[count][0]), 4); + + wid = WID_MEMORY_ACCESS_32BIT; + p_wid_req[7] = (char)(wid & 0x00FF); + p_wid_req[8] = (char)((wid & 0xFF00) >> 8); + + p_wid_req[9] = (char)4; + memcpy((u8 *) (p_wid_req + 10), (u8 *) (&data[count][1]), 4); + p_wid_req += 14; + } + ret = wlan_put_wid_node_in_pendingQ(priv, widNode); + //check wid status + if (!ret) { + if (widNode->RspBuf[0] != WID_STATUS_SUCCESS) + ret = -EINVAL; + } + + wlan_put_wid_node_in_freeQ(priv, widNode); + + LEAVE(); + return ret; +} + +int wlan_set_core_patch(wlan_private * priv, const u8(*patch)[2], u8 num) +{ + int ret, count = 0; + u8 wid_msg_id; + wlan_wid_packet_node *widNode = NULL; + u8 *wid_req = NULL, *p_wid_req; + u8 wid_req_len = 4 + 8 * num; + u16 wid = WID_STATUS; + + ENTER(); + + widNode = wlan_get_wid_node_in_freeQ(priv); + + if (!widNode) + return -ENOMEM; + + wid_msg_id = priv->wid_msg_id++; + + widNode->Buf = kmalloc(wid_req_len + WID_HEADER_LEN + 4, GFP_KERNEL); + widNode->BufLen = wid_req_len; + + widNode->RspBuf = kmalloc(4, GFP_KERNEL); + widNode->RspLen = 4; + widNode->WidMsgId = wid_msg_id; + widNode->WidCmd = wid; + widNode->BufType = WID_STR; + wid_req = widNode->Buf + WID_HEADER_LEN; + + wid_req[0] = 'W'; + wid_req[1] = wid_msg_id; + + wid_req[2] = (char)(wid_req_len & 0x00FF); + wid_req[3] = (char)((wid_req_len & 0xFF00) >> 8); + + p_wid_req = wid_req + 4; + + for (count = 0; count < num; count++) { + wid = WID_PHY_ACTIVE_REG; + p_wid_req[0] = (char)(wid & 0x00FF); + p_wid_req[1] = (char)((wid & 0xFF00) >> 8); + + p_wid_req[2] = (char)(0x01); + p_wid_req[3] = (char)patch[count][0]; + + wid = WID_PHY_ACTIVE_REG_VAL; + p_wid_req[4] = (char)(wid & 0x00FF); + p_wid_req[5] = (char)((wid & 0xFF00) >> 8); + + p_wid_req[6] = (char)(0x01); + p_wid_req[7] = (char)patch[count][1]; + p_wid_req += 8; + } + ret = wlan_put_wid_node_in_pendingQ(priv, widNode); + //check wid status + if (!ret) { + if (widNode->RspBuf[0] != WID_STATUS_SUCCESS) + ret = -EINVAL; + } + + wlan_put_wid_node_in_freeQ(priv, widNode); + + LEAVE(); + return ret; +} + +void wlan_wid_response(wlan_private * priv, u8 * wid_rsp, u16 wid_rsp_len) +{ + u16 rsp_len; + u16 rsp_wid; + u8 msg_id = 0; + u8 *payload = NULL, payload_len = 0; + struct list_head *qe, *qen; + wlan_wid_packet_node *widNode = NULL; + + if (wid_rsp[0] != 'R') { + WLAN_ERRP("wid_rsp[0] != 'R'\n"); + goto err; + } + + if (wid_rsp_len < 4) { + WLAN_ERRP("wid_rsp_len < 4\n"); + goto err; + } + + rsp_len = wid_rsp[2] | (wid_rsp[3] << 8); + if (wid_rsp_len != rsp_len) { + WLAN_ERRP("wid_rsp_len not match, %d != %d\n", wid_rsp_len, rsp_len); + goto err; + } + + if (wid_rsp_len < 7) { + WLAN_ERRP("wid_rsp_len < 7\n"); + goto err; + } + + msg_id = wid_rsp[1]; + rsp_wid = wid_rsp[4] | (wid_rsp[5] << 8); + payload_len = wid_rsp[6]; + payload = &wid_rsp[7]; + + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_DEBUG,"msg_id:%d rsp_wid:%d \n", msg_id, rsp_wid); + spin_lock(&priv->WidLock); + list_for_each_safe(qe, qen, &priv->WidPendingQ) { + widNode = (wlan_wid_packet_node *) qe; + //process wid write + if (rsp_wid == WID_STATUS) { + if (widNode->WidMsgId == msg_id) { + payload_len = widNode->RspLen > payload_len ? payload_len : widNode->RspLen; + memcpy(widNode->RspBuf, payload, payload_len); + widNode->WidWaitOption = TRUE; + wake_up(&widNode->WidDone); + if (is_sdio_init_complete()) + complete(&priv->widComp); + } + } else { //process wid query + if (widNode->WidMsgId == msg_id) { + rsp_len = widNode->BufLen > payload_len ? payload_len : widNode->BufLen; + memcpy(widNode->RspBuf, payload, rsp_len); + widNode->WidWaitOption = TRUE; + widNode->RspLen = (u32) rsp_len; + wake_up(&widNode->WidDone); + if (is_sdio_init_complete()) + complete(&priv->widComp); + } + } + } + spin_unlock(&priv->WidLock); + +err: + + return; +} + +int wlan_set_scan_timeout(wlan_private * priv) +{ + int ret; + char wid_req[24]; + u16 wid_req_len = 19; + u8 wid_msg_id = priv->wid_msg_id++; + u16 wid = 0; + + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_TRACE, "wlan_set_scan_timeout <<< \n"); + + wid = WID_SITE_SURVEY_SCAN_TIME; + + wid_req[0] = 'W'; + wid_req[1] = wid_msg_id; + + wid_req[2] = (char)(wid_req_len & 0x00FF); + wid_req[3] = (char)((wid_req_len & 0xFF00) >> 8); + + wid_req[4] = (char)(wid & 0x00FF); + wid_req[5] = (char)((wid & 0xFF00) >> 8); + wid_req[6] = 2; + wid_req[7] = SCAN_TIME_AT_EACH_CHANNEL; //50 ms one channel + wid_req[8] = 0; + + wid = WID_ACTIVE_SCAN_TIME; + wid_req[9] = (char)(wid & 0x00FF); + wid_req[10] = (char)((wid & 0xFF00) >> 8); + wid_req[11] = 2; + wid_req[12] = SCAN_TIME_AT_EACH_CHANNEL; //50 ms one channel + wid_req[13] = 0; + + wid = WID_PASSIVE_SCAN_TIME; + wid_req[14] = (char)(wid & 0x00FF); + wid_req[15] = (char)((wid & 0xFF00) >> 8); + wid_req[16] = 2; + wid_req[17] = SCAN_TIME_AT_EACH_CHANNEL; //50 ms one channel + wid_req[18] = 0; + + ret = wlan_send_wid_packet(priv, wid_req, wid_req_len, wid_msg_id); + + return ret; +} + +int wlan_start_scan_enable_network_info(wlan_private * priv) +{ + int ret; + char wid_req[255], *pWid_req; + u16 wid_req_len = 16; + u16 wid; + u8 wid_msg_id = 0; + ENTER(); + + wid_msg_id = priv->wid_msg_id++; + + wid_req[0] = 'W'; + wid_req[1] = wid_msg_id; + + wid_req[2] = (char)(wid_req_len & 0x00FF); + wid_req[3] = (char)((wid_req_len & 0xFF00) >> 8); + + wid = WID_SITE_SURVEY; + wid_req[4] = (char)(wid & 0x00FF); + wid_req[5] = (char)((wid & 0xFF00) >> 8); + + wid_req[6] = (char)(0x01); + wid_req[7] = (char)(0x01); + + wid = WID_START_SCAN_REQ; + wid_req[8] = (char)(wid & 0x00FF); + wid_req[9] = (char)((wid & 0xFF00) >> 8); + + wid_req[10] = (char)(0x01); + wid_req[11] = (char)(0x01); + + wid = WID_NETWORK_INFO_EN; + wid_req[12] = (char)(wid & 0x00FF); + wid_req[13] = (char)((wid & 0xFF00) >> 8); + + wid_req[14] = (char)(0x01); + wid_req[15] = (char)(0x01); // 0x01 scan network info + + wid_req_len = 16; + + if (priv->version == WLAN_VERSION_90_D || priv->version == WLAN_VERSION_90_E) { + int i = 0; + wid_req_len = wid_req_len; + pWid_req = &wid_req[wid_req_len]; + + while (i <= priv->scan_ssid_len) { + wid = WID_MEMORY_ADDRESS; + pWid_req[0] = (char)(wid & 0x00FF); + pWid_req[1] = (char)((wid & 0xFF00) >> 8); + pWid_req[2] = 4; + pWid_req[3] = 0x80 + i; + pWid_req[4] = 0x81; + pWid_req[5] = 0x10; + pWid_req[6] = 0x00; + wid_req_len += 7; + pWid_req += 7; + + wid = WID_MEMORY_ACCESS_32BIT; + pWid_req[0] = (char)(wid & 0x00FF); + pWid_req[1] = (char)((wid & 0xFF00) >> 8); + pWid_req[2] = 4; + pWid_req[3] = priv->scan_ssid[i + 0]; + pWid_req[4] = priv->scan_ssid[i + 1]; + pWid_req[5] = priv->scan_ssid[i + 2]; + pWid_req[6] = priv->scan_ssid[i + 3]; + wid_req_len += 7; + pWid_req += 7; + i += 4; + } + } else if (priv->version == WLAN_VERSION_91 || priv->version == WLAN_VERSION_91_E|| priv->version == WLAN_VERSION_91_F) { + pWid_req = &wid_req[wid_req_len]; + wid = WID_HIDE_SSID; + pWid_req[0] = (char)(wid & 0x00FF); + pWid_req[1] = (char)((wid & 0xFF00) >> 8); + pWid_req[2] = priv->scan_ssid_len; + memcpy(pWid_req + 3, priv->scan_ssid, priv->scan_ssid_len); + wid_req_len += 3 + priv->scan_ssid_len; + pWid_req += 3 + priv->scan_ssid_len; + } + + wid_req[2] = (char)(wid_req_len & 0x00FF); + wid_req[3] = (char)((wid_req_len & 0xFF00) >> 8); + + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_DEBUG, + "wid_req_len : %d ssid_len:%d \n", wid_req_len, + priv->scan_ssid_len); + + ret = wlan_send_wid_packet(priv, wid_req, wid_req_len, wid_msg_id); + if (ret) { + WLAN_ERRP("wlan_send_wid_packet failed!\n"); + } + LEAVE(); + return ret; +} + +int wlan_start_join(wlan_private * priv) +{ + int ret = 0; + char wid_req[255]; + u16 wid_req_len = 0; + u16 wid = 0; + u8 wid_msg_id = priv->wid_msg_id++; + u16 i = 0; + u8 key_str_len = 0; + u8 key_str[26 + 1], *key, *pWid_req; + + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_DEBUG, + "%s <<< mode:0x%x authtype:%d ssid:%s\n", __func__, + priv->imode, priv->authtype, priv->assoc_ssid); + + print_mac(priv->assoc_bssid); + + pWid_req = wid_req; + pWid_req[0] = 'W'; + pWid_req[1] = wid_msg_id; + wid_req_len = 4; + pWid_req += 4; + + wid = WID_802_11I_MODE; + pWid_req[0] = (char)(wid & 0x00FF); + pWid_req[1] = (char)((wid & 0xFF00) >> 8); + pWid_req[2] = 1; + if(priv->imode == 0x9 && (priv->version == WLAN_VERSION_91_E|| priv->version == WLAN_VERSION_91_F)){//huanglei add for wps + wid_req[3] = 0x49; + } + else + pWid_req[3] = (priv->imode == 0x05) ? 0x07 : priv->imode; //for wep104 need set imode 0x07 firmware problem + wid_req_len += 4; + pWid_req += 4; + + wid = WID_AUTH_TYPE; + pWid_req[0] = (char)(wid & 0x00FF); + pWid_req[1] = (char)((wid & 0xFF00) >> 8); + pWid_req[2] = 1; + pWid_req[3] = priv->authtype; + wid_req_len += 4; + pWid_req += 4; + + wid = WID_NETWORK_INFO_EN; + pWid_req[0] = (char)(wid & 0x00FF); + pWid_req[1] = (char)((wid & 0xFF00) >> 8); + pWid_req[2] = 1; + pWid_req[3] = 0; + wid_req_len += 4; + pWid_req += 4; + + wid = WID_CURRENT_TX_RATE; + pWid_req[0] = (char)(wid & 0x00FF); + pWid_req[1] = (char)((wid & 0xFF00) >> 8); + pWid_req[2] = 1; + pWid_req[3] = 1; + wid_req_len += 4; + pWid_req += 4; + + if ((priv->version == WLAN_VERSION_90_D) || (priv->version == WLAN_VERSION_90_E)) { + // bssid + wid = WID_MEMORY_ADDRESS; + pWid_req[0] = (char)(wid & 0x00FF); + pWid_req[1] = (char)((wid & 0xFF00) >> 8); + pWid_req[2] = 4; + pWid_req[3] = 0xec; + pWid_req[4] = 0x81; + pWid_req[5] = 0x10; + pWid_req[6] = 0x00; + wid_req_len += 7; + pWid_req += 7; + + wid = WID_MEMORY_ACCESS_32BIT; + pWid_req[0] = (char)(wid & 0x00FF); + pWid_req[1] = (char)((wid & 0xFF00) >> 8); + pWid_req[2] = 4; + pWid_req[3] = priv->assoc_bssid[0]; + pWid_req[4] = priv->assoc_bssid[1]; + pWid_req[5] = priv->assoc_bssid[2]; + pWid_req[6] = priv->assoc_bssid[3]; + wid_req_len += 7; + pWid_req += 7; + + wid = WID_MEMORY_ADDRESS; + pWid_req[0] = (char)(wid & 0x00FF); + pWid_req[1] = (char)((wid & 0xFF00) >> 8); + pWid_req[2] = 4; + pWid_req[3] = 0xf0; + pWid_req[4] = 0x81; + pWid_req[5] = 0x10; + pWid_req[6] = 0x00; + wid_req_len += 7; + pWid_req += 7; + + wid = WID_MEMORY_ACCESS_32BIT; + pWid_req[0] = (char)(wid & 0x00FF); + pWid_req[1] = (char)((wid & 0xFF00) >> 8); + pWid_req[2] = 4; + pWid_req[3] = priv->assoc_bssid[4]; + pWid_req[4] = priv->assoc_bssid[5]; + pWid_req[5] = 0; + pWid_req[6] = 0; + wid_req_len += 7; + pWid_req += 7; + } + + if ((priv->version == WLAN_VERSION_90_D) || (priv->version == WLAN_VERSION_90_E)) { + //huanglei add begin + wid = WID_MEMORY_ADDRESS; + pWid_req[0] = (char)(wid & 0x00FF); + pWid_req[1] = (char)((wid & 0xFF00) >> 8); + pWid_req[2] = 4; + pWid_req[3] = 0x04; + pWid_req[4] = 0x01; + pWid_req[5] = 0x00; + pWid_req[6] = 0x50; + wid_req_len += 7; + pWid_req += 7; + + wid = WID_MEMORY_ACCESS_16BIT; + pWid_req[0] = (char)(wid & 0x00FF); + pWid_req[1] = (char)((wid & 0xFF00) >> 8); + pWid_req[2] = 2; + pWid_req[3] = 0x1;//(cmax << 4) | (cmin) 00010001 + pWid_req[4] = 0x1; + wid_req_len += 5; + pWid_req += 5; + + wid = WID_MEMORY_ADDRESS; + pWid_req[0] = (char)(wid & 0x00FF); + pWid_req[1] = (char)((wid & 0xFF00) >> 8); + pWid_req[2] = 4; + pWid_req[3] = 0x08; + pWid_req[4] = 0x01; + pWid_req[5] = 0x00; + pWid_req[6] = 0x50; + wid_req_len += 7; + pWid_req += 7; + + wid = WID_MEMORY_ACCESS_16BIT; + pWid_req[0] = (char)(wid & 0x00FF); + pWid_req[1] = (char)((wid & 0xFF00) >> 8); + pWid_req[2] = 2; + pWid_req[3] = 0x1;//(cmax << 4) | (cmin) 00010001 + pWid_req[4] = 0x1; + wid_req_len += 5; + pWid_req += 5; + + wid = WID_MEMORY_ADDRESS; + pWid_req[0] = (char)(wid & 0x00FF); + pWid_req[1] = (char)((wid & 0xFF00) >> 8); + pWid_req[2] = 4; + pWid_req[3] = 0x0C; + pWid_req[4] = 0x01; + pWid_req[5] = 0x00; + pWid_req[6] = 0x50; + wid_req_len += 7; + pWid_req += 7; + + wid = WID_MEMORY_ACCESS_16BIT; + pWid_req[0] = (char)(wid & 0x00FF); + pWid_req[1] = (char)((wid & 0xFF00) >> 8); + pWid_req[2] = 2; + pWid_req[3] = 0x1;//(cmax << 4) | (cmin) 00010001 + pWid_req[4] = 0x1; + wid_req_len += 5; + pWid_req += 5; + + wid = WID_MEMORY_ADDRESS; + pWid_req[0] = (char)(wid & 0x00FF); + pWid_req[1] = (char)((wid & 0xFF00) >> 8); + pWid_req[2] = 4; + pWid_req[3] = 0x10; + pWid_req[4] = 0x01; + pWid_req[5] = 0x00; + pWid_req[6] = 0x50; + wid_req_len += 7; + pWid_req += 7; + + wid = WID_MEMORY_ACCESS_16BIT; + pWid_req[0] = (char)(wid & 0x00FF); + pWid_req[1] = (char)((wid & 0xFF00) >> 8); + pWid_req[2] = 2; + pWid_req[3] = 0x1;//(cmax << 4) | (cmin) 00010001 + pWid_req[4] = 0x1; + wid_req_len += 5; + pWid_req += 5; + //huanglei add end + } + + //bssid + wid = WID_BSSID; + pWid_req[0] = (char)(wid & 0x00FF); + pWid_req[1] = (char)((wid & 0xFF00) >> 8); + pWid_req[2] = 6; + memcpy(&pWid_req[3], priv->assoc_bssid, 6); + wid_req_len += 9; + pWid_req += 9; + + // ssid + wid = WID_SSID; + pWid_req[0] = (char)(wid & 0x00FF); + pWid_req[1] = (char)((wid & 0xFF00) >> 8); + pWid_req[2] = priv->assoc_ssid_len; + memcpy(pWid_req + 3, priv->assoc_ssid, priv->assoc_ssid_len); + wid_req_len += 3 + priv->assoc_ssid_len; + pWid_req += 3 + priv->assoc_ssid_len; + + wid = WID_START_SCAN_REQ; + pWid_req[0] = (char)(wid & 0x00FF); + pWid_req[1] = (char)((wid & 0xFF00) >> 8); + pWid_req[2] = 1; + pWid_req[3] = 0; + wid_req_len += 4; + pWid_req += 4; + + + wid = WID_WEP_KEY_VALUE0; + //write wep key + if (priv->imode == 3 || priv->imode == 5) { + for (i = 0; i < 4; i++) { + key = priv->wep_keys[i].key; + + if (priv->wep_keys[i].len == 0) + continue; + + if (priv->wep_keys[i].len == KEY_LEN_WEP_40) { + sprintf(key_str, "%02x%02x%02x%02x%02x\n", + key[0], key[1], key[2], key[3], key[4]); + key_str_len = 10; + key_str[key_str_len] = '\0'; + } else if (priv->wep_keys[i].len == KEY_LEN_WEP_104) { + sprintf(key_str, "%02x%02x%02x%02x%02x" + "%02x%02x%02x%02x%02x" + "%02x%02x%02x\n", + key[0], key[1], key[2], key[3], key[4], + key[5], key[6], key[7], key[8], key[9], + key[10], key[11], key[12]); + key_str_len = 26; + key_str[key_str_len] = '\0'; + } else + continue; + + pWid_req[0] = (char)((wid + i) & 0x00FF); + pWid_req[1] = (char)(((wid + i) & 0xFF00) >> 8); + + pWid_req[2] = key_str_len; + memcpy(pWid_req + 3, key_str, key_str_len); + + pWid_req += 3 + key_str_len; + wid_req_len += 3 + key_str_len; + } + } + + + + wid_req[2] = (char)(wid_req_len & 0x00FF); + wid_req[3] = (char)((wid_req_len & 0xFF00) >> 8); + + ret = wlan_send_wid_packet(priv, wid_req, wid_req_len, wid_msg_id); + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_DEBUG, + "%s >>> ret = %d req len %d mod:0x%x auth_type:0x%x \n", + __func__, ret, wid_req_len, priv->imode, priv->authtype); + + return ret; +} + +int wlan_disconnect_silent(wlan_private * priv) +{ + int ret = 0; + char null_data[6]; + char wid_req[255], *pWid_req = NULL; + u16 wid_req_len = 0; + u16 wid = 0; + u8 wid_msg_id = priv->wid_msg_id++; + + memset(null_data, 0 , 6); + + wid_req[0] = 'W'; + wid_req[1] = wid_msg_id; + + wid_req_len += 4; + pWid_req = wid_req + 4; + + wid = WID_BSSID; + pWid_req[0] = (char)(wid&0x00FF); + pWid_req[1] = (char)((wid&0xFF00) >> 8); + pWid_req[2] = 6; + memcpy(&pWid_req[3], null_data, 6); + wid_req_len += 9; + pWid_req += 9; + + wid = WID_SSID; + pWid_req[0] = (char)(wid&0x00FF); + pWid_req[1] = (char)((wid&0xFF00) >> 8); + pWid_req[2] = 6; + memcpy(&pWid_req[3], null_data, 6); + wid_req_len += 9; + pWid_req += 9; + + wid_req[2] = (char)(wid_req_len&0x00FF); + wid_req[3] = (char)((wid_req_len&0xFF00) >> 8); + + ret = wlan_send_wid_packet(priv, wid_req, wid_req_len, wid_msg_id); + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_DEBUG, "%s >>> ret = %d \n", __func__, ret); + return ret; +} + +int wlan_set_txrate(wlan_private * priv, u8 mbps) +{ + int ret; + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_TRACE, "wlan_set_txrate <<< \n"); + ret = wlan_generic_set_uchar(priv, WID_CURRENT_TX_RATE, mbps); //O FOR AUTO 1FOR 1MBPS + + if ((priv->version == WLAN_VERSION_90_D) || (priv->version == WLAN_VERSION_90_E)) { + //huanglei add begin + ret = wlan_generic_set_ulong(priv, WID_MEMORY_ADDRESS, 0x50000104); + ret = wlan_generic_set_ushort(priv, WID_MEMORY_ACCESS_16BIT, 0x0101); + ret = wlan_generic_set_ulong(priv, WID_MEMORY_ADDRESS, 0x50000108); + ret = wlan_generic_set_ushort(priv, WID_MEMORY_ACCESS_16BIT, 0x0101); + ret = wlan_generic_set_ulong(priv, WID_MEMORY_ADDRESS, 0x5000010C); + ret = wlan_generic_set_ushort(priv, WID_MEMORY_ACCESS_16BIT, 0x0101); + ret = wlan_generic_set_ulong(priv, WID_MEMORY_ADDRESS, 0x50000110); + ret = wlan_generic_set_ushort(priv, WID_MEMORY_ACCESS_16BIT, 0x0101); + //huanglei add end + } + + if (ret) { + WLAN_ERRP("failed \n"); + goto out; + } + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_TRACE, + "wlan_set_txrate success >>> \n"); + +out: + return ret; +} + +int wlan_get_fw_ver(wlan_private * priv, u32 * fw_ver) +{ + int ret = wlan_generic_get_ulong(priv, WID_SYS_FW_VER, (u8 *) fw_ver); + + if (ret) { + WLAN_ERRP("failed \n"); + goto out; + } + + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_TRACE, "Get FW_VER 0x%04x\n", *fw_ver); +out: + return ret; +} + +int wlan_get_mac_addr(wlan_private * priv, u8 * mac_addr) +{ + int ret = wlan_generic_get_str(priv, WID_MAC_ADDR, mac_addr, ETH_ALEN, NULL); + + if (ret) { + WLAN_ERRP("failed \n"); + goto out; + } + + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_TRACE, + "STA MAC Address [%02x:%02x:%02x:%02x:%02x:%02x]\n", + mac_addr[0], mac_addr[1], mac_addr[2], + mac_addr[3], mac_addr[4], mac_addr[5]); +out: + return ret; +} + +int wlan_get_bssid(wlan_private * priv, u8 * bssid) +{ + int ret = 0; + + memcpy(bssid, priv->curbssparams.bssid, ETH_ALEN); + + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_TRACE, + "Get BSSID [%02x:%02x:%02x:%02x:%02x:%02x]\n", + bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]); + + return ret; +} + +int wlan_get_channel(wlan_private * priv, u8 * channel) +{ + int ret; + + ret = wlan_generic_get_uchar(priv, WID_CURRENT_CHANNEL, channel); + if (ret) { + WLAN_ERRP("failed \n"); + goto out; + } + + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_TRACE, "Get Channel %d\n", *channel); +out: + return ret; +} + +int wlan_get_rssi(wlan_private *priv, u8 *rssi) +{ + int ret = 0; + u8 gRssi = 0; + + ret = wlan_generic_get_uchar(priv, WID_RSSI, &gRssi); + if(!ret) + wlan_update_aver_rssi(priv, priv->curbssparams.bssid, gRssi); + + gRssi = (u8)wlan_get_aver_rssi(priv, priv->curbssparams.bssid); + *rssi = gRssi; + return ret; +} + + +int wlan_set_mac_addr(wlan_private * priv, u8 * mac_addr) +{ + int ret; + + ret = wlan_generic_set_str(priv, WID_MAC_ADDR, mac_addr, ETH_ALEN); + if (ret) { + WLAN_ERRP("failed \n"); + goto out; + } + + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_TRACE, + "Set STA MAC Address [%02x:%02x:%02x:%02x:%02x:%02x]\n", + mac_addr[0], mac_addr[1], mac_addr[2], + mac_addr[3], mac_addr[4], mac_addr[5]); +out: + return ret; +} + +int wlan_set_preamble(wlan_private * priv, u8 preamble) +{ + int ret; + + ret = wlan_generic_set_uchar(priv, WID_PREAMBLE, preamble); + if (ret) { + WLAN_ERRP("failed \n"); + goto out; + } + + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_TRACE, "wlan_set_preamble \n"); +out: + return ret; +} + +int wlan_set_scan_complete(wlan_private * priv) +{ + int ret; + + ret = wlan_generic_set_uchar(priv, WID_NETWORK_INFO_EN, 0); + if (ret) { + WLAN_ERRP("failed \n"); + goto out; + } + +out: + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_TRACE, + "wlan_set_scan_complete ret=%d \n", ret); + return ret; +} + +int wlan_set_ssid(wlan_private * priv, u8 * ssid, u8 ssid_len) +{ + int ret; + + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_TRACE, + "Set SSID: %s, len = %d\n", ssid, ssid_len); + + ret = wlan_generic_set_str(priv, WID_SSID, ssid, ssid_len); + if (ret) { + WLAN_ERRP("failed \n"); + goto out; + } + + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_TRACE, "Set SSID Done\n"); + +out: + return ret; +} + +int wlan_get_ssid(wlan_private * priv, u8 * ssid, u8 * ssid_len) +{ + int ret; + u32 len = 0; + + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_TRACE, "Get SSID \n"); + + ret = wlan_generic_get_str(priv, WID_SSID, ssid, 32, &len); + *ssid_len = len; + if (*ssid_len > 0) + ssid[*ssid_len] = '\0'; + + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_TRACE, + "Get SSID Done len:%d %s\n", *ssid_len, + (*ssid_len > 1) ? ssid : (u8 *) "NULL"); + + return ret; +} + +int wlan_set_bssid(wlan_private * priv, u8 * bssid) +{ + int ret; + + ret = wlan_generic_set_str(priv, WID_BSSID, bssid, ETH_ALEN); + if (ret) { + WLAN_ERRP("failed \n"); + goto out; + } + + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_TRACE, + "Set BSSID [%02x:%02x:%02x:%02x:%02x:%02x]\n", + bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]); +out: + return ret; +} + +int wlan_disconnect(wlan_private * priv) +{ + int ret; + + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_TRACE, "wlan_disconnect \n"); + + wlan_remove_tx_data_queue(priv); + ret = wlan_generic_set_uchar(priv, WID_DISCONNECT, 0); + if (ret) { + WLAN_ERRP("failed \n"); + goto out; + } + + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_TRACE, "wlan_disconnect Done\n"); + +out: + return ret; +} + +int wlan_set_imode(wlan_private * priv, u8 imode) +{ + int ret; + + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_TRACE, "Set IMode 0x%02x\n", imode); + + ret = wlan_generic_set_uchar(priv, WID_802_11I_MODE, imode); + if (ret) { + WLAN_ERRP("failed \n"); + goto out; + } + + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_TRACE, "Set IMode Done\n"); + +out: + return ret; +} + +int wlan_set_authtype(wlan_private * priv, u8 authtype) +{ + int ret; + + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_TRACE, + "Set AuthType 0x%02x\n", authtype); + + ret = wlan_generic_set_uchar(priv, WID_AUTH_TYPE, authtype); + if (ret) { + WLAN_ERRP("failed \n"); + goto out; + } + + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_TRACE, "Set AuthType Done\n"); + +out: + return ret; +} + +int wlan_set_listen_interval(wlan_private * priv, u8 interval) +{ + int ret; + + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_TRACE, + "Set wlan_set_listen_interval 0x%02x\n", interval); + + ret = wlan_generic_set_uchar(priv, WID_LISTEN_INTERVAL, interval); + if (ret) { + WLAN_ERRP("failed \n"); + goto out; + } + + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_TRACE, + "Set wlan_set_listen_interval Done\n"); +out: + return ret; +} + +int wlan_set_link_loss_threshold(wlan_private * priv, u8 threshold) +{ + int ret; + + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_TRACE, + "Set wlan_set_link_loss_threshold 0x%02x\n", threshold); + + ret = wlan_generic_set_uchar(priv, WID_LINK_LOSS_THRESHOLD, threshold); + if (ret) { + WLAN_ERRP("failed \n"); + goto out; + } + + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_TRACE, + "Set wlan_set_link_loss_threshold Done\n"); + +out: + return ret; +} + +int wlan_set_power_save(wlan_private * priv) +{ + int ret = 0; + if (priv->version == WLAN_VERSION_91 || priv->version == WLAN_VERSION_91_E|| priv->version == WLAN_VERSION_91_F) { + ret = wlan_generic_set_uchar(priv, WID_POWER_SAVE, 0x30); + if(ret){ + WLAN_ERRP("wlan_generic_set_uchar WID_POWER_SAVE failed! \n"); + } + } + return ret; + +} + +int wlan_set_wepkey(wlan_private * priv, u16 index, u8 * key, u8 key_len) +{ + int ret; + u8 key_str[26 + 1]; // plus 1 for debug print + u8 key_str_len; + + if (key_len == KEY_LEN_WEP_40) { + sprintf(key_str, "%02x%02x%02x%02x%02x\n", + key[0], key[1], key[2], key[3], key[4]); + key_str_len = 10; + key_str[key_str_len] = '\0'; + } else if (key_len == KEY_LEN_WEP_104) { + sprintf(key_str, "%02x%02x%02x%02x%02x" + "%02x%02x%02x%02x%02x" + "%02x%02x%02x\n", + key[0], key[1], key[2], key[3], key[4], + key[5], key[6], key[7], key[8], key[9], + key[10], key[11], key[12]); + key_str_len = 26; + key_str[key_str_len] = '\0'; + } else { + WLAN_ERRP("Error in WEP Key length %d\n", key_len); + ret = -EINVAL; + goto out; + } + + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_TRACE, + "Set WEP KEY[%d]: %s\n", index, key_str); + + ret = wlan_generic_set_str(priv, + (WID_WEP_KEY_VALUE0 + index), key_str, + key_str_len); + if (ret) { + goto out; + } + + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_TRACE, + "Set WEP KEY[%d] Done\n", index); + +out: + return ret; +} + +static void dump_key(u8 * key, u8 key_len) +{ + WLAN_DBGP("%02x %02x %02x %02x %02x %02x %02x %02x\n", + key[0], key[1], key[2], key[3], key[4], key[5], key[6], key[7]); + WLAN_DBGP("%02x %02x %02x %02x %02x %02x %02x %02x\n", + key[8], key[9], key[10], key[11], key[12], key[13], key[14], key[15]); + if (key_len > 16) + WLAN_DBGP("%02x %02x %02x %02x %02x %02x %02x %02x\n", + key[16], key[17], key[18], key[19], key[20], key[21], key[22], key[23]); + if (key_len > 24) + WLAN_DBGP("%02x %02x %02x %02x %02x %02x %02x %02x\n", + key[24], key[25], key[26], key[27], key[28], key[29], key[30], key[31]); +} + +int wlan_set_ptk(wlan_private * priv, u8 * key, u8 key_len) +{ + int ret; + u8 key_str[32 + ETH_ALEN + 1]; + u8 key_str_len = key_len + ETH_ALEN + 1; + + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_TRACE, "Set PTK: len = %d\n", key_len); + + if (WLAN_DBGLA(WLAN_DA_WID, WLAN_DL_VERB)) + dump_key(key, key_len); + + if (priv->connect_status != MAC_CONNECTED) { + WLAN_ERRP("Adding PTK while not connected\n"); + ret = -EINVAL; + goto out; + } + + /*----------------------------------------*/ + /* STA Addr | KeyLength | Key */ + /*----------------------------------------*/ + /* 6 | 1 | KeyLength */ + /*----------------------------------------*/ + + /*---------------------------------------------------------*/ + /* key */ + /*---------------------------------------------------------*/ + /* Temporal Key | Rx Micheal Key | Tx Micheal Key */ + /*---------------------------------------------------------*/ + /* 16 bytes | 8 bytes | 8 bytes */ + /*---------------------------------------------------------*/ + + memcpy(key_str, priv->curbssparams.bssid, ETH_ALEN); + key_str[6] = key_len; + memcpy(key_str + 7, key, 16); + + /* swap TX MIC and RX MIC, wlan need RX MIC to be ahead */ + if (key_len > 16) { + memcpy(key_str + 7 + 16, key + 24, 8); + memcpy(key_str + 7 + 24, key + 16, 8); + } + + if (priv->is_wapi) + ret = wlan_generic_set_str(priv, + WID_ADD_WAPI_PTK, key_str, + key_str_len); + else + ret = wlan_generic_set_str(priv, + WID_ADD_PTK, key_str, key_str_len); + if (ret) { + goto out; + } + + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_TRACE, "Set PTK Done\n"); + +out: + return ret; +} + +int wlan_set_gtk(wlan_private * priv, u8 key_id, + u8 * key_rsc, u8 key_rsc_len, u8 * key, u8 key_len) +{ + int ret; + u8 key_str[32 + ETH_ALEN + 8 + 2]; + u8 key_str_len = key_len + ETH_ALEN + 8 + 2; + + /*---------------------------------------------------------*/ + /* STA Addr | KeyRSC | KeyID | KeyLength | Key */ + /*---------------------------------------------------------*/ + /* 6 | 8 | 1 | 1 | KeyLength */ + /*---------------------------------------------------------*/ + + /*-------------------------------------*/ + /* key */ + /*-------------------------------------*/ + /* Temporal Key | Rx Micheal Key */ + /*-------------------------------------*/ + /* 16 bytes | 8 bytes */ + /*-------------------------------------*/ + + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_TRACE, "Set GTK: len = %d\n", key_len); + if (WLAN_DBGLA(WLAN_DA_WID, WLAN_DL_VERB)) + dump_key(key, key_len); + + if (priv->connect_status != MAC_CONNECTED) { + WLAN_ERRP("Adding GTK while not connected\n"); + ret = -EINVAL; + goto out; + } + + memcpy(key_str, priv->curbssparams.bssid, ETH_ALEN); + memcpy(key_str + 6, key_rsc, key_rsc_len); + key_str[14] = key_id; + key_str[15] = key_len; + memcpy(key_str + 16, key, 16); + + /* swap TX MIC and RX MIC, wlan need RX MIC to be ahead */ + if (key_len > 16) { + //memcpy(key_str + 16 + 16, key + 16, key_len - 16); + memcpy(key_str + 16 + 16, key + 24, 8); + memcpy(key_str + 16 + 24, key + 16, 8); + } + + if (priv->is_wapi) + ret = wlan_generic_set_str(priv, + WID_ADD_WAPI_RX_GTK, key_str, + key_str_len); + else + ret = wlan_generic_set_str(priv, + WID_ADD_RX_GTK, key_str, + key_str_len); + if (ret) { + goto out; + } + + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_TRACE, "Set GTK Done\n"); +out: + return ret; +} + +int wlan_set_pm_mode(wlan_private * priv, u8 pm_mode) +{ + int ret; + + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_TRACE, + "Set PM Mode 0x%02x\n", pm_mode); + + ret = wlan_generic_set_uchar(priv, WID_POWER_MANAGEMENT, pm_mode); + if (ret) { + goto out; + } + + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_TRACE, "Set PM Mode Done\n"); + +out: + return ret; +} + +int wlan_set_preasso_sleep(wlan_private * priv, u32 preasso_sleep) +{ + int ret; + + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_TRACE, + "Set Preasso Sleep 0x%08x\n", preasso_sleep); + + ret = wlan_generic_set_ulong(priv, WID_PREASSO_SLEEP, preasso_sleep); + if (ret) { + WLAN_ERRP("failed \n"); + goto out; + } + + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_TRACE, "Set Preasso Sleep Done\n"); + +out: + return ret; +} + +int rda5890_set_preamble(wlan_private * priv, unsigned char preamble) +{ + int ret; + + ret = wlan_generic_set_uchar(priv, WID_PREAMBLE, preamble); + if (ret) { + goto out; + } + + WLAN_DBGLAP(WLAN_DA_WID, WLAN_DL_TRACE, "rda5890_set_preamble \n"); +out: + return ret; +} + +int wlan_set_pta(wlan_private * priv, struct pta_param_s* param) +{ + int ret; + + ret = wlan_generic_set_bin(priv, WID_PTA_PARAMETER, (u8*)param, sizeof(struct pta_param_s)); + if (ret) { + WLAN_ERRP("set WID_PTA_PARAMETER failed \n"); + } + + return ret; +} diff --git a/drivers/net/wireless/rda/rda_wlan/wlan_wid.h b/drivers/net/wireless/rda/rda_wlan/wlan_wid.h new file mode 100755 index 00000000..2a5bdf7e --- /dev/null +++ b/drivers/net/wireless/rda/rda_wlan/wlan_wid.h @@ -0,0 +1,344 @@ +#ifndef __WLAN_WID_H__ +#define __WLAN_WID_H__ + +#define MAX_STRING_LEN (256) +#define MAX_CMD_LEN (MAX_STRING_LEN) +#define WLAN_MAX_WID_LEN (MAX_CMD_LEN - 2) + +#define MAC_CONNECTED (1) +#define MAC_DISCONNECTED (0) +#define WID_STATUS_SUCCESS (1) + +#define print_mac(x) printk("%x %x %x %x %x %x \n", x[0], x[1], x[2],x[3], x[4], x[5]) + +typedef enum +{ + G_SHORT_PREAMBLE = 0, + G_LONG_PREAMBLE = 1, + G_AUTO_PREAMBLE = 2 +}G_PREAMBLE_T; + + +/* WID Data Types */ +typedef enum { + WID_CHAR = 0, + WID_SHORT = 1, + WID_INT = 2, + WID_STR = 3, + WID_BIN_DATA = 4 +} WID_TYPE_T; + +typedef enum{ + HOST_MSG_DATAOUT = 0x10, /* Receive data from host */ + HOST_MSG_DATAIN = 0x20, /* Transmit data to host */ + HOST_MSG_CONFIGRSP = 0x30, /* Response to host */ + HOST_MSG_CONFIGREQ = 0x40, /* Request from host */ + HOST_MSG_ASYNCEVENT = 0x50 +}HOST_MSG_TYPE; + + +/* WLAN Identifiers */ +typedef enum { + WID_NIL = -1, + WID_BSS_TYPE = 0x0000, + WID_CURRENT_TX_RATE = 0x0001, + WID_CURRENT_CHANNEL = 0x0002, + WID_PREAMBLE = 0x0003, + WID_11G_OPERATING_MODE = 0x0004, + WID_STATUS = 0x0005, + WID_11G_PROT_MECH = 0x0006, + +#ifdef MAC_HW_UNIT_TEST_MODE + WID_GOTO_SLEEP = 0x0007, +#else /* MAC_HW_UNIT_TEST_MODE */ + WID_SCAN_TYPE = 0x0007, +#endif /* MAC_HW_UNIT_TEST_MODE */ + WID_PRIVACY_INVOKED = 0x0008, + WID_KEY_ID = 0x0009, + WID_QOS_ENABLE = 0x000A, + WID_POWER_MANAGEMENT = 0x000B, + WID_802_11I_MODE = 0x000C, + WID_AUTH_TYPE = 0x000D, + WID_SITE_SURVEY = 0x000E, + WID_LISTEN_INTERVAL = 0x000F, + WID_DTIM_PERIOD = 0x0010, + WID_ACK_POLICY = 0x0011, + WID_RESET = 0x0012, + WID_PCF_MODE = 0x0013, + WID_CFP_PERIOD = 0x0014, + WID_BCAST_SSID = 0x0015, + +#ifdef MAC_HW_UNIT_TEST_MODE + WID_PHY_TEST_PATTERN = 0x0016, +#else /* MAC_HW_UNIT_TEST_MODE */ + WID_DISCONNECT = 0x0016, +#endif /* MAC_HW_UNIT_TEST_MODE */ + + WID_READ_ADDR_SDRAM = 0x0017, + WID_TX_POWER_LEVEL_11A = 0x0018, + WID_REKEY_POLICY = 0x0019, + WID_SHORT_SLOT_ALLOWED = 0x001A, + WID_PHY_ACTIVE_REG = 0x001B, + WID_PHY_ACTIVE_REG_VAL = 0x001C, + WID_TX_POWER_LEVEL_11B = 0x001D, + WID_START_SCAN_REQ = 0x001E, + WID_RSSI = 0x001F, + WID_JOIN_REQ = 0x0020, + WID_ANTENNA_SELECTION = 0x0021, + WID_USER_CONTROL_ON_TX_POWER = 0x0027, + WID_MEMORY_ACCESS_8BIT = 0x0029, + WID_UAPSD_SUPPORT_AP = 0x002A, + + WID_CURRENT_MAC_STATUS = 0x0031, + WID_AUTO_RX_SENSITIVITY = 0x0032, + WID_DATAFLOW_CONTROL = 0x0033, + WID_SCAN_FILTER = 0x0036, + WID_LINK_LOSS_THRESHOLD = 0x0037, + WID_AUTORATE_TYPE = 0x0038, + WID_CCA_THRESHOLD = 0x0039, + + WID_802_11H_DFS_MODE = 0x003B, + WID_802_11H_TPC_MODE = 0x003C, + + WID_PHY_REG_ADDR = 0x0040, + WID_PHY_REG_VAL = 0x0041, + WID_PTA_MODE = 0x0042, + WID_TRAP_TEST = 0x0043, + WID_PTA_BLOCK_BT = 0x0044, + WID_NETWORK_INFO_EN = 0x0045, + WID_RX_DATA_RATE = 0x004B, + WID_POWER_SAVE = 0x004C, + + WID_RTS_THRESHOLD = 0x1000, + WID_FRAG_THRESHOLD = 0x1001, + WID_SHORT_RETRY_LIMIT = 0x1002, + WID_LONG_RETRY_LIMIT = 0x1003, + WID_CFP_MAX_DUR = 0x1004, + WID_PHY_TEST_FRAME_LEN = 0x1005, + WID_BEACON_INTERVAL = 0x1006, + WID_MEMORY_ACCESS_16BIT = 0x1008, + + WID_RX_SENSE = 0x100B, + WID_ACTIVE_SCAN_TIME = 0x100C, + WID_PASSIVE_SCAN_TIME = 0x100D, + WID_SITE_SURVEY_SCAN_TIME = 0x100E, + WID_JOIN_TIMEOUT = 0x100F, + WID_AUTH_TIMEOUT = 0x1010, + WID_ASOC_TIMEOUT = 0x1011, + WID_11I_PROTOCOL_TIMEOUT = 0x1012, + WID_EAPOL_RESPONSE_TIMEOUT = 0x1013, + WID_CCA_BUSY_STATUS = 0x1014, + + WID_FAILED_COUNT = 0x2000, + WID_RETRY_COUNT = 0x2001, + WID_MULTIPLE_RETRY_COUNT = 0x2002, + WID_FRAME_DUPLICATE_COUNT = 0x2003, + WID_ACK_FAILURE_COUNT = 0x2004, + WID_RECEIVED_FRAGMENT_COUNT = 0x2005, + WID_MULTICAST_RECEIVED_FRAME_COUNT = 0x2006, + WID_FCS_ERROR_COUNT = 0x2007, + WID_SUCCESS_FRAME_COUNT = 0x2008, + WID_PHY_TEST_PKT_CNT = 0x2009, + WID_PHY_TEST_TXD_PKT_CNT = 0x200A, + WID_TX_FRAGMENT_COUNT = 0x200B, + WID_TX_MULTICAST_FRAME_COUNT = 0x200C, + WID_RTS_SUCCESS_COUNT = 0x200D, + WID_RTS_FAILURE_COUNT = 0x200E, + WID_WEP_UNDECRYPTABLE_COUNT = 0x200F, + WID_REKEY_PERIOD = 0x2010, + WID_REKEY_PACKET_COUNT = 0x2011, +#ifdef MAC_HW_UNIT_TEST_MODE + WID_Q_ENABLE_INFO = 0x2012, +#else /* MAC_HW_UNIT_TEST_MODE */ + WID_802_1X_SERV_ADDR = 0x2012, +#endif /* MAC_HW_UNIT_TEST_MODE */ + WID_STACK_IP_ADDR = 0x2013, + WID_STACK_NETMASK_ADDR = 0x2014, + WID_HW_RX_COUNT = 0x2015, + WID_MEMORY_ADDRESS = 0x201E, + WID_MEMORY_ACCESS_32BIT = 0x201F, + WID_RF_REG_VAL = 0x2021, + WID_FIRMWARE_INFO = 0x2023, + + WID_SYS_FW_VER = 0x2801, + WID_SYS_DBG_LVL = 0x2802, + WID_SYS_DBG_AREA = 0x2803, + WID_UT_MODE = 0x2804, + WID_UT_TX_LEN = 0x2805, + WID_PTA_CTS_FRAME_LEN = 0x2806, + WID_PREASSO_SLEEP = 0x2807, + + WID_SSID = 0x3000, + WID_FIRMWARE_VERSION = 0x3001, + WID_OPERATIONAL_RATE_SET = 0x3002, + WID_BSSID = 0x3003, + WID_WEP_KEY_VALUE0 = 0x3004, + WID_WEP_KEY_VALUE1 = 0x3005, + WID_WEP_KEY_VALUE2 = 0x3006, + WID_WEP_KEY_VALUE3 = 0x3007, + WID_802_11I_PSK = 0x3008, + WID_HCCA_ACTION_REQ = 0x3009, + WID_802_1X_KEY = 0x300A, + WID_HARDWARE_VERSION = 0x300B, + WID_MAC_ADDR = 0x300C, + WID_PHY_TEST_DEST_ADDR = 0x300D, + WID_PHY_TEST_STATS = 0x300E, + WID_PHY_VERSION = 0x300F, + WID_SUPP_USERNAME = 0x3010, + WID_SUPP_PASSWORD = 0x3011, + WID_SITE_SURVEY_RESULTS = 0x3012, + WID_RX_POWER_LEVEL = 0x3013, + + WID_ADD_WEP_KEY = 0x3019, + WID_REMOVE_WEP_KEY = 0x301A, + WID_ADD_PTK = 0x301B, + WID_ADD_RX_GTK = 0x301C, + WID_ADD_TX_GTK = 0x301D, + WID_REMOVE_KEY = 0x301E, + WID_ASSOC_REQ_INFO = 0x301F, + WID_ASSOC_RES_INFO = 0x3020, + WID_UPDATE_RF_SUPPORTED_INFO = 0x3021, + WID_COUNTRY_IE = 0x3022, + + WID_WAPI_ASSOC_IE = 0x3023, + WID_ADD_WAPI_PTK = 0x3024, + WID_ADD_WAPI_RX_GTK = 0x3025, + WID_ADD_WAPI_TX_GTK = 0x3026, + WID_HIDE_SSID = 0x3027, + //huanglei add for wps + WID_GEN_ASSOC_IE = 0x3028, + + WID_CONFIG_HCCA_ACTION_REQ = 0x4000, + WID_UAPSD_CONFIG = 0x4001, + WID_UAPSD_STATUS = 0x4002, + WID_WMM_AP_AC_PARAMS = 0x4003, + WID_WMM_STA_AC_PARAMS = 0x4004, + WID_NEWORK_INFO = 0x4005, + WID_STA_JOIN_INFO = 0x4006, + WID_CONNECTED_STA_LIST = 0x4007, + WID_HUT_STATS = 0x4082, + WID_STATISTICS = 0x4008, + WID_MEMORY_DUMP = 0x4009, + WID_LOAD_TRAP_MAP = 0x400a, + WID_AGC_DGC_TBL = 0x400b, + // miaodefang for PTA + WID_PTA_PARAMETER = 0x4010, + + /* NMAC Binary WID list */ + WID_11N_AUTORATE_TABLE = 0x4080, + + WID_ALL = 0x7FFE, + WID_MAX = 0xFFFF +} WID_T; + +typedef enum +{ + PTA_NONE_PROTECT = 0, + PTA_NULL_DATA_PROTECT, + PTA_PS_POLL_PROTECT, + PTA_SELF_CTS_PROTECT, + PTA_AUTO_PROTECT + +} PTA_PROTECT_MODE_T; + +struct pta_param_s +{ + u8 prot_mode; + u8 mac_rate; // 0: MIN_basic rate + u8 hw_retry; + u8 sw_retry; + u8 cca_bypass; + + u8 restore; + + u16 active_time; /* Unit is 100us */ + u16 thresh_time; /* Unit is 100us */ + + u16 auto_prot_thresh_time; /* Unit is 100us */ + + /* + * BIT0: Check high priority Q NULL before send PS_Poll or NULL frame + * BIT1: Check normal priority Q(AC_VO_Q) NULL before send PS_Poll or NULL frame + * BIT2: Check AC_VI_Q NULL before send PS_Poll or NULL frame + * BIT3: Check AC_BE_Q NULL before send PS_Poll or NULL frame + * BIT4: Check AC_BK_Q NULL before send PS_Poll or NULL frame + * BIT5: Check g_more_data_expected when send PS_Poll + */ + u16 flags; + +} __packed; + +void wlan_clean_wid_node(wlan_wid_packet_node * widNode); +wlan_wid_packet_node * wlan_get_wid_node(wlan_private * priv); +void wlan_put_wid_node_in_freeQ(wlan_private * priv, wlan_wid_packet_node * widNode); +wlan_wid_packet_node * wlan_get_wid_node_in_freeQ(wlan_private * priv); +int wlan_put_wid_node_in_pendingQ(wlan_private * priv, wlan_wid_packet_node * widNode); +wlan_wid_packet_node * wlan_get_wid_node_in_pendingQ(wlan_private * priv); +int wlan_alloc_wid_queue(wlan_private * priv); +int wlan_release_wid_pending_queue(wlan_private *priv); +int wlan_free_wid_queue(wlan_private * priv); +int wlan_read_wid_rsp_polling(wlan_private *priv); +int wlan_generic_get(wlan_private *priv, + u16 wid, u8 *val, u16 val_len, u32*rspLen, WID_TYPE_T type); +int wlan_generic_get_uchar(wlan_private *priv, + u16 wid, u8 *val); + +int wlan_generic_get_ushort(wlan_private *priv, + u16 wid, u8 *val); +int wlan_generic_get_ulong(wlan_private *priv, + u16 wid, u8 *val); +int wlan_generic_get_str(wlan_private *priv, + u16 wid, u8 *val, u32 len, u32 * rspLen); +int wlan_send_wid_packet(wlan_private *priv, u8 *val, u16 val_len, + u8 wid_msg_id); +int wlan_generic_set(wlan_private *priv, + u16 wid, u8 *val, u16 val_len, WID_TYPE_T type); +int wlan_generic_set_uchar(wlan_private *priv, + u16 wid, u8 val); +int wlan_generic_set_ushort(wlan_private *priv, + u16 wid, u16 val); +int wlan_generic_set_ulong(wlan_private *priv, + u16 wid, u32 val); +int wlan_generic_set_str(wlan_private *priv, + u16 wid, u8* val, u32 val_len); +int wlan_generic_set_bin(wlan_private * priv, u16 wid, u8 * val, u32 val_len); +int wlan_set_core_init_patch(wlan_private *priv, const u32 (*data)[2], u8 num); +int wlan_set_core_patch(wlan_private *priv, const u8 (*patch)[2], u8 num); +void wlan_wid_response(wlan_private *priv, + u8 *wid_rsp, u16 wid_rsp_len); +int wlan_set_scan_timeout(wlan_private *priv); +int wlan_start_scan_enable_network_info(wlan_private *priv); +int wlan_start_join(wlan_private *priv); +int wlan_set_txrate(wlan_private *priv, u8 mbps); +int wlan_get_fw_ver(wlan_private *priv, u32 *fw_ver); +int wlan_get_mac_addr(wlan_private *priv, u8 *mac_addr); +int wlan_get_bssid(wlan_private *priv, u8 *bssid); +int wlan_get_channel(wlan_private *priv, u8 *channel); +int wlan_get_rssi(wlan_private *priv, u8 *rssi); +int wlan_set_mac_addr(wlan_private *priv, u8 *mac_addr); +int wlan_set_preamble(wlan_private *priv, u8 preamble); +int wlan_set_scan_complete(wlan_private *priv); +int wlan_set_ssid(wlan_private *priv, + u8 *ssid, u8 ssid_len); +int wlan_get_ssid(wlan_private *priv, + u8 *ssid, u8 *ssid_len); +int wlan_set_bssid(wlan_private *priv, u8 *bssid); +int wlan_disconnect(wlan_private *priv); +int wlan_disconnect_silent(wlan_private * priv); +int wlan_set_imode(wlan_private *priv, u8 imode); +int wlan_set_authtype(wlan_private *priv, u8 authtype); +int wlan_set_listen_interval(wlan_private *priv, u8 interval); +int wlan_set_link_loss_threshold(wlan_private *priv, u8 threshold); +int wlan_set_power_save(wlan_private *priv); +int wlan_set_wepkey(wlan_private *priv, + u16 index, u8 *key, u8 key_len); +int wlan_set_ptk(wlan_private *priv, + u8 *key, u8 key_len); +int wlan_set_gtk(wlan_private *priv, u8 key_id, + u8 *key_rsc, u8 key_rsc_len, + u8 *key, u8 key_len); +int wlan_set_pm_mode(wlan_private *priv, u8 pm_mode); +int wlan_set_preasso_sleep(wlan_private *priv, u32 preasso_sleep); +int rda5890_set_preamble(wlan_private *priv, unsigned char preamble); +int wlan_set_pta(wlan_private * priv, struct pta_param_s* param); +#endif -- cgit