bool "MTK MT6620 WiFi SDIO"
---help---
A library for MTK_wcn_combo SDIO WLAN devices.
-
+ config RDA5990
+ depends on WLAN_80211 && MMC
+ select WIRELESS_EXT
+ select WEXT_PRIV
+ select IEEE80211
+ bool "rda 5990p"
+ ---help---
+ rda5990P fm bt wifi
+
config MV8686
depends on WLAN_80211 && MMC
select WIRELESS_EXT
obj-$(CONFIG_RTL8188EU) += rkusbwifi/
obj-$(CONFIG_AR6003) += ar6003/
obj-$(CONFIG_RKWIFI) += rkwifi/
+obj-$(CONFIG_RDA5990) += rda5990/
#obj-m += wlan/
--- /dev/null
+#obj-y += rda_gpio_i2c/ # 模拟I2C开此功能
+#obj-y += drv_fm_rda/
+
+obj-y += rda_wlan/
+obj-y += rda_5990_power_ctrl/
--- /dev/null
+# 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.
+
+
+# Makefile generated by Mediatek
+# rda fm support
+
+ifeq ($(MTK_FM_SUPPORT), yes)
+ifeq ($(CUSTOM_KERNEL_FM), mt6620)
+
+#obj-$(CONFIG_MTK_COMBO_FM) += RDA5990_FM_drv.o
+# for 模拟I2C
+obj-$(CONFIG_MTK_COMBO_FM) += RDA5990_FM_drv_gpio.o
+
+endif
+endif
+
+
--- /dev/null
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h> // udelay()
+#include <linux/device.h> // device_create()
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/cdev.h>
+#include <linux/fs.h>
+#include <linux/version.h> /* constant of kernel version */
+#include <asm/uaccess.h> // get_user()
+
+#include <linux/fm.h>
+#include <mach/mt6575_gpio.h>
+#include <mach/mtk_rtc.h>
+#include <linux/proc_fs.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+
+// if need debug, define FMDEBUG
+//#define FMDEBUG
+
+// if your platform is MT6515/6575, define MTK_MT6515
+#define MTK_MT6515
+
+// if your platform is MT6515/6575 and MTK FM is MT6626, define MT6626
+//#define MT6626
+
+#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
+
+extern int rda_fm_power_off();
+extern int rda_fm_power_on();
+
+/******************************************************************************
+ * CONSTANT DEFINITIONS
+ *****************************************************************************/
+#define RDAFM_SLAVE_ADDR (0x11 << 1) //RDA FM Chip address
+
+#define RDAFM_MASK_RSSI 0X7F // RSSI
+#define RDAFM_DEV "RDA599x"
+
+//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
+ *****************************************************************************/
+
+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, int kind, 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 struct i2c_board_info __initdata i2c_rdafm={ I2C_BOARD_INFO(RDAFM_DEV, (RDAFM_SLAVE_ADDR>>1))};
+#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
+ .probe = fm_i2c_probe,
+ .remove = fm_i2c_remove,
+ .detect = fm_i2c_detect,
+ .driver.name = RDAFM_DEV,
+ .id_table = &fm_i2c_id,
+ // .address_data = &addr_data,
+ .address_list = (const unsigned short*) forces,
+#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, //0x42C6
+ 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);
+
+ //set seekth
+ tRegValue = 0;
+ RDAFM_read(client, 0x05, &tRegValue);
+ tRegValue &= (~(0x7f<<8));
+ tRegValue |= ((0x8 & 0x7f) << 8);
+ RDAFM_write(client, 0x05, tRegValue);
+ msleep(50);
+
+ 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;
+}
+
+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);
+
+ // First, read 5802NM chip ID
+ FM_DEBUG("%s()First, read 5802NM chip ID\n", __func__);
+ ret = RDAFM_GetChipID(client, &RDAFM_CHIP_ID);
+ FM_DEBUG("%s() 5802NM chip ID = 0x%04x\n", __func__, RDAFM_CHIP_ID);
+ // 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;
+ }
+
+
+
+ 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);
+
+ 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
+ if(fm->chip_id == ID_RDA5820NS){
+ ret = rda_fm_power_on();
+ if(ret < 0){
+ return -EPERM;
+ }
+ msleep(100);
+ }
+
+
+ //Reset RDA FM
+ tRegValue = 0x0002;
+ RDAFM_write(client, 0x02, tRegValue);
+ msleep(100);
+
+
+ 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");
+
+ 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){
+ ret = rda_fm_power_off();
+ if(ret < 0){
+ return -EPERM;
+ }
+ }
+
+ 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;
+ }
+
+ RDAFM_read(client, 0x05, &tRegValue);
+ tRegValue &= (~(0x7f<<8));
+ //tRegValue |= ((parm->seekth & 0x7f) << 8);
+ tRegValue |= ((0x8 & 0x7f) << 8);
+ RDAFM_write(client, 0x05, tRegValue);
+
+
+#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;
+}
+
+/*
+ * fm_scan
+ */
+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;
+
+ 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);
+
+ 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_i2c_detect(struct i2c_client *client, int kind, struct i2c_board_info *info)
+{
+ FM_DEBUG("fm_i2c_detect\n");
+ strcpy(info->type, RDAFM_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;
+}
+#endif
+
+int i2c_static_add_device(struct i2c_board_info *info)
+{
+ struct i2c_adapter *adapter;
+ struct i2c_client *client;
+ int ret;
+
+ adapter = i2c_get_adapter(RDAFM_I2C_PORT);
+ if (!adapter) {
+ FM_DEBUG("%s: can't get i2c adapter\n", __func__);
+ ret = -ENODEV;
+ goto i2c_err;
+ }
+
+ client = i2c_new_device(adapter, info);
+ if (!client) {
+ FM_DEBUG("%s: can't add i2c device at 0x%x\n",
+ __FUNCTION__, (unsigned int)info->addr);
+ ret = -ENODEV;
+ goto i2c_err;
+ }
+
+ i2c_put_adapter(adapter);
+
+ return 0;
+
+i2c_err:
+ return ret;
+}
+
+static int mt_fm_probe(struct platform_device *pdev)
+{
+ int err = -1;
+ FM_ALERT("mt_fm_probe\n");
+ err = i2c_static_add_device(&i2c_rdafm);
+ if (err < 0){
+ FM_DEBUG("%s(): add i2c device error, err = %d\n", __func__, err);
+ return err;
+ }
+
+ // 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_unregister_device(g_fm_struct->i2c_client);
+ 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 struct platform_device mt_fm_device = {
+ .name = FM_NAME,
+ .id = -1,
+};
+#endif
+
+
+/*
+ * mt_fm_init
+ */
+static int __init mt_fm_init(void)
+{
+ int err = 0;
+
+ FM_DEBUG("mt_fm_init\n");
+#if defined(MTK_MT6515)
+ err = platform_device_register(&mt_fm_device);
+ if(err){
+ FM_DEBUG("platform_device_register fail\n");
+ return err;
+ }else{
+ FM_DEBUG("platform_device_register success\n");
+ }
+#endif
+ err = platform_driver_register(&mt_fm_dev_drv);
+ if (err)
+ {
+ FM_DEBUG("platform_driver_register failed\n");
+ }else{
+ FM_DEBUG("platform_driver_register success\n");
+ }
+
+ return err;
+}
+
+/*
+ * mt_fm_exit
+ */
+static void __exit mt_fm_exit(void)
+{
+ FM_DEBUG("mt_fm_exit\n");
+ platform_driver_unregister(&mt_fm_dev_drv);
+#if defined(MTK_MT6515)
+ platform_device_unregister(&mt_fm_device);
+#endif
+}
+
+module_init(mt_fm_init);
+module_exit(mt_fm_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("MediaTek FM Driver");
+MODULE_AUTHOR("William Chung <William.Chung@MediaTek.com>");
+
+
--- /dev/null
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h> // udelay()
+#include <linux/device.h> // device_create()
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/cdev.h>
+#include <linux/fs.h>
+#include <linux/version.h> /* constant of kernel version */
+#include <asm/uaccess.h> // get_user()
+
+#include <linux/fm.h>
+#include <mach/mt6575_gpio.h>
+#include <mach/mtk_rtc.h>
+#include <linux/proc_fs.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+
+// if need debug, define FMDEBUG
+//#define FMDEBUG
+
+// if your platform is MT6515/6575, define MTK_MT6515
+#define MTK_MT6515
+
+// if your platform is MT6515/6575 and MTK FM is MT6626, define MT6626
+//#define MT6626
+
+#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
+
+extern int rda_gpio_i2c_read_1_addr_2_data(uint8_t chipAddr, uint8_t regAddr, unsigned short *buffer);
+extern int rda_gpio_i2c_write_1_addr_2_data(uint8_t chipAddr, uint8_t regAddr, unsigned short data);
+extern int rda_fm_power_off(void);
+extern int rda_fm_power_on(void);
+
+/******************************************************************************
+ * CONSTANT DEFINITIONS
+ *****************************************************************************/
+#define RDAFM_SLAVE_ADDR 0x11 //RDA FM Chip address
+
+#define RDAFM_MASK_RSSI 0X7F // RSSI
+
+
+
+#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;
+ uint8_t chipAddr;
+ 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
+ *****************************************************************************/
+
+
+static int RDAFM_clear_hmute(uint8_t chipAddr);
+static int RDAFM_enable_hmute(uint8_t chipAddr);
+static bool RDAFM_Scan(uint8_t chipAddr,
+ 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(uint8_t chipAddr, uint8_t addr, uint16_t *val);
+static int RDAFM_write(uint8_t chipAddr, uint8_t addr, uint16_t val);
+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(void);
+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);
+
+
+
+
+
+
+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, //0x42C6
+ 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(uint8_t chipAddr, uint16_t *pChipID)
+{
+ int err;
+ int ret = -1;
+ uint16_t val = 0x0002;
+
+ //Reset RDA FM
+ err = RDAFM_write(chipAddr, 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(chipAddr, 0x0C, &val);
+ if (err == 0)
+ {
+ if ((0x5802 == val) || (0x5803 == val))
+ {
+ err = RDAFM_read(chipAddr, 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(uint8_t chipAddr, uint8_t regAddr, uint16_t *val)
+{
+ int ret = -1;
+ ret = rda_gpio_i2c_read_1_addr_2_data(chipAddr, regAddr, val);
+
+ return ret;
+}
+
+/*
+ * RDAFM_write
+ */
+static int RDAFM_write(uint8_t chipAddr, uint8_t regAddr, uint16_t val)
+{
+ int n;
+
+ n = rda_gpio_i2c_write_1_addr_2_data(chipAddr, regAddr, val);
+ if (n < 0)
+ {
+ FM_ALERT("RDAFM_write send:0x%X err:%d\n", regAddr, n);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int RDAFM_clear_hmute(uint8_t chipAddr)
+{
+ int ret = 0;
+ uint16_t tRegValue = 0;
+
+ FM_DEBUG("RDAFM_clear_hmute\n");
+
+ ret = RDAFM_read(chipAddr, 0x02, &tRegValue);
+ if (ret < 0)
+ {
+ FM_ALERT("RDAFM_clear_hmute read register failed!\n");
+ return -1;
+ }
+
+ tRegValue |= (1 << 14);
+
+ ret = RDAFM_write(chipAddr, 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(uint8_t chipAddr)
+{
+ int ret = 0;
+ uint16_t tRegValue = 0;
+
+ FM_DEBUG("RDAFM_enable_hmute\n");
+
+ ret = RDAFM_read(chipAddr, 0x02, &tRegValue);
+ if (ret < 0)
+ {
+ FM_ALERT("RDAFM_enable_hmute read register failed!\n");
+ return -1;
+ }
+
+ tRegValue &= (~(1 << 14));
+
+ ret = RDAFM_write(chipAddr, 0x02, tRegValue);
+
+ if (ret < 0)
+ {
+ FM_ALERT("RDAFM_enable_hmute write register failed!\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static bool RDAFM_Scan(uint8_t chipAddr,
+ 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(chipAddr);
+
+ //set seekth
+ tRegValue = 0;
+ RDAFM_read(chipAddr, 0x05, &tRegValue);
+ tRegValue &= (~(0x7f<<8));
+ tRegValue |= ((0x8 & 0x7f) << 8);
+ RDAFM_write(chipAddr, 0x05, tRegValue);
+ msleep(50);
+
+ 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(chipAddr, 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(chipAddr, 0x03, tRegValue);
+ msleep(40);
+
+ //read 0x0B and check FM_TRUE(bit[8])
+ tRegValue = 0;
+ ret = RDAFM_read(chipAddr, 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(chipAddr, 0x0A, &tRegValue);
+ //channel = ((tRegValue) & 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(chipAddr);
+
+ 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");
+
+ 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;
+ break;
+ }
+
+ case FM_IOCTL_POWERDOWN:
+ {
+ FM_DEBUG("FM_IOCTL_POWERDOWN\n");
+ if (down_interruptible(&fm_ops_mutex))
+ return -EFAULT;
+ ret = fm_powerdown(fm);
+ up(&fm_ops_mutex);
+ break;
+ }
+
+ // tune (frequency, auto Hi/Lo ON/OFF )
+ case FM_IOCTL_TUNE:
+ {
+ struct fm_tune_parm parm;
+ FM_DEBUG("FM_IOCTL_TUNE\n");
+
+ 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");
+
+ 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");
+
+ 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");
+
+ 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");
+
+ 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->chipAddr);
+ }else{
+ ret = RDAFM_clear_hmute(fm->chipAddr);
+ }
+
+ up(&fm_ops_mutex);
+
+ break;
+ }
+
+ case FM_IOCTL_GETRSSI:
+ {
+ uint32_t rssi;
+ FM_DEBUG("FM_IOCTL_GETRSSI\n");
+
+ 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");
+
+ 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->chipAddr, parm_ctl.addr, parm_ctl.val);
+ }
+ else
+ {
+ ret = RDAFM_read(fm->chipAddr, 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->chipAddr, &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_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->chipAddr, &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;
+ }
+
+ case FM_IOCTL_SCAN_GETRSSI:
+ {
+ FM_DEBUG("FM_IOCTL_SCAN_GETRSSI\n");
+ break;
+ }
+
+ case FM_IOCTL_GETMONOSTERO:
+ {
+ FM_DEBUG("FM_IOCTL_GETMONOSTERO\n");
+ break;
+ }
+
+ case FM_IOCTL_SETMONOSTERO:
+ {
+ FM_DEBUG("FM_IOCTL_SETMONOSTERO\n");
+ break;
+ }
+
+ case FM_IOCTL_GETCURPAMD:
+ {
+ FM_DEBUG("FM_IOCTL_GETCURPAMD\n");
+ break;
+ }
+
+ case FM_IOCTL_EM_TEST:
+ {
+ FM_DEBUG("FM_IOCTL_EM_TEST\n");
+ break;
+ }
+
+ case FM_IOCTL_RDS_SUPPORT:
+ {
+ FM_DEBUG("FM_IOCTL_RDS_SUPPORT\n");
+ break;
+ }
+
+ case FM_IOCTL_RDS_ONOFF:
+ {
+ FM_DEBUG("FM_IOCTL_RDS_ONOFF\n");
+ break;
+ }
+
+ case FM_IOCTL_GETGOODBCNT:
+ {
+ FM_DEBUG("FM_IOCTL_GETGOODBCNT\n");
+ break;
+ }
+
+ case FM_IOCTL_GETBADBNT:
+ {
+ FM_DEBUG("FM_IOCTL_GETBADBNT\n");
+ break;
+ }
+
+ case FM_IOCTL_GETBLERRATIO:
+ {
+ FM_DEBUG("FM_IOCTL_GETBLERRATIO\n");
+ break;
+ }
+
+ case FM_IOCTL_POWERUP_TX:
+ {
+ FM_DEBUG("FM_IOCTL_POWERUP_TX\n");
+ break;
+ }
+
+ case FM_IOCTL_TUNE_TX:
+ {
+ FM_DEBUG("FM_IOCTL_TUNE_TX\n");
+ break;
+ }
+
+ case FM_IOCTL_TX_SUPPORT:
+ {
+ FM_DEBUG("FM_IOCTL_TX_SUPPORT\n");
+ break;
+ }
+
+ case FM_IOCTL_RDSTX_ENABLE:
+ {
+ FM_DEBUG("FM_IOCTL_RDSTX_ENABLE\n");
+ break;
+ }
+
+ case FM_IOCTL_RDSTX_SUPPORT:
+ {
+ FM_DEBUG("FM_IOCTL_RDSTX_SUPPORT\n");
+ break;
+ }
+
+ case FM_IOCTL_TX_SCAN:
+ {
+ FM_DEBUG("FM_IOCTL_TX_SCAN\n");
+ break;
+ }
+
+ case FM_IOCTL_RDS_TX:
+ {
+ FM_DEBUG("FM_IOCTL_RDS_TX\n");
+ break;
+ }
+
+ case FM_IOCTL_OVER_BT_ENABLE:
+ {
+ FM_DEBUG("FM_IOCTL_OVER_BT_ENABLE\n");
+ break;
+ }
+
+ case FM_IOCTL_ANA_SWITCH:
+ {
+ FM_DEBUG("FM_IOCTL_ANA_SWITCH\n");
+ break;
+ }
+
+ case FM_IOCTL_GETCAPARRAY:
+ {
+ FM_DEBUG("FM_IOCTL_GETCAPARRAY\n");
+ break;
+ }
+
+ case FM_IOCTL_GPS_RTC_DRIFT:
+ {
+ FM_DEBUG("FM_IOCTL_GPS_RTC_DRIFT\n");
+ break;
+ }
+
+ case FM_IOCTL_I2S_SETTING:
+ {
+ FM_DEBUG("FM_IOCTL_I2S_SETTING\n");
+ break;
+ }
+
+ case FM_IOCTL_RDS_GROUPCNT:
+ {
+ FM_DEBUG("FM_IOCTL_RDS_GROUPCNT\n");
+ break;
+ }
+
+ case FM_IOCTL_RDS_GET_LOG:
+ {
+ FM_DEBUG("FM_IOCTL_RDS_GET_LOG\n");
+ break;
+ }
+
+ case FM_IOCTL_GET_HW_INFO:
+ {
+ FM_DEBUG("FM_IOCTL_GET_HW_INFO\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;
+}
+
+static int fm_init(void)
+{
+ 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;
+ fm->chipAddr = RDAFM_SLAVE_ADDR;
+ atomic_set(&scan_complete_flag, 0);
+
+ // First, read 5802NM chip ID
+ FM_DEBUG("%s()First, read 5802NM chip ID\n", __func__);
+ ret = RDAFM_GetChipID(fm->chipAddr, &RDAFM_CHIP_ID);
+ FM_DEBUG("%s() 5802NM chip ID = 0x%04x\n", __func__, RDAFM_CHIP_ID);
+ // 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(fm->chipAddr, &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;
+ }
+
+
+
+ if ((err = fm_setup_cdev(fm)))
+ {
+ goto ERR_EXIT;
+ }
+
+ g_fm_struct = 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);
+
+ 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;
+
+
+ if (fm->powerup)
+ {
+ parm->err = FM_BADSTATUS;
+ return -EPERM;
+ }
+
+ // if chip_id is ID_RDA5820NS, enable the FM chip in combo
+ if(fm->chip_id == ID_RDA5820NS){
+ ret = rda_fm_power_on();
+ if(ret < 0){
+ return -EPERM;
+ }
+ msleep(100);
+ }
+
+
+ //Reset RDA FM
+ tRegValue = 0x0002;
+ RDAFM_write(fm->chipAddr, 0x02, tRegValue);
+ msleep(100);
+
+
+
+ if (ID_RDA5802N == RDAFM_CHIP_ID){
+ for (i=0; i<((sizeof(RDA5802N_initialization_reg)) / (sizeof(uint16_t))); i++)
+ {
+ ret = RDAFM_write(fm->chipAddr, i+2, RDA5802N_initialization_reg[i]);
+
+ if (ret < 0)
+ {
+ FM_DEBUG("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(fm->chipAddr, 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(fm->chipAddr, 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;
+
+ RDAFM_read(fm->chipAddr, 0x02, &tRegValue);
+ tRegValue &= (~(1 << 0));
+ RDAFM_write(fm->chipAddr, 0x02, tRegValue);
+
+ if(fm->chip_id == ID_RDA5820NS){
+ ret = rda_fm_power_off();
+ if(ret < 0){
+ return -EPERM;
+ }
+ }
+
+ 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;
+
+
+ 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;
+ }
+
+ RDAFM_read(fm->chipAddr, 0x05, &tRegValue);
+ tRegValue &= (~(0x7f<<8));
+ //tRegValue |= ((parm->seekth & 0x7f) << 8);
+ tRegValue |= ((0x8 & 0x7f) << 8);
+ RDAFM_write(fm->chipAddr, 0x05, tRegValue);
+
+
+#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(fm->chipAddr);
+
+ 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(fm->chipAddr, 0x03, val);
+ msleep(40);
+ ret = RDAFM_read(fm->chipAddr, 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(fm->chipAddr);
+
+ 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;
+}
+
+/*
+ * fm_scan
+ */
+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;
+
+ if (!fm->powerup){
+ parm->err = FM_BADSTATUS;
+ return -EPERM;
+ }
+
+ RDAFM_read(fm->chipAddr, 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(fm->chipAddr, 0x03, tRegValue);
+ msleep(40);
+
+
+ if(RDAFM_Scan(fm->chipAddr, 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;
+
+ if (vol > 15)
+ vol = 15;
+
+ FM_DEBUG("fm_setvol:%d\n", vol);
+
+ ret = RDAFM_read(fm->chipAddr, 0x05, &tRegValue);
+ if (ret)
+ return -EPERM;
+ tRegValue &= ~(0x000f);
+ tRegValue |= vol;
+
+ ret = RDAFM_write(fm->chipAddr, 0x05, tRegValue);
+ if (ret)
+ return -EPERM;
+
+ return 0;
+}
+
+static int fm_getvol(struct fm *fm, uint32_t *vol)
+{
+ int ret = 0;
+ uint16_t tRegValue;
+
+ ret = RDAFM_read(fm->chipAddr, 0x05, &tRegValue);
+ if (ret)
+ return -EPERM;
+
+ 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;
+
+ ret = RDAFM_read(fm->chipAddr, 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;
+
+
+ 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);
+
+
+ val = (((parm->freq - bottomOfBand + 5) << 6) | (1 << 4) | (val & 0x0f));
+
+ ret = RDAFM_write(fm->chipAddr, 0x03, val);
+ if (ret < 0)
+ {
+ FM_ALERT("fm_tune write freq failed\n");
+ parm->err = FM_SEEK_FAILED;
+ return ret;
+ }
+ msleep(40);
+
+ return ret;
+}
+
+
+static int mt_fm_probe(struct platform_device *pdev)
+{
+ int err = -1;
+ FM_DEBUG("mt_fm_probe\n");
+
+ if ((err = fm_init()))
+ {
+ FM_ALERT("fm_init ERR:%d\n", err);
+ }
+
+ return err;
+}
+
+static int mt_fm_remove(struct platform_device *pdev)
+{
+ FM_DEBUG("mt_fm_remove\n");
+
+ struct fm *fm = g_fm_struct;
+ if(fm)
+ {
+ fm_destroy(fm);
+ fm = NULL;
+ }
+
+ return 0;
+}
+
+
+static struct platform_driver mt_fm_dev_drv =
+{
+ .probe = mt_fm_probe,
+ .remove = mt_fm_remove,
+ .driver = {
+ .name = FM_NAME,
+ .owner = THIS_MODULE,
+ }
+};
+
+#if defined(MTK_MT6515)
+static struct platform_device mt_fm_device = {
+ .name = FM_NAME,
+ .id = -1,
+};
+#endif
+
+
+/*
+ * mt_fm_init
+ */
+static int __init mt_fm_init(void)
+{
+ int err = 0;
+
+ FM_DEBUG("mt_fm_init\n");
+#if defined(MTK_MT6515)
+ err = platform_device_register(&mt_fm_device);
+ if(err){
+ FM_DEBUG("platform_device_register fail\n");
+ return err;
+ }else{
+ FM_DEBUG("platform_device_register success\n");
+ }
+#endif
+ err = platform_driver_register(&mt_fm_dev_drv);
+ if (err)
+ {
+ FM_DEBUG("platform_driver_register failed\n");
+ }else{
+ FM_DEBUG("platform_driver_register success\n");
+ }
+
+ return err;
+}
+
+/*
+ * mt_fm_exit
+ */
+static void __exit mt_fm_exit(void)
+{
+ FM_DEBUG("mt_fm_exit\n");
+ platform_driver_unregister(&mt_fm_dev_drv);
+#if defined(MTK_MT6515)
+ platform_device_unregister(&mt_fm_device);
+#endif
+}
+
+module_init(mt_fm_init);
+module_exit(mt_fm_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("MediaTek FM Driver");
+MODULE_AUTHOR("William Chung <William.Chung@MediaTek.com>");
--- /dev/null
+obj-y := rda_5990_power_ctrl.o
+#for 模拟I2C
+#obj-y := rda_5990_power_ctrl_by_gpio.o
--- /dev/null
+/* ----------------------------------------------------------------------- *\r
+ *\r
+ This file created by albert RDA Inc\r
+ */\r
+\r
+#include <linux/module.h>\r
+#include <linux/init.h>\r
+#include <linux/slab.h>\r
+#include <linux/i2c.h>\r
+#include <linux/string.h>\r
+#include <linux/rtc.h> /* get the user-level API */\r
+#include <linux/bcd.h>\r
+#include <linux/list.h>\r
+#include <linux/delay.h>\r
+\r
+\r
+#include <linux/nfs_fs.h>\r
+#include <linux/nfs_fs_sb.h>\r
+#include <linux/nfs_mount.h>\r
+#include <linux/fs.h>\r
+#include <linux/file.h>\r
+#include <linux/tty.h>\r
+#include <linux/syscalls.h>\r
+#include <asm/termbits.h>\r
+#include <linux/serial.h>\r
+\r
+#include <linux/wakelock.h>\r
+\r
+#define RDA5890_USE_CRYSTAL // if use share crystal should close this\r
+#define RDA5990_USE_DCDC\r
+\r
+#define u32 unsigned int\r
+#define u8 unsigned char\r
+#define u16 unsigned short\r
+\r
+#define RDA_I2C_CHANNEL (0)\r
+#define RDA_WIFI_CORE_ADDR (0x13 << 1)\r
+#define RDA_WIFI_RF_ADDR (0x14 << 1) //correct add is 0x14\r
+#define RDA_BT_CORE_ADDR (0x15 << 1)\r
+#define RDA_BT_RF_ADDR (0x16 << 1)\r
+\r
+#define I2C_MASTER_ACK (1<<0)\r
+#define I2C_MASTER_RD (1<<4)\r
+#define I2C_MASTER_STO (1<<8)\r
+#define I2C_MASTER_WR (1<<12)\r
+#define I2C_MASTER_STA (1<<16)\r
+\r
+#define RDA_WIFI_RF_I2C_DEVNAME "rda_wifi_rf_i2c"\r
+#define RDA_WIFI_CORE_I2C_DEVNAME "rda_wifi_core_i2c"\r
+#define RDA_BT_RF_I2C_DEVNAME "rda_bt_rf_i2c"\r
+#define RDA_BT_CORE_I2C_DEVNAME "rda_bt_core_i2c"\r
+\r
+static struct mutex i2c_rw_lock;\r
+//extern int\r
+//i2c_register_board_info(int busnum, struct i2c_board_info const *info,\r
+// unsigned n);\r
+\r
+\r
+static unsigned short wlan_version = 0;\r
+static struct wake_lock rda_5990_wake_lock;\r
+static struct delayed_work rda_5990_sleep_worker;\r
+static struct i2c_client * rda_wifi_core_client = NULL;\r
+static struct i2c_client * rda_wifi_rf_client = NULL;\r
+static struct i2c_client * rda_bt_core_client = NULL;\r
+static struct i2c_client * rda_bt_rf_client = NULL;\r
+\r
+static const struct i2c_device_id wifi_rf_i2c_id[] = {{RDA_WIFI_RF_I2C_DEVNAME, 0}, {}};\r
+MODULE_DEVICE_TABLE(i2c, wifi_rf_i2c_id);\r
+\r
+static unsigned short wifi_rf_force[] = { RDA_I2C_CHANNEL, RDA_WIFI_RF_ADDR, I2C_CLIENT_END, I2C_CLIENT_END };\r
+\r
+static struct i2c_board_info __initdata i2c_rda_wifi_rf={ I2C_BOARD_INFO(RDA_WIFI_RF_I2C_DEVNAME, (RDA_WIFI_RF_ADDR>>1))};\r
+static struct i2c_driver rda_wifi_rf_driver;\r
+\r
+\r
+\r
+static const struct i2c_device_id wifi_core_i2c_id[] = {{RDA_WIFI_CORE_I2C_DEVNAME, 0}, {}};\r
+MODULE_DEVICE_TABLE(i2c, wifi_core_i2c_id);\r
+\r
+static unsigned short wifi_core_force[] = { RDA_I2C_CHANNEL, RDA_WIFI_CORE_ADDR, I2C_CLIENT_END, I2C_CLIENT_END };\r
+static struct i2c_board_info __initdata i2c_rda_wifi_core={ I2C_BOARD_INFO(RDA_WIFI_CORE_I2C_DEVNAME, (RDA_WIFI_CORE_ADDR>>1))};\r
+static struct i2c_driver rda_wifi_core_driver;\r
+\r
+\r
+\r
+static const struct i2c_device_id bt_rf_i2c_id[] = {{RDA_BT_RF_I2C_DEVNAME, 0}, {}};\r
+\r
+MODULE_DEVICE_TABLE(i2c, bt_rf_i2c_id);\r
+\r
+static unsigned short bt_rf_force[] = { RDA_I2C_CHANNEL, RDA_BT_RF_ADDR, I2C_CLIENT_END, I2C_CLIENT_END };\r
+static struct i2c_board_info __initdata i2c_rda_bt_rf={ I2C_BOARD_INFO(RDA_BT_RF_I2C_DEVNAME, (RDA_BT_RF_ADDR>>1))};\r
+static struct i2c_driver rda_bt_rf_driver;\r
+\r
+static const struct i2c_device_id bt_core_i2c_id[] = {{RDA_BT_CORE_I2C_DEVNAME, 0}, {}};\r
+MODULE_DEVICE_TABLE(i2c, bt_core_i2c_id);\r
+\r
+static unsigned short bt_core_force[] = { RDA_I2C_CHANNEL, RDA_BT_CORE_ADDR, I2C_CLIENT_END, I2C_CLIENT_END };\r
+static struct i2c_board_info __initdata i2c_rda_bt_core={ I2C_BOARD_INFO(RDA_BT_CORE_I2C_DEVNAME, (RDA_BT_CORE_ADDR>>1))};\r
+static struct i2c_driver rda_bt_core_driver;\r
+\r
+\r
+static u8 isBigEnded = 0;\r
+static u8 wifi_in_test_mode = 0;\r
+\r
+static int i2c_write_data_4_addr_4_data(struct i2c_client* client, const u32 addr, const u32 data)\r
+{\r
+ unsigned char ADDR[4], DATA[4];\r
+ int ret = 0;\r
+\r
+ if(!isBigEnded)\r
+ {\r
+ ADDR[0] = addr >> 24;\r
+ ADDR[1] = addr >> 16;\r
+ ADDR[2] = addr >> 8;\r
+ ADDR[3] = addr >> 0;\r
+\r
+ DATA[0] = data >> 24;\r
+ DATA[1] = data >> 16;\r
+ DATA[2] = data >> 8;\r
+ DATA[3] = data >> 0;\r
+ }\r
+ else\r
+ {\r
+ memcpy(ADDR, &addr, sizeof(u32));\r
+ memcpy(DATA, &data, sizeof(u32));\r
+ }\r
+\r
+ ret = i2c_master_send(client, (char*)ADDR, 4);\r
+ if (ret < 0)\r
+ {\r
+ printk(KERN_INFO "***i2c_write_data_4_addr_4_data send:0x%X err:%d\n", addr,ret);\r
+ return -1;\r
+ }\r
+\r
+ ret = i2c_master_send(client, (char*)DATA, 4);\r
+ if (ret < 0)\r
+ {\r
+ printk(KERN_INFO "***i2c_write_data_4_addr_4_data send:0x%X err:%d\n", data,ret);\r
+ return -1;\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+\r
+static int i2c_read_4_addr_4_data(struct i2c_client* client, const u32 addr, u32* data)\r
+{\r
+ unsigned char ADDR[4], DATA[4];\r
+ int ret = 0;\r
+\r
+ if(!isBigEnded)\r
+ {\r
+ ADDR[0] = addr >> 24;\r
+ ADDR[1] = addr >> 16;\r
+ ADDR[2] = addr >> 8;\r
+ ADDR[3] = addr >> 0;\r
+ }\r
+ else\r
+ {\r
+ memcpy(ADDR, &addr, sizeof(u32));\r
+ }\r
+\r
+ ret = i2c_master_send(client, (char*)ADDR, 4);\r
+ if (ret < 0)\r
+ {\r
+ printk(KERN_INFO "***i2c_read_4_addr_4_data send:0x%X err:%d\n", addr,ret);\r
+ return -1;\r
+ }\r
+\r
+ ret = i2c_master_recv(client, (char*)DATA, 4);\r
+ if (ret < 0)\r
+ {\r
+ printk(KERN_INFO "***i2c_read_4_addr_4_data send:0x%X err:%d\n", addr,ret);\r
+ return -1;\r
+ }\r
+\r
+ if(!isBigEnded)\r
+ {\r
+ data[3] = DATA[0];\r
+ data[2] = DATA[1];\r
+ data[1] = DATA[2];\r
+ data[0] = DATA[3];\r
+ }\r
+ else\r
+ memcpy(data, DATA, sizeof(u32));\r
+\r
+ return 0;\r
+}\r
+\r
+\r
+static int i2c_write_1_addr_2_data(struct i2c_client* client, const u8 addr, const u16 data)\r
+{\r
+ unsigned char DATA[3];\r
+ int ret = 0;\r
+\r
+ if(!isBigEnded)\r
+ {\r
+ DATA[0] = addr;\r
+ DATA[1] = data >> 8;\r
+ DATA[2] = data >> 0;\r
+ }\r
+ else\r
+ {\r
+ DATA[0] = addr;\r
+ DATA[1] = data >> 0;\r
+ DATA[2] = data >> 8;\r
+ }\r
+\r
+ ret = i2c_master_send(client, (char*)DATA, 3);\r
+ if (ret < 0)\r
+ {\r
+ printk(KERN_INFO "***i2c_write_1_addr_2_data send:0x%X err:%d bigendia: %d \n", addr,ret, isBigEnded);\r
+ return -1;\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+\r
+static int i2c_read_1_addr_2_data(struct i2c_client* client, const u8 addr, u16* data)\r
+{\r
+ unsigned char DATA[2];\r
+ int ret = 0;\r
+\r
+ ret = i2c_master_send(client, (char*)&addr, 1);\r
+ if (ret < 0)\r
+ {\r
+ printk(KERN_INFO "***i2c_read_1_addr_2_data send:0x%X err:%d\n", addr,ret);\r
+ return -1;\r
+ }\r
+\r
+ ret = i2c_master_recv(client, DATA, 2);\r
+ if (ret < 0)\r
+ {\r
+ printk(KERN_INFO "***i2c_read_1_addr_2_data send:0x%X err:%d\n", addr,ret);\r
+ return -1;\r
+ }\r
+\r
+ if(!isBigEnded)\r
+ {\r
+ *data = (DATA[0] << 8) | DATA[1];\r
+ }\r
+ else\r
+ {\r
+ *data = (DATA[1] << 8) | DATA[0];\r
+ }\r
+ return 0;\r
+}\r
+\r
+\r
+static int rda_wifi_rf_probe(struct i2c_client *client, const struct i2c_device_id *id)\r
+{\r
+ int result = 0;\r
+\r
+ rda_wifi_rf_client = client;\r
+ return result;\r
+}\r
+\r
+static int rda_wifi_rf_remove(struct i2c_client *client)\r
+{\r
+ return 0;\r
+}\r
+\r
+static int rda_wifi_rf_detect(struct i2c_client *client, int kind, struct i2c_board_info *info)\r
+{ \r
+ strcpy(info->type, RDA_WIFI_RF_I2C_DEVNAME); \r
+ return 0; \r
+}\r
+\r
+static struct i2c_driver rda_wifi_rf_driver = {\r
+ .probe = rda_wifi_rf_probe,\r
+ .remove = rda_wifi_rf_remove,\r
+ .detect = rda_wifi_rf_detect,\r
+ .driver.name = RDA_WIFI_RF_I2C_DEVNAME,\r
+ .id_table = wifi_rf_i2c_id,\r
+// .address_data = &rda_wifi_rf_addr_data,\r
+ //.address_list = (const unsigned short*) wifi_rf_force,\r
+};\r
+\r
+static int rda_wifi_core_detect(struct i2c_client *client, int kind, struct i2c_board_info *info)\r
+{\r
+ strcpy(info->type, RDA_WIFI_CORE_I2C_DEVNAME);\r
+ return 0; \r
+}\r
+\r
+static int rda_wifi_core_probe(struct i2c_client *client, const struct i2c_device_id *id)\r
+{\r
+ int result = 0;\r
+\r
+ rda_wifi_core_client = client;\r
+ return result;\r
+}\r
+\r
+static int rda_wifi_core_remove(struct i2c_client *client)\r
+{\r
+ return 0;\r
+}\r
+\r
+int rda_wifi_power_off(void);\r
+static void rda_wifi_shutdown(struct i2c_client * client)\r
+{\r
+ printk("rda_wifi_shutdown \n");\r
+ rda_wifi_power_off();\r
+}\r
+\r
+static struct i2c_driver rda_wifi_core_driver = \r
+{\r
+ .probe = rda_wifi_core_probe,\r
+ .remove = rda_wifi_core_remove,\r
+ .detect = rda_wifi_core_detect,\r
+ .shutdown = rda_wifi_shutdown,\r
+ .driver.name = RDA_WIFI_CORE_I2C_DEVNAME,\r
+ .id_table = wifi_core_i2c_id,\r
+ //.address_data = &rda_wifi_core_addr_data,\r
+ //.address_list = (const unsigned short*)wifi_core_force,\r
+};\r
+\r
+const u32 wifi_core_init_data[][2] = \r
+{\r
+\r
+};\r
+\r
+u16 wifi_off_data[][2] = \r
+{\r
+ { 0x3F, 0x0001 }, //page up\r
+ { 0x31, 0x0B40 }, //power off wifi\r
+ { 0x3F, 0x0000 }, //page down\r
+};\r
+\r
+u16 wifi_en_data[][2] = \r
+{\r
+ //item:VerD_wf_on_2012_02_08\r
+ {0x3f, 0x0001},\r
+#ifdef RDA5990_USE_DCDC /*houzhen update Mar 15 2012 */\r
+ {0x23, 0x8FA1},//20111001 higher AVDD voltage to improve EVM to 0x8f21 download current -1db 0x8fA1>>0x8bA1 \r
+#else\r
+ {0x23, 0x0FA1},\r
+#endif\r
+ {0x31, 0x0B40 }, //power off wifi\r
+// {0x22, 0xD3C7},//for ver.c 20111109, txswitch\r
+ {0x24, 0x80C8},//freq_osc_in[1:0]00 0x80C8 >> 0x80CB\r
+ {0x27, 0x4925},//for ver.c20111109, txswitch\r
+ // {0x28, 0x80A1}, //BT_enable \r
+ {0x31, 0x8140},//enable wifi \r
+ {0x32, 0x0113},//set_ rdenout_ldooff_wf=0; rden4in_ldoon_wf=1 \r
+ // {0x39, 0x0004}, //uart switch to wf \r
+ {0x3F, 0x0000}, //page down\r
+};\r
+\r
+\r
+u16 wifi_dc_cal_data[][2]=\r
+{\r
+ {0x3f, 0x0000},\r
+ {0x30, 0x0248},\r
+ {0x30, 0x0249},\r
+ //{wait 200ms; } here\r
+};\r
+\r
+u16 wifi_dig_reset_data[][2]=\r
+{\r
+ {0x3F, 0x0001},\r
+ {0x31, 0x8D40},\r
+ {0x31, 0x8F40},\r
+ {0x31, 0x8b40},\r
+ {0x3F, 0x0000},\r
+};\r
+\r
+u16 wifi_rf_init_data_verE[][2] = \r
+{\r
+ {0x3f, 0x0000},\r
+ //{;;set_rf_swi},ch\r
+ {0x06, 0x0101},\r
+ {0x07, 0x0101},\r
+ {0x08, 0x0101},\r
+ {0x09, 0x0101},\r
+ {0x0A, 0x002C},//aain_0\r
+ {0x0D, 0x0507},\r
+ {0x0E, 0x2300},\r
+ {0x0F, 0x5689},//\r
+ //{;;//set_RF },\r
+ {0x10, 0x0f78},//20110824\r
+ {0x11, 0x0602},\r
+ {0x13, 0x0652},//adc_tuning_bit[011]\r
+ {0x14, 0x8886},\r
+ {0x15, 0x0990},\r
+ {0x16, 0x049f},\r
+ {0x17, 0x0990},\r
+ {0x18, 0x049F},\r
+ {0x19, 0x3C01},\r
+ {0x1C, 0x0934},\r
+ {0x1D, 0xFF00},//for ver.D20120119for temperature 70 degree\r
+ //{0x1F, 0x01F8},//for ver.c20111109\r
+ //{0x1F, 0x0300},//for burst tx 不锁\r
+ {0x20, 0x06E4},\r
+ {0x21, 0x0ACF},//for ver.c20111109,dr dac reset,dr txflt reset\r
+ {0x22, 0x24DC},\r
+ {0x23, 0x23FF},\r
+ {0x24, 0x00FC},\r
+ {0x26, 0x004F},//004F >> 005f premote pa \r
+ {0x27, 0x171D},///mdll*7\r
+ {0x28, 0x031D},///mdll*7\r
+ {0x2A, 0x2860},//et0x2849-8.5p :yd 0x2861-7pf C1,C2=6.8p\r
+ {0x2B, 0x0800},//bbpll,or ver.c20111116\r
+ {0x32, 0x8a08},\r
+ {0x33, 0x1D02},//liuyanan\r
+ //{;;//agc_gain},\r
+ {0x36, 0x02f4}, //00F8;//gain_7\r
+ {0x37, 0x01f4}, //0074;//aain_6\r
+ {0x38, 0x21d4}, //0014;//gain_5\r
+ {0x39, 0x25d4}, //0414;//aain_4\r
+ {0x3A, 0x2584}, //1804;//gain_3\r
+ {0x3B, 0x2dc4}, //1C04;//aain_2\r
+ {0x3C, 0x2d04}, //1C02;//gain_1\r
+ {0x3D, 0x2c02}, //3C01;//gain_0\r
+ {0x33, 0x1502},//liuyanan\r
+ //{;;SET_channe},_to_11\r
+ {0x1B, 0x0001},//set_channel \r
+ {0x30, 0x024D},\r
+ {0x29, 0xD468},\r
+ {0x29, 0x1468},\r
+ {0x30, 0x0249},\r
+ {0x3f, 0x0000},\r
+};\r
+\r
+u16 wifi_rf_init_data[][2] = \r
+{\r
+ {0x3f, 0x0000},\r
+ //{;;set_rf_swi},ch\r
+ {0x06, 0x0101},\r
+ {0x07, 0x0101},\r
+ {0x08, 0x0101},\r
+ {0x09, 0x0101},\r
+ {0x0A, 0x002C},//aain_0\r
+ {0x0D, 0x0507},\r
+ {0x0E, 0x2300},//2012_02_20 \r
+ {0x0F, 0x5689},//\r
+ //{;;//set_RF },\r
+ {0x10, 0x0f78},//20110824\r
+ {0x11, 0x0602},\r
+ {0x13, 0x0652},//adc_tuning_bit[011]\r
+ {0x14, 0x8886},\r
+ {0x15, 0x0990},\r
+ {0x16, 0x049f},\r
+ {0x17, 0x0990},\r
+ {0x18, 0x049F},\r
+ {0x19, 0x3C01},//sdm_vbit[3:0]=1111\r
+ {0x1C, 0x0934},\r
+ {0x1D, 0xFF00},//for ver.D20120119for temperature 70 degree 0xCE00 >> 0xFF00\r
+ {0x1F, 0x0300},//div2_band_48g_dr=1;div2_band_48g_reg[8:0]\r
+ {0x20, 0x06E4},\r
+ {0x21, 0x0ACF},//for ver.c20111109,dr dac reset,dr txflt reset\r
+ {0x22, 0x24DC},\r
+ {0x23, 0x23FF},\r
+ {0x24, 0x00FC},\r
+ {0x26, 0x004F},//004F >> 005f premote pa \r
+ {0x27, 0x171D},///mdll*7\r
+ {0x28, 0x031D},///mdll*7\r
+ {0x2A, 0x2860},//et0x2849-8.5p :yd 0x2861-7pf\r
+ {0x2B, 0x0800},//bbpll,or ver.c20111116\r
+ {0x32, 0x8a08},\r
+ {0x33, 0x1D02},//liuyanan\r
+ //{;;//agc_gain},\r
+ {0x36, 0x02f4}, //00F8;//gain_7\r
+ {0x37, 0x01f4}, //0074;//aain_6\r
+ {0x38, 0x21d4}, //0014;//gain_5\r
+ {0x39, 0x25d4}, //0414;//aain_4\r
+ {0x3A, 0x2584}, //1804;//gain_3\r
+ {0x3B, 0x2dc4}, //1C04;//aain_2\r
+ {0x3C, 0x2d04}, //1C02;//gain_1\r
+ {0x3D, 0x2c02}, //3C01;//gain_0\r
+ {0x33, 0x1502},//liuyanan\r
+ //{;;SET_channe},_to_11\r
+ {0x1B, 0x0001},//set_channel \r
+ {0x30, 0x024D},\r
+ {0x29, 0xD468},\r
+ {0x29, 0x1468},\r
+ {0x30, 0x0249},\r
+ {0x3f, 0x0000},\r
+};\r
+u16 wifi_uart_debug_data[][2] = \r
+{\r
+ {0x3F,0x0001},\r
+ {0x28,0x80A1}, //BT_enable \r
+ {0x39,0x0004}, //uart switch to wf\r
+ {0x3f,0x0000},\r
+};\r
+\r
+u16 wifi_tm_en_data[][2] =\r
+{\r
+ {0x3F,0x0001},\r
+#ifdef RDA5990_USE_DCDC /*houzhen update Mar 15 2012 */\r
+ {0x23, 0x8FA1},//20111001 higher AVDD voltage to improve EVM to 0x8f21 download current -1db 0x8fA1>>0x8bA1 \r
+#else\r
+ {0x23, 0x0FA1},\r
+#endif\r
+ {0x22,0xD3C7},//for ver.c 20111109, tx\r
+ {0x24, 0x80C8},//freq_osc_in[1:0]00 0x80C8 >> 0x80CB \r
+ {0x27,0x4925},//for ver.c20111109, txs\r
+ {0x28,0x80A1}, //BT_enable \r
+ {0x29,0x111F}, \r
+ {0x31,0x8140}, \r
+ {0x32,0x0113},//set_ rdenout_ldooff_wf\r
+ {0x39,0x0004},//uart switch to wf\r
+ {0x3f,0x0000},\r
+};\r
+\r
+u16 wifi_tm_rf_init_data[][2] = \r
+{\r
+ {0x3f, 0x0000},\r
+ //set_rf_switch \r
+ {0x06,0x0101}, \r
+ {0x07,0x0101}, \r
+ {0x08,0x0101}, \r
+ {0x09,0x0101}, \r
+ {0x0A,0x002C},//aain_0 \r
+ {0x0D, 0x0507}, \r
+ {0x0E,0x2300},//2012_02_20 \r
+ {0x0F,0x5689},// \r
+ //set_RF \r
+ {0x10,0x0f78},//20110824 \r
+ {0x11,0x0602}, \r
+ {0x13,0x0652},//adc_tuning_bit[011] \r
+ {0x14,0x8886}, \r
+ {0x15,0x0990}, \r
+ {0x16,0x049f}, \r
+ {0x17,0x0990}, \r
+ {0x18,0x049F}, \r
+ {0x19,0x3C01},//sdm_vbit[3:0]=1111 \r
+ {0x1C,0x0934}, \r
+ {0x1D,0xFF00},//for ver.D20120119for temperature 70 degree \r
+ {0x1F,0x0300},//div2_band_48g_dr=1;div2_band_48g_reg[8:0]1000000000\r
+ {0x20,0x06E4}, \r
+ {0x21,0x0ACF},//for ver.c20111109,dr dac reset,dr txflt reset \r
+ {0x22,0x24DC}, \r
+ {0x23,0x23FF}, \r
+ {0x24,0x00FC}, \r
+ {0x26,0x004F}, \r
+ {0x27,0x171D},///mdll*7 \r
+ {0x28,0x031D},///mdll*7 \r
+ {0x2A,0x2860}, \r
+ {0x2B,0x0800},//bbpll,or ver.c20111116 \r
+ {0x32,0x8a08}, \r
+ {0x33,0x1D02},//liuyanan \r
+ //agc_gain \r
+ {0x36,0x02f4}, //00F8;//gain_7 \r
+ {0x37,0x01f4}, //0074;//aain_6 \r
+ {0x38,0x21d4}, //0014;//gain_5 \r
+ {0x39,0x25d4}, //0414;//aain_4 \r
+ {0x3A,0x2584}, //1804;//gain_3 \r
+ {0x3B,0x2dc4}, //1C04;//aain_2 \r
+ {0x3C,0x2d04}, //1C02;//gain_1 \r
+ {0x3D,0x2c02}, //3C01;//gain_0 \r
+ //DC_CAL \r
+ {0x30,0x0248}, \r
+ {0x30,0x0249}, \r
+ //wait 200ms; \r
+ {0x33,0x1502},//liuyanan \r
+ //SET_channel_to_11 \r
+ {0x1B,0x0001},//set_channel \r
+ {0x3f,0x0000},\r
+};\r
+\r
+/*houzhen update Mar 15 2012\r
+ should be called when power up/down bt\r
+ */\r
+static int rda5990_wf_setup_A2_power(int enable)\r
+{\r
+ int ret;\r
+ u16 temp_data=0;\r
+ printk(KERN_INFO "***rda5990_wf_setup_A2_power start! \n");\r
+ ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x3f, 0x0001);\r
+ if(ret)\r
+ goto err;\r
+\r
+ if(enable)\r
+ {\r
+ ret=i2c_read_1_addr_2_data(rda_wifi_rf_client,0x22,&temp_data);\r
+ if(ret)\r
+ goto err;\r
+ printk(KERN_INFO "***0xA2 readback value:0x%X \n", temp_data);\r
+\r
+ temp_data |=0x0200; /*en reg4_pa bit*/\r
+#ifdef RDA5890_USE_CRYSTAL \r
+ temp_data &= ~(1 << 14); //disable xen_out\r
+#endif\r
+ ret=i2c_write_1_addr_2_data(rda_wifi_rf_client,0x22,temp_data);\r
+ if(ret)\r
+ goto err;\r
+ //read wlan version\r
+ ret = i2c_read_1_addr_2_data(rda_wifi_rf_client,0x21,&temp_data);\r
+ if(ret)\r
+ goto err;\r
+ else\r
+ wlan_version = temp_data;\r
+ }\r
+ else\r
+ {\r
+ ret=i2c_read_1_addr_2_data(rda_wifi_rf_client,0x28,&temp_data);\r
+ if(ret)\r
+ goto err;\r
+ if(temp_data&0x8000) // bt is on \r
+ {\r
+ goto out;\r
+ }\r
+ else\r
+ {\r
+ ret=i2c_read_1_addr_2_data(rda_wifi_rf_client,0x22,&temp_data);\r
+ if(ret)\r
+ goto err;\r
+ temp_data&=0xfdff;\r
+\r
+ ret=i2c_write_1_addr_2_data(rda_wifi_rf_client,0x22,temp_data);\r
+ if(ret)\r
+ goto err;\r
+ }\r
+ wlan_version = 0;\r
+ }\r
+\r
+out:\r
+ ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x3f, 0x0000);\r
+ if(ret)\r
+ goto err;\r
+ printk(KERN_INFO "***rda5990_wf_setup_A2_power succeed! \n");\r
+ return 0;\r
+\r
+err:\r
+ printk(KERN_INFO "***rda5990_wf_setup_A2_power failed! \n");\r
+ return -1;\r
+}\r
+\r
+\r
+int rda_wifi_rf_init(void)\r
+{\r
+ unsigned int count = 0;\r
+ int ret = 0;\r
+ \r
+ mutex_lock(&i2c_rw_lock);\r
+ if( (wlan_version&0x1f) == 7)\r
+ {\r
+ for(count = 0; count < sizeof(wifi_rf_init_data)/sizeof(wifi_rf_init_data[0]); count ++)\r
+ {\r
+ ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, wifi_rf_init_data[count][0], wifi_rf_init_data[count][1]);\r
+ if(ret)\r
+ goto err;\r
+ }\r
+ }\r
+ else if((wlan_version&0x1f) == 4 || (wlan_version&0x1f)==5)\r
+ {\r
+ for(count = 0; count < sizeof(wifi_rf_init_data_verE)/sizeof(wifi_rf_init_data_verE[0]); count ++)\r
+ {\r
+ ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, wifi_rf_init_data_verE[count][0], wifi_rf_init_data_verE[count][1]);\r
+ if(ret)\r
+ goto err;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ printk("unknown version of this 5990 chip\n");\r
+ goto err;\r
+ }\r
+ mutex_unlock(&i2c_rw_lock);\r
+ printk(KERN_INFO "***rda_wifi_rf_init_succceed \n");\r
+ msleep(5); //5ms delay\r
+ return 0;\r
+err:\r
+ mutex_unlock(&i2c_rw_lock);\r
+ printk(KERN_INFO "***rda_wifi_rf_init failed! \n");\r
+ return -1;\r
+}\r
+\r
+int rda_wifi_dc_cal(void)\r
+{\r
+ unsigned int count = 0;\r
+ int ret = 0;\r
+\r
+ mutex_lock(&i2c_rw_lock);\r
+ for(count = 0; count < sizeof(wifi_dc_cal_data)/sizeof(wifi_dc_cal_data[0]); count ++)\r
+ {\r
+ ret = i2c_write_1_addr_2_data(rda_wifi_rf_client ,wifi_dc_cal_data[count][0], wifi_dc_cal_data[count][1]);\r
+ if(ret)\r
+ goto err;\r
+ }\r
+\r
+ mutex_unlock(&i2c_rw_lock);\r
+ printk(KERN_INFO "***rda_wifi_rf_dc_calsuccceed \n");\r
+ msleep(50); //50ms delay\r
+ return 0;\r
+\r
+err:\r
+ mutex_unlock(&i2c_rw_lock);\r
+ printk(KERN_INFO "***rda_wifi_rf_dc_calf_failed! \n");\r
+ return -1;\r
+}\r
+\r
+int rda_wifi_en(void)\r
+{\r
+ unsigned int count = 0;\r
+ int ret = 0;\r
+\r
+ mutex_lock(&i2c_rw_lock); \r
+ for(count = 0; count < sizeof(wifi_en_data)/sizeof(wifi_en_data[0]); count ++)\r
+ {\r
+ ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, wifi_en_data[count][0], wifi_en_data[count][1]);\r
+ if(ret)\r
+ goto err;\r
+ if(wifi_en_data[count][0] == 0x31)\r
+ msleep(10); //10ms delay\r
+ }\r
+\r
+ ret=rda5990_wf_setup_A2_power(1); //en pa_reg for wf\r
+ if(ret)\r
+ goto err;\r
+\r
+ mutex_unlock(&i2c_rw_lock);\r
+ msleep(8); //8ms delay\r
+\r
+ printk(KERN_INFO "***rda_wifi_en_succceed \n");\r
+ return 0;\r
+err:\r
+ mutex_unlock(&i2c_rw_lock);\r
+ printk(KERN_INFO "***rda_wifi_power_on failed! \n");\r
+ return -1;\r
+}\r
+\r
+int rda_wifi_debug_en(void)\r
+{\r
+ unsigned int count = 0;\r
+ int ret = 0;\r
+ \r
+ mutex_lock(&i2c_rw_lock); \r
+ for(count = 0; count < sizeof(wifi_uart_debug_data)/sizeof(wifi_uart_debug_data[0]); count ++)\r
+ {\r
+ ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, wifi_uart_debug_data[count][0], wifi_uart_debug_data[count][1]);\r
+ if(ret)\r
+ goto err;\r
+ }\r
+\r
+err:\r
+ mutex_unlock(&i2c_rw_lock);\r
+ return ret;\r
+}\r
+\r
+int rda_tm_wifi_en(void)\r
+{\r
+ unsigned int count = 0;\r
+ int ret = 0;\r
+ unsigned short temp_data;\r
+\r
+ for(count = 0; count < sizeof(wifi_tm_en_data)/sizeof(wifi_tm_en_data[0]); count ++)\r
+ {\r
+ ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, wifi_tm_en_data[count][0], wifi_tm_en_data[count][1]);\r
+ if(ret)\r
+ goto err;\r
+ }\r
+\r
+ msleep(8); //8ms delay\r
+ ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x3f, 0x0001); //PAGE UP\r
+ if(ret)\r
+ goto err;\r
+ \r
+ ret = i2c_read_1_addr_2_data(rda_wifi_rf_client,0x21,&temp_data);\r
+ if(ret)\r
+ goto err;\r
+ else\r
+ wlan_version = temp_data;\r
+\r
+ ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x3f, 0x0000); //PAGE DOWN\r
+ if(ret)\r
+ goto err;\r
+ \r
+\r
+ printk(KERN_INFO "***rda_wifi_en_succceed \n");\r
+ return 0;\r
+err:\r
+ printk(KERN_INFO "***rda_wifi_power_on failed! \n");\r
+ return -1;\r
+}\r
+\r
+int rda_tm_wifi_rf_init(void)\r
+{\r
+ unsigned int count = 0;\r
+ int ret = 0;\r
+\r
+ for(count = 0; count < sizeof(wifi_tm_rf_init_data)/sizeof(wifi_tm_rf_init_data[0]); count ++)\r
+ {\r
+ ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, wifi_tm_rf_init_data[count][0], wifi_tm_rf_init_data[count][1]);\r
+ if(ret)\r
+ goto err;\r
+ }\r
+\r
+ printk(KERN_INFO "***rda_wifi_rf_init_succceed \n");\r
+ msleep(5); //5ms delay\r
+ return 0;\r
+\r
+err:\r
+ printk(KERN_INFO "***rda_wifi_rf_init failed! \n");\r
+ return -1;\r
+}\r
+/*houzhen add 2012 04 09\r
+ add to ensure wf dig powerup\r
+ */\r
+\r
+int rda_wifi_dig_reset(void)\r
+{\r
+ unsigned int count = 0;\r
+ int ret = 0;\r
+ msleep(8); //8ms delay\r
+ mutex_lock(&i2c_rw_lock);\r
+\r
+ for(count = 0; count < sizeof(wifi_dig_reset_data)/sizeof(wifi_dig_reset_data[0]); count ++)\r
+ {\r
+ ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, wifi_dig_reset_data[count][0], wifi_dig_reset_data[count][1]);\r
+ if(ret)\r
+ goto err;\r
+ }\r
+\r
+ mutex_unlock(&i2c_rw_lock);\r
+ msleep(8); //8ms delay\r
+ printk(KERN_INFO "***rda_wifi_dig_reset \n");\r
+ return 0;\r
+err:\r
+ mutex_unlock(&i2c_rw_lock);\r
+ printk(KERN_INFO "***rda_wifi_dig_reset failed! \n"); \r
+ return -1;\r
+}\r
+\r
+int rda_wlan_version(void)\r
+{\r
+ printk("******version %x \n", wlan_version);\r
+ return wlan_version;\r
+}\r
+\r
+int rda_wifi_power_off(void)\r
+{\r
+ unsigned int count = 0;\r
+ int ret = 0;\r
+ u16 temp=0x0000;\r
+ printk(KERN_INFO "rda_wifi_power_off \n");\r
+\r
+ if(!rda_wifi_rf_client)\r
+ {\r
+ printk(KERN_INFO "rda_wifi_power_off failed on:i2c client \n");\r
+ return -1;\r
+ }\r
+\r
+ mutex_lock(&i2c_rw_lock);\r
+ ret=rda5990_wf_setup_A2_power(0); //disable pa_reg for wf\r
+ if(ret)\r
+ goto err;\r
+\r
+ ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x3f, 0x0001); //page up\r
+ if(ret)\r
+ goto err;\r
+\r
+ ret=i2c_read_1_addr_2_data(rda_wifi_rf_client,0x28,&temp); //poll bt status\r
+ if(ret)\r
+ goto err;\r
+\r
+ if(temp&0x8000)\r
+ {\r
+ ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x3f, 0x0000); //page down\r
+ if(ret)\r
+ goto err;\r
+\r
+ ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x0f, 0x2223); // set antenna for bt\r
+ if(ret)\r
+ goto err;\r
+\r
+ }\r
+\r
+ for(count = 0; count < sizeof(wifi_off_data)/sizeof(wifi_off_data[0]); count ++)\r
+ {\r
+ ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, wifi_off_data[count][0], wifi_off_data[count][1]);\r
+ if(ret)\r
+ goto err;\r
+ }\r
+ printk(KERN_INFO "***rda_wifi_power_off success!!! \n");\r
+\r
+\r
+\r
+ mutex_unlock(&i2c_rw_lock);\r
+ return 0;\r
+\r
+err:\r
+ mutex_unlock(&i2c_rw_lock);\r
+ printk(KERN_INFO "***rda_wifi_power_off failed! \n");\r
+ return -1;\r
+\r
+}\r
+\r
+int rda_wifi_power_on(void)\r
+{\r
+ int ret;\r
+ char retry = 3;\r
+\r
+ printk("------------------rda_wifi_power_on\n");\r
+ if(!rda_wifi_rf_client)\r
+ {\r
+ printk(KERN_INFO "rda_wifi_power_on failed on:i2c client \n");\r
+ return -1;\r
+ }\r
+\r
+_retry: \r
+\r
+\r
+ if(!wifi_in_test_mode)\r
+ {\r
+ ret = rda_wifi_en(); \r
+ if(ret < 0)\r
+ goto err;\r
+\r
+ ret = rda_wifi_rf_init(); \r
+ if(ret < 0)\r
+ goto err;\r
+\r
+ ret = rda_wifi_dc_cal(); \r
+ if(ret < 0)\r
+ goto err;\r
+\r
+ msleep(20); //20ms delay\r
+ ret=rda_wifi_dig_reset(); //houzhen add to ensure wf power up safely\r
+\r
+ if(ret < 0)\r
+ goto err;\r
+ msleep(20); //20ms delay\r
+ }\r
+ else\r
+ {\r
+ ret = rda_tm_wifi_en();\r
+ if(ret < 0)\r
+ goto err;\r
+\r
+ ret = rda_tm_wifi_rf_init();\r
+ if(ret < 0)\r
+ goto err;\r
+ }\r
+ printk(KERN_INFO "rda_wifi_power_on_succeed!! \n");\r
+\r
+ return 0;\r
+\r
+err:\r
+ printk(KERN_INFO "rda_wifi_power_on_failed retry:%d \n", retry);\r
+ if(retry -- > 0)\r
+ { \r
+ rda_wifi_power_off();\r
+ goto _retry;\r
+ }\r
+\r
+ return -1;\r
+}\r
+\r
+extern int rda_wifi_power_on(void);\r
+\r
+int rda_fm_power_on(void)\r
+{\r
+ int ret = 0;\r
+ u16 temp = 0;\r
+\r
+ if(!rda_wifi_rf_client)\r
+ {\r
+ printk(KERN_INFO "rda_wifi_rf_client is NULL, rda_fm_power_on failed!\n");\r
+ return -1;\r
+ }\r
+\r
+ ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x3f, 0x0001); // page down\r
+ if(ret < 0){\r
+ printk(KERN_INFO "%s() write address(0x%02x) with value(0x%04x) failed! \n", __func__, 0x3f, 0x0001);\r
+ return -1;\r
+ }\r
+ ret = i2c_read_1_addr_2_data(rda_wifi_rf_client, 0x22, &temp); //read 0xA2\r
+ if(ret < 0){\r
+ printk(KERN_INFO "%s() read from address(0x%02x) failed! \n", __func__, 0x22);\r
+ return -1;\r
+ }\r
+ temp = temp & (~(1 << 15)); //clear bit[15]\r
+ ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x22, temp); //write back\r
+ if(ret < 0){\r
+ printk(KERN_INFO "%s() write address(0x%02x) with value(0x%04x) failed! \n", __func__, 0x3f, 0x0001);\r
+ return -1;\r
+ }\r
+ ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x3f, 0x0000); // page up\r
+ if(ret < 0){\r
+ printk(KERN_INFO "%s() write address(0x%02x) with value(0x%04x) failed! \n", __func__, 0x3f, 0x0001);\r
+ return -1;\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+int rda_fm_power_off(void)\r
+{\r
+ int ret = 0;\r
+ u16 temp = 0;\r
+\r
+ if(!rda_wifi_rf_client)\r
+ {\r
+ printk(KERN_INFO "rda_wifi_rf_client is NULL, rda_fm_power_off failed!\n");\r
+ return -1;\r
+ }\r
+\r
+ ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x3f, 0x0001); // page down\r
+ if(ret < 0){\r
+ printk(KERN_INFO "%s() write address(0x%02x) with value(0x%04x) failed! \n", __func__, 0x3f, 0x0001);\r
+ return -1;\r
+ }\r
+ ret = i2c_read_1_addr_2_data(rda_wifi_rf_client, 0x22, &temp); //read 0xA2\r
+ if(ret < 0){\r
+ printk(KERN_INFO "%s() read from address(0x%02x) failed! \n", __func__, 0x22);\r
+ return -1;\r
+ }\r
+ temp = temp | (1 << 15); //set bit[15]\r
+ ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x22, temp); //write back\r
+ if(ret < 0){\r
+ printk(KERN_INFO "%s() write address(0x%02x) with value(0x%04x) failed! \n", __func__, 0x3f, 0x0001);\r
+ return -1;\r
+ }\r
+ ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, 0x3f, 0x0000); // page up\r
+ if(ret < 0){\r
+ printk(KERN_INFO "%s() write address(0x%02x) with value(0x%04x) failed! \n", __func__, 0x3f, 0x0001);\r
+ return -1;\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+static int rda_bt_rf_probe(struct i2c_client *client, const struct i2c_device_id *id)\r
+{\r
+ int result = 0;\r
+\r
+ rda_bt_rf_client = client;\r
+ return result;\r
+}\r
+\r
+static int rda_bt_rf_remove(struct i2c_client *client)\r
+{\r
+ rda_bt_rf_client = NULL;\r
+ return 0;\r
+}\r
+\r
+static int rda_bt_rf_detect(struct i2c_client *client, int kind, struct i2c_board_info *info)\r
+{ \r
+ strcpy(info->type, RDA_BT_RF_I2C_DEVNAME); \r
+ return 0; \r
+}\r
+\r
+static struct i2c_driver rda_bt_rf_driver = {\r
+ .probe = rda_bt_rf_probe,\r
+ .remove = rda_bt_rf_remove,\r
+ .detect = rda_bt_rf_detect,\r
+ .driver.name = RDA_BT_RF_I2C_DEVNAME,\r
+ .id_table = bt_rf_i2c_id,\r
+ //.address_data = &rda_bt_rf_addr_data,\r
+ //.address_list = (const unsigned short*)bt_rf_force,\r
+};\r
+\r
+\r
+static int rda_bt_core_detect(struct i2c_client *client, int kind, struct i2c_board_info *info)\r
+{\r
+ strcpy(info->type, RDA_BT_CORE_I2C_DEVNAME);\r
+ return 0; \r
+}\r
+\r
+static int rda_bt_core_probe(struct i2c_client *client, const struct i2c_device_id *id)\r
+{\r
+ int result = 0;\r
+\r
+ rda_bt_core_client = client;\r
+ return result;\r
+}\r
+\r
+static int rda_bt_core_remove(struct i2c_client *client)\r
+{\r
+ return 0;\r
+}\r
+\r
+static struct i2c_driver rda_bt_core_driver = {\r
+ .probe = rda_bt_core_probe,\r
+ .remove = rda_bt_core_remove,\r
+ .detect = rda_bt_core_detect,\r
+ .driver.name = RDA_BT_CORE_I2C_DEVNAME,\r
+ .id_table = bt_core_i2c_id,\r
+ //.address_data = &rda_bt_core_addr_data,\r
+ //.address_list = (const unsigned short*)bt_core_force,\r
+};\r
+\r
+u16 rda_5990_bt_off_data[][2] = \r
+{\r
+ {0x3f, 0x0001 }, //pageup\r
+ {0x28, 0x00A1 }, //power off bt\r
+ {0x3f, 0x0000 }, //pagedown\r
+};\r
+\r
+/*houzhen update 2012 03 06*/\r
+u16 rda_5990_bt_en_data[][2] = \r
+{\r
+ {0x3f, 0x0001 }, //pageup\r
+#ifdef RDA5990_USE_DCDC \r
+ {0x23, 0x8FA1}, // //20111001 higher AVDD voltage to improve EVM\r
+#else\r
+ {0x23, 0x0FA1},\r
+#endif \r
+ {0x24, 0x80C8}, // ;//freq_osc_in[1:0]00 \r
+ {0x26, 0x47A5}, // reg_vbit_normal_bt[2:0] =111\r
+ {0x27, 0x4925}, // //for ver.c20111109, txswitch\r
+ {0x29, 0x111F}, // // rden4in_ldoon_bt=1 \r
+ {0x32, 0x0111}, // set_ rdenout_ldooff_wf=0; \r
+ {0x39, 0x0000}, // //uart switch to bt\r
+\r
+ {0x28, 0x80A1}, // bt en\r
+ {0x3f, 0x0000}, //pagedown\r
+};\r
+\r
+\r
+u16 rda_5990_bt_dc_cal[][2] = \r
+{\r
+ {0x3f, 0x0000 }, \r
+ {0x30, 0x0129 },\r
+ {0x30, 0x012B },\r
+ {0x3f, 0x0000 }, \r
+};\r
+\r
+\r
+u16 rda_5990_bt_set_rf_switch_data[][2] = \r
+{\r
+ {0x3f, 0x0000 }, \r
+ {0x0F, 0x2223 },\r
+ {0x3f, 0x0000 }, \r
+};\r
+\r
+\r
+u16 RDA5990_bt_enable_clk_data[][2] = \r
+{\r
+ {0x3f, 0x0000 }, \r
+ {0x30, 0x0040 },\r
+ {0x2a, 0x285d },\r
+ {0x3f, 0x0000 }, \r
+};\r
+\r
+u16 RDA5990_bt_dig_reset_data[][2] = \r
+{\r
+ {0x3f, 0x0001 }, //pageup\r
+ {0x28, 0x86A1 },\r
+ {0x28, 0x87A1 },\r
+ {0x28, 0x85A1 },\r
+ {0x3f, 0x0000 }, //pagedown\r
+};\r
+\r
+/*houzhen update 2012 03 06*/\r
+u16 rda_5990_bt_rf_data[][2] = \r
+{\r
+ {0x3f, 0x0000}, //pagedown\r
+ {0x01, 0x1FFF},\r
+ {0x06, 0x07F7},\r
+ {0x08, 0x29E7},\r
+ {0x09, 0x0520},\r
+ {0x0B, 0x03DF},\r
+ {0x0C, 0x85E8},\r
+ {0x0F, 0x0DBC},\r
+ {0x12, 0x07F7},\r
+ {0x13, 0x0327},\r
+ {0x14, 0x0CCC},\r
+ {0x15, 0x0526},\r
+ {0x16, 0x8918},\r
+ {0x18, 0x8800},\r
+ {0x19, 0x10C8},\r
+ {0x1A, 0x9078},\r
+ {0x1B, 0x80E2},\r
+ {0x1C, 0x361F},\r
+ {0x1D, 0x4363},\r
+ {0x1E, 0x303F},\r
+ {0x23, 0x2222},\r
+ {0x24, 0x359D},\r
+ {0x27, 0x0011},\r
+ {0x28, 0x124F},\r
+ {0x39, 0xA5FC},\r
+ {0x3f, 0x0001}, //page 1\r
+ {0x00, 0x043F},\r
+ {0x01, 0x467F},\r
+ {0x02, 0x28FF},\r
+ {0x03, 0x67FF},\r
+ {0x04, 0x57FF},\r
+ {0x05, 0x7BFF},\r
+ {0x06, 0x3FFF},\r
+ {0x07, 0x7FFF},\r
+ {0x18, 0xF3F5},\r
+ {0x19, 0xF3F5},\r
+ {0x1A, 0xE7F3},\r
+ {0x1B, 0xF1FF},\r
+ {0x1C, 0xFFFF},\r
+ {0x1D, 0xFFFF},\r
+ {0x1E, 0xFFFF},\r
+ {0x1F, 0xFFFF},\r
+ // {0x22, 0xD3C7}, \r
+ // {0x23, 0x8fa1},\r
+ // {0x24, 0x80c8},\r
+ // {0x26, 0x47A5},\r
+ // {0x27, 0x4925},\r
+ // {0x28, 0x85a1},\r
+ // {0x29, 0x111f},\r
+ // {0x32, 0x0111},\r
+ // {0x39, 0x0000},\r
+ {0x3f, 0x0000}, //pagedown\r
+};\r
+\r
+/*houzhen update Mar 15 2012\r
+ should be called when power up/down bt\r
+ */\r
+static int rda5990_bt_setup_A2_power(int enable)\r
+{\r
+ int ret;\r
+ u16 temp_data=0;\r
+\r
+ ret = i2c_write_1_addr_2_data(rda_bt_rf_client, 0x3f, 0x0001);\r
+ if(ret)\r
+ goto err;\r
+\r
+ if(enable)\r
+ {\r
+ ret=i2c_read_1_addr_2_data(rda_bt_rf_client,0x22,&temp_data);\r
+ if(ret)\r
+ goto err;\r
+ printk(KERN_INFO "***0xA2 readback value:0x%X \n", temp_data);\r
+\r
+ temp_data |=0x0200; /*en reg4_pa bit*/\r
+\r
+ ret=i2c_write_1_addr_2_data(rda_bt_rf_client,0x22,temp_data);\r
+ if(ret)\r
+ goto err; \r
+ }\r
+ else\r
+ {\r
+ ret=i2c_read_1_addr_2_data(rda_bt_rf_client,0x31,&temp_data);\r
+ if(ret)\r
+ goto err;\r
+\r
+ if(temp_data&0x8000) // wf is on \r
+ {\r
+ goto out;\r
+ }\r
+ else\r
+ {\r
+ ret=i2c_read_1_addr_2_data(rda_bt_rf_client,0x22,&temp_data);\r
+ if(ret)\r
+ goto err;\r
+ temp_data&=0xfdff;\r
+\r
+ ret=i2c_write_1_addr_2_data(rda_bt_rf_client,0x22,temp_data);\r
+ if(ret)\r
+ goto err;\r
+ }\r
+\r
+ }\r
+\r
+out:\r
+ ret = i2c_write_1_addr_2_data(rda_bt_rf_client, 0x3f, 0x0000);\r
+ if(ret)\r
+ goto err;\r
+ return 0;\r
+\r
+err:\r
+ printk(KERN_INFO "***rda5990_bt_setup_A2_power failed! \n");\r
+ return -1;\r
+}\r
+\r
+int rda_bt_power_off(void);\r
+\r
+int rda_bt_power_on(void)\r
+{\r
+ unsigned int count = 0;\r
+ int ret = 0;\r
+\r
+ printk(KERN_INFO "rda_bt_power_on \n");\r
+\r
+ if(!rda_bt_rf_client || !rda_bt_rf_client)\r
+ {\r
+ printk(KERN_INFO "rda_bt_power_on failed on:i2c client \n");\r
+ return -1;\r
+ }\r
+\r
+ mutex_lock(&i2c_rw_lock);\r
+\r
+ for(count = 0; count < sizeof(rda_5990_bt_en_data)/sizeof(rda_5990_bt_en_data[0]); count ++)\r
+ {\r
+ ret = i2c_write_1_addr_2_data(rda_bt_rf_client, rda_5990_bt_en_data[count][0], rda_5990_bt_en_data[count][1]);\r
+ if(ret)\r
+ goto err;\r
+ }\r
+\r
+ ret=rda5990_bt_setup_A2_power(1); \r
+ if(ret)\r
+ { \r
+ printk(KERN_INFO "***rda5990_bt_setup_A2_power fail!!! \n");\r
+ goto err;\r
+ }\r
+\r
+ printk(KERN_INFO "***rda_bt_power_on success!!! \n");\r
+\r
+ mutex_unlock(&i2c_rw_lock);\r
+ /*houzhen update 2012 03 06*/\r
+ msleep(10); //delay 10 ms after power on\r
+\r
+ return 0;\r
+\r
+err:\r
+ mutex_unlock(&i2c_rw_lock);\r
+ printk(KERN_INFO "***rda_bt_power_on failed! \n");\r
+ return -1;\r
+\r
+}\r
+\r
+int rda_bt_power_off(void)\r
+{\r
+ unsigned int count = 0;\r
+ int ret = 0;\r
+ printk(KERN_INFO "rda_bt_power_off \n");\r
+\r
+ if(!rda_bt_rf_client)\r
+ {\r
+ printk(KERN_INFO "rda_bt_power_off failed on:i2c client \n");\r
+ return -1;\r
+ }\r
+\r
+ mutex_lock(&i2c_rw_lock);\r
+ for(count = 0; count < sizeof(rda_5990_bt_off_data)/sizeof(rda_5990_bt_off_data[0]); count ++)\r
+ {\r
+ ret = i2c_write_1_addr_2_data(rda_bt_rf_client ,rda_5990_bt_off_data[count][0], rda_5990_bt_off_data[count][1]);\r
+ if(ret)\r
+ goto err;\r
+ }\r
+ msleep(10); //10ms\r
+ printk(KERN_INFO "***rda_bt_power_off success!!! \n");\r
+\r
+ ret=rda5990_bt_setup_A2_power(0);//disable ldo_pa reg \r
+ if(ret)\r
+ goto err;\r
+\r
+\r
+\r
+ mutex_unlock(&i2c_rw_lock); \r
+ return 0;\r
+\r
+err:\r
+ mutex_unlock(&i2c_rw_lock);\r
+ printk(KERN_INFO "***rda_bt_power_off failed! \n");\r
+ return -1;\r
+\r
+}\r
+\r
+\r
+int RDA5990_bt_rf_init(void)\r
+{\r
+ unsigned int count = 0;\r
+ int ret = 0;\r
+ printk(KERN_INFO "RDA5990_bt_rf_init \n");\r
+\r
+ if(!rda_bt_rf_client)\r
+ {\r
+ printk(KERN_INFO "RDA5990_bt_rf_init on:i2c client \n");\r
+ return -1;\r
+ }\r
+\r
+ mutex_lock(&i2c_rw_lock);\r
+ for(count = 0; count < sizeof(rda_5990_bt_rf_data)/sizeof(rda_5990_bt_rf_data[0]); count ++)\r
+ {\r
+ ret = i2c_write_1_addr_2_data(rda_bt_rf_client, rda_5990_bt_rf_data[count][0], rda_5990_bt_rf_data[count][1]);\r
+ if(ret)\r
+ goto err;\r
+ }\r
+\r
+ mutex_unlock(&i2c_rw_lock);\r
+ printk(KERN_INFO "***RDA5990_bt_rf_init success!!! \n");\r
+ msleep(5); //5ms\r
+ return 0;\r
+\r
+err:\r
+ mutex_unlock(&i2c_rw_lock);\r
+ printk(KERN_INFO "***RDA5990_bt_rf_init failed! \n");\r
+ return -1;\r
+\r
+}\r
+\r
+/*houzhen add 2012 04 09\r
+ add to ensure bt dig powerup\r
+ */\r
+\r
+int RDA5990_bt_dig_reset(void)\r
+{\r
+ unsigned int count = 0;\r
+ int ret = 0;\r
+\r
+ printk(KERN_INFO "RDA5990_bt_dig_reset \n");\r
+ if(!rda_bt_rf_client)\r
+ {\r
+ printk(KERN_INFO "RDA5990_bt_dig_reset on:i2c client \n");\r
+ return -1;\r
+ }\r
+\r
+ mutex_lock(&i2c_rw_lock);\r
+ for(count = 0; count < sizeof(RDA5990_bt_dig_reset_data)/sizeof(RDA5990_bt_dig_reset_data[0]); count ++)\r
+ {\r
+ ret = i2c_write_1_addr_2_data(rda_bt_rf_client, RDA5990_bt_dig_reset_data[count][0], RDA5990_bt_dig_reset_data[count][1]);\r
+ if(ret)\r
+ goto err;\r
+ }\r
+\r
+ mutex_unlock(&i2c_rw_lock);\r
+ printk(KERN_INFO "***RDA5990_bt_rf_init success!!! \n");\r
+ msleep(5); //5ms\r
+ return 0;\r
+\r
+err:\r
+ mutex_unlock(&i2c_rw_lock);\r
+ printk(KERN_INFO "***RDA5990_bt_rf_init failed! \n");\r
+ return -1;\r
+\r
+}\r
+\r
+\r
+int RDA5990_bt_dc_cal(void)\r
+{\r
+ unsigned int count = 0;\r
+ int ret = 0;\r
+ printk(KERN_INFO "rda_bt_dc_cal \n");\r
+\r
+ if(!rda_bt_rf_client)\r
+ {\r
+ printk(KERN_INFO "rda_bt_rf_client \n");\r
+ return -1;\r
+ }\r
+ mutex_lock(&i2c_rw_lock);\r
+\r
+ for(count = 0; count < sizeof(rda_5990_bt_dc_cal)/sizeof(rda_5990_bt_dc_cal[0]); count ++)\r
+ {\r
+ ret = i2c_write_1_addr_2_data(rda_bt_rf_client, rda_5990_bt_dc_cal[count][0], rda_5990_bt_dc_cal[count][1]);\r
+ if(ret)\r
+ goto err;\r
+ }\r
+\r
+ mutex_unlock(&i2c_rw_lock);\r
+ printk(KERN_INFO "***rda_bt_dc_cal success!!! \n");\r
+ msleep(200); //200ms\r
+\r
+ return 0;\r
+\r
+err:\r
+ mutex_unlock(&i2c_rw_lock);\r
+ printk(KERN_INFO "***rda_bt_dc_cal failed! \n");\r
+ return -1;\r
+\r
+}\r
+\r
+\r
+\r
+/*houzhen update Mar 15 2012 \r
+ bypass RDA5990_bt_set_rf_switch when wf is already on\r
+ */\r
+\r
+int RDA5990_bt_set_rf_switch(void)\r
+{\r
+ unsigned int count = 0;\r
+ int ret = 0;\r
+ u16 temp_data=0;\r
+ printk(KERN_INFO "RDA5990_bt_set_rf_switch \n");\r
+\r
+ if(!rda_bt_rf_client || !rda_wifi_rf_client)\r
+ {\r
+ printk(KERN_INFO "RDA5990_bt_set_rf_switch failed on:i2c client \n");\r
+ return -1;\r
+ }\r
+\r
+ mutex_lock(&i2c_rw_lock);\r
+\r
+ ret = i2c_write_1_addr_2_data(rda_bt_rf_client, 0x3f, 0x0001);\r
+ if(ret)\r
+ goto err; \r
+\r
+ ret=i2c_read_1_addr_2_data(rda_bt_rf_client,0x31,&temp_data); \r
+\r
+ if(ret)\r
+ goto err; \r
+\r
+ if(temp_data&0x8000) // if wf is already on\r
+ {\r
+ printk(KERN_INFO "wf already en, bypass RDA5990_bt_set_rf_switch function \n");\r
+ ret = i2c_write_1_addr_2_data(rda_bt_rf_client, 0x3f, 0x0000);\r
+ if(ret)\r
+ goto err; \r
+ mutex_unlock(&i2c_rw_lock); \r
+ return 0;\r
+ }\r
+\r
+ for(count = 0; count < sizeof(rda_5990_bt_set_rf_switch_data)/sizeof(rda_5990_bt_set_rf_switch_data[0]); count ++)\r
+ {\r
+ ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, rda_5990_bt_set_rf_switch_data[count][0], rda_5990_bt_set_rf_switch_data[count][1]);\r
+ if(ret)\r
+ goto err; \r
+ }\r
+\r
+ mutex_unlock(&i2c_rw_lock);\r
+ printk(KERN_INFO "***RDA5990_bt_set_rf_switch success!!! \n");\r
+ msleep(50); //50ms\r
+ return 0;\r
+\r
+err:\r
+ mutex_unlock(&i2c_rw_lock);\r
+ printk(KERN_INFO "***RDA5990_bt_set_rf_switch failed! \n");\r
+ return -1;\r
+\r
+}\r
+\r
+\r
+/*houzhen update Mar 15 2012 \r
+ bypass RDA5990_bt_enable_clk when wf is already on\r
+ */\r
+\r
+int RDA5990_bt_enable_clk(void)\r
+{\r
+ unsigned int count = 0;\r
+ int ret = 0;\r
+ u16 temp_data=0;\r
+ printk(KERN_INFO "RDA5990_bt_enable_clk \n");\r
+\r
+ if(!rda_bt_rf_client)\r
+ {\r
+ printk(KERN_INFO "RDA5990_bt_enable_clk failed on:i2c client \n");\r
+ return -1;\r
+ }\r
+\r
+ mutex_lock(&i2c_rw_lock);\r
+ ret = i2c_write_1_addr_2_data(rda_bt_rf_client, 0x3f, 0x0001);\r
+ if(ret)\r
+ goto err; \r
+\r
+ ret=i2c_read_1_addr_2_data(rda_bt_rf_client,0x31,&temp_data); \r
+\r
+ if(ret)\r
+ goto err; \r
+\r
+ if(temp_data&0x8000) // if wf is already on\r
+ {\r
+ printk(KERN_INFO "wf already en, bypass RDA5990_bt_enable_clk function \n");\r
+ ret = i2c_write_1_addr_2_data(rda_bt_rf_client, 0x3f, 0x0000);\r
+ if(ret)\r
+ goto err; \r
+ mutex_unlock(&i2c_rw_lock);\r
+ return 0;\r
+ }\r
+\r
+\r
+ for(count = 0; count < sizeof(RDA5990_bt_enable_clk_data)/sizeof(RDA5990_bt_enable_clk_data[0]); count ++)\r
+ {\r
+ ret = i2c_write_1_addr_2_data(rda_wifi_rf_client, RDA5990_bt_enable_clk_data[count][0], RDA5990_bt_enable_clk_data[count][1]);\r
+ if(ret)\r
+ goto err; \r
+ }\r
+\r
+ mutex_unlock(&i2c_rw_lock);\r
+ printk(KERN_INFO "***RDA5990_bt_enable_clk success!!! \n");\r
+ msleep(50); //50ms\r
+ return 0;\r
+\r
+err:\r
+ mutex_unlock(&i2c_rw_lock);\r
+ printk(KERN_INFO "***RDA5990_bt_enable_clk failed! \n");\r
+ return -1;\r
+\r
+}\r
+\r
+//extern void mt_combo_bgf_enable_irq(void);\r
+//extern void mt_combo_bgf_disable_irq(void);\r
+\r
+#define RDA_BT_IOCTL_MAGIC 'u'\r
+#define RDA_BT_POWER_ON_IOCTL _IO(RDA_BT_IOCTL_MAGIC ,0x01)\r
+#define RD_BT_RF_INIT_IOCTL _IO(RDA_BT_IOCTL_MAGIC ,0x02)\r
+#define RD_BT_DC_CAL_IOCTL _IO(RDA_BT_IOCTL_MAGIC ,0x03)\r
+#define RD_BT_SET_RF_SWITCH_IOCTL _IO(RDA_BT_IOCTL_MAGIC ,0x04)\r
+#define RDA_BT_POWER_OFF_IOCTL _IO(RDA_BT_IOCTL_MAGIC ,0x05)\r
+#define RDA_BT_EN_CLK _IO(RDA_BT_IOCTL_MAGIC ,0x06)\r
+#define RD_BT_DC_DIG_RESET_IOCTL _IO(RDA_BT_IOCTL_MAGIC ,0x07)\r
+\r
+#define RDA_WIFI_POWER_ON_IOCTL _IO(RDA_BT_IOCTL_MAGIC ,0x10)\r
+#define RDA_WIFI_POWER_OFF_IOCTL _IO(RDA_BT_IOCTL_MAGIC ,0x11)\r
+#define RDA_WIFI_POWER_SET_TEST_MODE_IOCTL _IO(RDA_BT_IOCTL_MAGIC ,0x12)\r
+#define RDA_WIFI_POWER_CANCEL_TEST_MODE_IOCTL _IO(RDA_BT_IOCTL_MAGIC ,0x13)\r
+#define RDA_WIFI_DEBUG_MODE_IOCTL _IO(RDA_BT_IOCTL_MAGIC ,0x14)\r
+\r
+extern int rk29sdk_wifi_set_carddetect(int val);\r
+static int rda_5990_pw_ioctl(struct file *file, unsigned int cmd, unsigned long arg)\r
+{\r
+ int ret = 0;\r
+\r
+ switch(cmd)\r
+ {\r
+ case RDA_WIFI_POWER_ON_IOCTL:\r
+ rda_wifi_power_on();\r
+ rk29sdk_wifi_set_carddetect(1);\r
+ break;\r
+\r
+ case RDA_WIFI_POWER_OFF_IOCTL:\r
+ rk29sdk_wifi_set_carddetect(0);\r
+ rda_wifi_power_off();\r
+ break;\r
+\r
+ case RDA_WIFI_POWER_SET_TEST_MODE_IOCTL:\r
+ wifi_in_test_mode = 1;\r
+ printk("****set rda wifi in test mode");\r
+ break;\r
+\r
+ case RDA_WIFI_POWER_CANCEL_TEST_MODE_IOCTL:\r
+ wifi_in_test_mode = 0;\r
+ printk("****set rda wifi in normal mode");\r
+ break;\r
+\r
+ case RDA_WIFI_DEBUG_MODE_IOCTL:\r
+ ret = rda_wifi_debug_en();\r
+ break;\r
+ \r
+ case RDA_BT_POWER_ON_IOCTL:\r
+ {\r
+ ret = rda_bt_power_on();\r
+ //mt_combo_bgf_enable_irq();\r
+ }\r
+ break;\r
+\r
+ /* should call thif function after bt_power_on*/\r
+ case RDA_BT_EN_CLK:\r
+ ret = RDA5990_bt_enable_clk();\r
+ break;\r
+\r
+ case RD_BT_RF_INIT_IOCTL:\r
+ ret = RDA5990_bt_rf_init();\r
+ break;\r
+\r
+ case RD_BT_DC_CAL_IOCTL: \r
+ ret = RDA5990_bt_dc_cal();\r
+ break;\r
+\r
+ case RD_BT_DC_DIG_RESET_IOCTL: \r
+ ret = RDA5990_bt_dig_reset();\r
+ break;\r
+\r
+ case RD_BT_SET_RF_SWITCH_IOCTL:\r
+ ret = RDA5990_bt_set_rf_switch(); \r
+ break;\r
+\r
+ case RDA_BT_POWER_OFF_IOCTL:\r
+ {\r
+ //mt_combo_bgf_disable_irq();\r
+ ret = rda_bt_power_off(); \r
+ }\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+\r
+ printk(KERN_INFO "rda_bt_pw_ioctl cmd=0x%02x \n", cmd);\r
+\r
+ return ret;\r
+} \r
+\r
+void mmc_rescan_slot(int id)\r
+{\r
+ rda_wifi_power_on();\r
+ rk29sdk_wifi_set_carddetect(1);\r
+}\r
+EXPORT_SYMBOL(mmc_rescan_slot);\r
+\r
+void mmc_remove(int id)\r
+{\r
+ rk29sdk_wifi_set_carddetect(0);\r
+ rda_wifi_power_off();\r
+}\r
+EXPORT_SYMBOL(mmc_remove);\r
+\r
+static int rda_5990_major;\r
+static struct class *rda_5990_class = NULL;\r
+static const struct file_operations rda_5990_operations = {\r
+ .owner = THIS_MODULE,\r
+ .unlocked_ioctl = rda_5990_pw_ioctl,\r
+ .release = NULL\r
+};\r
+\r
+void rda_5990_sleep_worker_task(struct work_struct *work)\r
+{\r
+ printk("---rda_5990_sleep_worker_task end");\r
+ wake_unlock(&rda_5990_wake_lock);\r
+}\r
+\r
+void rda_5990_set_wake_lock(void)\r
+{\r
+ wake_lock(&rda_5990_wake_lock);\r
+ cancel_delayed_work(&rda_5990_sleep_worker);\r
+ schedule_delayed_work(&rda_5990_sleep_worker, 6*HZ);\r
+}\r
+\r
+int rda_5990_power_ctrl_init(void)\r
+{\r
+ int ret = 0;\r
+ printk("rda_5990_power_ctrl_init begin\n");\r
+\r
+ /*i2c_register_board_info(0, &i2c_rda_wifi_core, 1);\r
+ if (i2c_add_driver(&rda_wifi_core_driver))\r
+ {\r
+ printk("rda_wifi_core_driver failed!\n");\r
+ ret = -ENODEV;\r
+ return ret;\r
+ }\r
+ */\r
+\r
+ //i2c_register_board_info(0, &i2c_rda_wifi_rf, 1);\r
+ if (i2c_add_driver(&rda_wifi_rf_driver))\r
+ {\r
+ printk("rda_wifi_rf_driver failed!\n");\r
+ ret = -ENODEV;\r
+ return ret;\r
+ }\r
+ \r
+ /*\r
+ i2c_register_board_info(0, &i2c_rda_bt_core, 1);\r
+ if (i2c_add_driver(&rda_bt_core_driver))\r
+ {\r
+ printk("rda_bt_core_driver failed!\n");\r
+ ret = -ENODEV;\r
+ return ret;\r
+ }\r
+ */\r
+\r
+ //i2c_register_board_info(0, &i2c_rda_bt_rf, 1);\r
+ if (i2c_add_driver(&rda_bt_rf_driver))\r
+ {\r
+ printk("rda_bt_rf_driver failed!\n");\r
+ ret = -ENODEV;\r
+ return ret;\r
+ }\r
+\r
+ rda_5990_major = register_chrdev(0, "rda5990_power_ctrl", &rda_5990_operations);\r
+ if(rda_5990_major < 0)\r
+ {\r
+ printk(KERN_INFO "register rdabt_power_ctrl failed!!! \n");\r
+ return rda_5990_major;\r
+ }\r
+\r
+ rda_5990_class = class_create(THIS_MODULE, "rda_combo");\r
+ if(IS_ERR(rda_5990_class))\r
+ {\r
+ unregister_chrdev(rda_5990_major, "rdabt_power_ctrl");\r
+ return PTR_ERR(rda_5990_class);\r
+ }\r
+\r
+ device_create(rda_5990_class, NULL, MKDEV(rda_5990_major, 0), NULL, "rdacombo");\r
+\r
+ {\r
+ unsigned char* temp = NULL;\r
+ unsigned short testData = 0xffee;\r
+ temp = (unsigned char *)&testData;\r
+ if(*temp == 0xee)\r
+ isBigEnded = 0;\r
+ else\r
+ isBigEnded = 1;\r
+ }\r
+\r
+ INIT_DELAYED_WORK(&rda_5990_sleep_worker, rda_5990_sleep_worker_task);\r
+ wake_lock_init(&rda_5990_wake_lock, WAKE_LOCK_SUSPEND, "RDA_sleep_worker_wake_lock");\r
+\r
+ mutex_init(&i2c_rw_lock); \r
+ printk("rda_5990_power_ctrl_init end\n");\r
+ return 0;\r
+}\r
+\r
+void rda_5990_power_ctrl_exit(void)\r
+{\r
+ i2c_del_driver(&rda_wifi_core_driver);\r
+ i2c_del_driver(&rda_wifi_rf_driver);\r
+ i2c_del_driver(&rda_bt_core_driver);\r
+ i2c_del_driver(&rda_bt_rf_driver);\r
+\r
+ unregister_chrdev(rda_5990_major, "rdabt_power_ctrl");\r
+ if(rda_5990_class)\r
+ class_destroy(rda_5990_class); \r
+\r
+ cancel_delayed_work_sync(&rda_5990_sleep_worker);\r
+ wake_lock_destroy(&rda_5990_wake_lock);\r
+}\r
+\r
+unsigned char rda_5990_wifi_in_test_mode(void)\r
+{\r
+ return wifi_in_test_mode;\r
+}\r
+\r
+\r
+static __inline__ void cfmakeraw(struct termios *s)\r
+{\r
+ s->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);\r
+ s->c_oflag &= ~OPOST;\r
+ s->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);\r
+ s->c_cflag &= ~(CSIZE|PARENB);\r
+ s->c_cflag |= CS8;\r
+}\r
+\r
+static __inline__ int cfsetospeed(struct termios *s, speed_t speed)\r
+{\r
+ s->c_cflag = (s->c_cflag & ~CBAUD) | (speed & CBAUD);\r
+ return 0;\r
+}\r
+\r
+static __inline__ int cfsetispeed(struct termios *s, speed_t speed)\r
+{\r
+ s->c_cflag = (s->c_cflag & ~CBAUD) | (speed & CBAUD);\r
+ return 0;\r
+}\r
+\r
+static int rda_wifi_init_uart(char *dev)\r
+{\r
+ int errno;\r
+ struct termios ti;\r
+ struct serial_struct ss;\r
+ int fd;\r
+\r
+ fd = sys_open(dev, O_RDWR | O_NOCTTY, 0);\r
+ if (fd < 0) {\r
+ printk("Can't open serial port");\r
+ return -1;\r
+ }\r
+\r
+ sys_ioctl(fd, TCFLSH, TCIOFLUSH);\r
+\r
+ /* Clear the cust flag */\r
+ if((errno = sys_ioctl(fd, TIOCGSERIAL, &ss))<0){\r
+ printk("BAUD: error to get the serial_struct info:%s\n", errno);\r
+ goto err;\r
+ }\r
+\r
+ if (ss.flags & ASYNC_SPD_CUST) {\r
+ printk("clear ASYNC_SPD_CUST\r\n");\r
+ ss.flags &= ~ASYNC_SPD_CUST;\r
+ }\r
+ if((errno = sys_ioctl(fd, TIOCSSERIAL, &ss))<0){\r
+ printk("BAUD: error to set serial_struct:%s\n", errno);\r
+ goto err;\r
+ }\r
+\r
+ if ((errno = sys_ioctl(fd, TCGETS, (long)&ti)) < 0) {\r
+ printk("unable to get UART port setting");\r
+ printk("Can't get port settings");\r
+ goto err;\r
+ }\r
+\r
+ cfmakeraw(&ti);\r
+\r
+ ti.c_cflag |= CLOCAL;\r
+ ti.c_cflag &= ~CRTSCTS;\r
+ ti.c_lflag = 0;\r
+ ti.c_cc[VTIME] = 5; /* 0.5 sec */\r
+ ti.c_cc[VMIN] = 0;\r
+\r
+ /* Set initial baudrate */\r
+ cfsetospeed(&ti, B115200);\r
+ cfsetispeed(&ti, B115200);\r
+\r
+ if ((errno = sys_ioctl(fd, TCSETS, (long)&ti)) < 0) {\r
+ printk("unable to set UART port setting");\r
+ printk("Can't set port settings");\r
+ goto err;\r
+ }\r
+\r
+ errno = sys_ioctl(fd, TCFLSH, TCIOFLUSH);\r
+ if(errno < 0)\r
+ goto err;\r
+\r
+ return fd;\r
+\r
+err:\r
+ if(fd > 0)\r
+ sys_close(fd);\r
+\r
+ return -1;\r
+} \r
+\r
+EXPORT_SYMBOL(rda_wlan_version);\r
+\r
+EXPORT_SYMBOL(rda_wifi_init_uart);\r
+EXPORT_SYMBOL(rda_5990_wifi_in_test_mode);\r
+\r
+EXPORT_SYMBOL(rda_5990_set_wake_lock);\r
+EXPORT_SYMBOL(rda_wifi_power_off);\r
+EXPORT_SYMBOL(rda_wifi_power_on);\r
+EXPORT_SYMBOL(rda_fm_power_on);\r
+EXPORT_SYMBOL(rda_fm_power_off);\r
+\r
+module_init(rda_5990_power_ctrl_init);\r
+module_exit(rda_5990_power_ctrl_exit);\r
+\r
+MODULE_LICENSE("GPL");\r
+\r
--- /dev/null
+/* ----------------------------------------------------------------------- *\r
+ *\r
+ This file created by albert RDA Inc\r
+ */\r
+\r
+#include <linux/module.h>\r
+#include <linux/init.h>\r
+#include <linux/slab.h>\r
+#include <linux/i2c.h>\r
+#include <linux/string.h>\r
+#include <linux/rtc.h> /* get the user-level API */\r
+#include <linux/bcd.h>\r
+#include <linux/list.h>\r
+#include <linux/delay.h>\r
+\r
+\r
+#include <linux/nfs_fs.h>\r
+#include <linux/nfs_fs_sb.h>\r
+#include <linux/nfs_mount.h>\r
+#include <linux/fs.h>\r
+#include <linux/file.h>\r
+#include <linux/tty.h>\r
+#include <linux/syscalls.h>\r
+#include <asm/termbits.h>\r
+#include <linux/serial.h>\r
+\r
+\r
+#include <mach/mt6575_gpio.h>\r
+#include <mach/mtk_rtc.h>\r
+#include <linux/wakelock.h>\r
+\r
+#define RDA5890_USE_CRYSTAL //if use share crystal should close this\r
+#define RDA5990_USE_DCDC\r
+\r
+#define u32 unsigned int\r
+#define u8 unsigned char\r
+#define u16 unsigned short\r
+\r
+extern int rda_gpio_i2c_read_1_addr_2_data(uint8_t chipAddr, uint8_t regAddr, uint16_t *buffer);\r
+extern int rda_gpio_i2c_write_1_addr_2_data(uint8_t chipAddr, uint8_t regAddr, uint16_t data);\r
+extern int rda_gpio_i2c_read_4_addr_4_data(uint8_t chipAddr, uint32_t regAddr, uint32_t *buffer);\r
+extern int rda_gpio_i2c_write_4_addr_4_data(uint8_t chipAddr, uint32_t regAddr, uint32_t data);\r
+\r
+\r
+//#define RDA_I2C_CHANNEL (0)\r
+#define RDA_WIFI_CORE_ADDR (0x13)\r
+#define RDA_WIFI_RF_ADDR (0x14) //correct add is 0x14\r
+#define RDA_BT_CORE_ADDR (0x15)\r
+#define RDA_BT_RF_ADDR (0x16)\r
+\r
+static struct mutex i2c_rw_lock;\r
+static unsigned short wlan_version = 0;\r
+static struct wake_lock rda_5990_wake_lock;\r
+static struct delayed_work rda_5990_sleep_worker;\r
+\r
+static u8 isBigEnded = 0;\r
+\r
+static u8 wifi_in_test_mode = 0;\r
+\r
+const u32 wifi_core_init_data[][2] = \r
+{\r
+\r
+};\r
+\r
+u16 wifi_off_data[][2] = \r
+{\r
+ { 0x3F, 0x0001 }, //page up\r
+ { 0x31, 0x0B40 }, //power off wifi\r
+ { 0x3F, 0x0000 }, //page down\r
+};\r
+\r
+u16 wifi_en_data[][2] = \r
+{\r
+ //item:VerD_wf_on_2012_02_08\r
+ {0x3f, 0x0001},\r
+#ifdef RDA5990_USE_DCDC /*houzhen update Mar 15 2012 */\r
+ {0x23, 0x8FA1},//20111001 higher AVDD voltage to improve EVM to 0x8f21 download current -1db 0x8fA1>>0x8bA1 \r
+#else\r
+ {0x23, 0x0FA1},\r
+#endif\r
+ {0x31, 0x0B40 }, //power off wifi\r
+// {0x22, 0xD3C7},//for ver.c 20111109, txswitch\r
+ {0x24, 0x80C8},//freq_osc_in[1:0]00 0x80C8 >> 0x80CB\r
+ {0x27, 0x4925},//for ver.c20111109, txswitch\r
+ // {0x28, 0x80A1}, //BT_enable \r
+ {0x31, 0x8140},//enable wifi \r
+ {0x32, 0x0113},//set_ rdenout_ldooff_wf=0; rden4in_ldoon_wf=1 \r
+ // {0x39, 0x0004}, //uart switch to wf \r
+ {0x3F, 0x0000}, //page down\r
+};\r
+\r
+\r
+u16 wifi_dc_cal_data[][2]=\r
+{\r
+ {0x3f, 0x0000},\r
+ {0x30, 0x0248},\r
+ {0x30, 0x0249},\r
+ //{wait 200ms; } here\r
+};\r
+\r
+u16 wifi_dig_reset_data[][2]=\r
+{\r
+ {0x3F, 0x0001},\r
+ {0x31, 0x8D40},\r
+ {0x31, 0x8F40},\r
+ {0x31, 0x8b40},\r
+ {0x3F, 0x0000},\r
+};\r
+\r
+u16 wifi_rf_init_data_verE[][2] = \r
+{\r
+ {0x3f, 0x0000},\r
+ //{;;set_rf_swi},ch\r
+ {0x06, 0x0101},\r
+ {0x07, 0x0101},\r
+ {0x08, 0x0101},\r
+ {0x09, 0x0101},\r
+ {0x0A, 0x002C},//aain_0\r
+ {0x0D, 0x0507},\r
+ {0x0E, 0x2300},\r
+ {0x0F, 0x5689},//\r
+ //{;;//set_RF },\r
+ {0x10, 0x0f78},//20110824\r
+ {0x11, 0x0602},\r
+ {0x13, 0x0652},//adc_tuning_bit[011]\r
+ {0x14, 0x8886},\r
+ {0x15, 0x0990},\r
+ {0x16, 0x049f},\r
+ {0x17, 0x0990},\r
+ {0x18, 0x049F},\r
+ {0x19, 0x3C01},\r
+ {0x1C, 0x0934},\r
+ {0x1D, 0xFF00},//for ver.D20120119for temperature 70 degree\r
+ //{0x1F, 0x01F8},//for ver.E should not set\r
+ //{0x1F, 0x0300},//for ver.E should not set\r
+ {0x20, 0x06E4},\r
+ {0x21, 0x0ACF},//for ver.c20111109,dr dac reset,dr txflt reset\r
+ {0x22, 0x24DC},\r
+ {0x23, 0x23FF},\r
+ {0x24, 0x00FC},\r
+ {0x26, 0x004F},//004F >> 005f premote pa \r
+ {0x27, 0x171D},///mdll*7\r
+ {0x28, 0x031D},///mdll*7\r
+ {0x2A, 0x2860},//et0x2849-8.5p :yd 0x2861-7pf C1,C2=6.8p\r
+ {0x2B, 0x0800},//bbpll,or ver.c20111116\r
+ {0x32, 0x8a08},\r
+ {0x33, 0x1D02},//liuyanan\r
+ //{;;//agc_gain},\r
+ {0x36, 0x02f4}, //00F8;//gain_7\r
+ {0x37, 0x01f4}, //0074;//aain_6\r
+ {0x38, 0x21d4}, //0014;//gain_5\r
+ {0x39, 0x25d4}, //0414;//aain_4\r
+ {0x3A, 0x2584}, //1804;//gain_3\r
+ {0x3B, 0x2dc4}, //1C04;//aain_2\r
+ {0x3C, 0x2d04}, //1C02;//gain_1\r
+ {0x3D, 0x2c02}, //3C01;//gain_0\r
+ {0x33, 0x1502},//liuyanan\r
+ //{;;SET_channe},_to_11\r
+ {0x1B, 0x0001},//set_channel \r
+ {0x30, 0x024D},\r
+ {0x29, 0xD468},\r
+ {0x29, 0x1468},\r
+ {0x30, 0x0249},\r
+ {0x3f, 0x0000},\r
+};\r
+\r
+u16 wifi_rf_init_data[][2] = \r
+{\r
+ {0x3f, 0x0000},\r
+ //{;;set_rf_swi},ch\r
+ {0x06, 0x0101},\r
+ {0x07, 0x0101},\r
+ {0x08, 0x0101},\r
+ {0x09, 0x0101},\r
+ {0x0A, 0x002C},//aain_0\r
+ {0x0D, 0x0507},\r
+ {0x0E, 0x2300},\r
+ {0x0F, 0x5689},//\r
+ //{;;//set_RF },\r
+ {0x10, 0x0f78},//20110824\r
+ {0x11, 0x0602},\r
+ {0x13, 0x0652},//adc_tuning_bit[011]\r
+ {0x14, 0x8886},\r
+ {0x15, 0x0990},\r
+ {0x16, 0x049f},\r
+ {0x17, 0x0990},\r
+ {0x18, 0x049F},\r
+ {0x19, 0x3C01},\r
+ {0x1C, 0x0934},\r
+ {0x1D, 0xFF00},//for ver.D20120119for temperature 70 degree\r
+ //{0x1F, 0x01F8},//for ver.c20111109\r
+ {0x1F, 0x0300},//for burst tx 不锁\r
+ {0x20, 0x06E4},\r
+ {0x21, 0x0ACF},//for ver.c20111109,dr dac reset,dr txflt reset\r
+ {0x22, 0x24DC},\r
+ {0x23, 0x23FF},\r
+ {0x24, 0x00FC},\r
+ {0x26, 0x004F},//004F >> 005f premote pa \r
+ {0x27, 0x171D},///mdll*7\r
+ {0x28, 0x031D},///mdll*7\r
+ {0x2A, 0x2860},//et0x2849-8.5p :yd 0x2861-7pf C1,C2=6.8p\r
+ {0x2B, 0x0800},//bbpll,or ver.c20111116\r
+ {0x32, 0x8a08},\r
+ {0x33, 0x1D02},//liuyanan\r
+ //{;;//agc_gain},\r
+ {0x36, 0x02f4}, //00F8;//gain_7\r
+ {0x37, 0x01f4}, //0074;//aain_6\r
+ {0x38, 0x21d4}, //0014;//gain_5\r
+ {0x39, 0x25d4}, //0414;//aain_4\r
+ {0x3A, 0x2584}, //1804;//gain_3\r
+ {0x3B, 0x2dc4}, //1C04;//aain_2\r
+ {0x3C, 0x2d04}, //1C02;//gain_1\r
+ {0x3D, 0x2c02}, //3C01;//gain_0\r
+ {0x33, 0x1502},//liuyanan\r
+ //{;;SET_channe},_to_11\r
+ {0x1B, 0x0001},//set_channel \r
+ {0x30, 0x024D},\r
+ {0x29, 0xD468},\r
+ {0x29, 0x1468},\r
+ {0x30, 0x0249},\r
+ {0x3f, 0x0000},\r
+};\r
+\r
+u16 wifi_uart_debug_data[][2] = \r
+{\r
+ {0x3F,0x0001},\r
+ {0x28,0x80A1}, //BT_enable \r
+ {0x39,0x0004}, //uart switch to wf\r
+ {0x3f,0x0000},\r
+};\r
+\r
+u16 wifi_tm_en_data[][2] =\r
+{\r
+ {0x3F,0x0001},\r
+#ifdef RDA5990_USE_DCDC /*houzhen update Mar 15 2012 */\r
+ {0x23, 0x8FA1},//20111001 higher AVDD voltage to improve EVM to 0x8f21 download current -1db 0x8fA1>>0x8bA1 \r
+#else\r
+ {0x23, 0x0FA1},\r
+#endif\r
+ {0x22,0xD3C7},//for ver.c 20111109, tx\r
+ {0x24, 0x80C8},//freq_osc_in[1:0]00 0x80C8 >> 0x80CB \r
+ {0x27,0x4925},//for ver.c20111109, txs\r
+ {0x28,0x80A1}, //BT_enable \r
+ {0x29,0x111F}, \r
+ {0x31,0x8140}, \r
+ {0x32,0x0113},//set_ rdenout_ldooff_wf\r
+ {0x39,0x0004},//uart switch to wf\r
+ {0x3f,0x0000},\r
+};\r
+\r
+u16 wifi_tm_rf_init_data[][2] = \r
+{\r
+ {0x3f, 0x0000},\r
+ //set_rf_switch \r
+ {0x06,0x0101}, \r
+ {0x07,0x0101}, \r
+ {0x08,0x0101}, \r
+ {0x09,0x0101}, \r
+ {0x0A,0x002C},//aain_0\r
+ {0x0D,0x0507}, \r
+ {0x0E,0x2300},//2012_02_20 \r
+ {0x0F,0x5689},// \r
+ //set_RF \r
+ {0x10,0x0f78},//20110824 \r
+ {0x11,0x0602}, \r
+ {0x13,0x0652},//adc_tuning_bit[011] \r
+ {0x14,0x8886}, \r
+ {0x15,0x0990}, \r
+ {0x16,0x049f}, \r
+ {0x17,0x0990}, \r
+ {0x18,0x049F}, \r
+ {0x19,0x3C01},//sdm_vbit[3:0]=1111 \r
+ {0x1C,0x0934}, \r
+ {0x1D,0xCE00},//for ver.D20120119for temperature 70 degree \r
+ {0x1F,0x0300},//div2_band_48g_dr=1;div2_band_48g_reg[8:0]1000000000\r
+ {0x20,0x06E4}, \r
+ {0x21,0x0ACF},//for ver.c20111109,dr dac reset,dr txflt reset \r
+ {0x22,0x24DC}, \r
+ {0x23,0x23FF}, \r
+ {0x24,0x00FC}, \r
+ {0x26,0x004F}, \r
+ {0x27,0x171D},///mdll*7 \r
+ {0x28,0x031D},///mdll*7 \r
+ {0x2A,0x2860}, \r
+ {0x2B,0x0800},//bbpll,or ver.c20111116 \r
+ {0x32,0x8a08}, \r
+ {0x33,0x1D02},//liuyanan \r
+ //agc_gain \r
+ {0x36,0x02f4}, //00F8;//gain_7 \r
+ {0x37,0x01f4}, //0074;//aain_6 \r
+ {0x38,0x21d4}, //0014;//gain_5 \r
+ {0x39,0x25d4}, //0414;//aain_4 \r
+ {0x3A,0x2584}, //1804;//gain_3 \r
+ {0x3B,0x2dc4}, //1C04;//aain_2 \r
+ {0x3C,0x2d04}, //1C02;//gain_1 \r
+ {0x3D,0x2c02}, //3C01;//gain_0 \r
+ //DC_CAL \r
+ {0x30,0x0248}, \r
+ {0x30,0x0249}, \r
+ //wait 200ms; \r
+ {0x33,0x1502},//liuyanan \r
+ //SET_channel_to_11 \r
+ {0x1B,0x0001},//set_channel \r
+ {0x3f,0x0000},\r
+};\r
+\r
+/*houzhen update Mar 15 2012\r
+ should be called when power up/down bt\r
+ */\r
+static int rda5990_wf_setup_A2_power(int enable)\r
+{\r
+ int ret;\r
+ u16 temp_data=0;\r
+ printk("***rda5990_wf_setup_A2_power start! \n");\r
+ ret = rda_gpio_i2c_write_1_addr_2_data(RDA_WIFI_RF_ADDR, 0x3f, 0x0001);\r
+ if(ret)\r
+ goto err;\r
+\r
+ if(enable)\r
+ {\r
+ ret = rda_gpio_i2c_read_1_addr_2_data(RDA_WIFI_RF_ADDR, 0x22, &temp_data);\r
+ if(ret)\r
+ goto err;\r
+ printk("***0xA2 readback value:0x%X \n", temp_data);\r
+\r
+ temp_data |=0x0200; /*en reg4_pa bit*/\r
+#ifdef RDA5890_USE_CRYSTAL \r
+ temp_data &= ~(1 << 14); //disable xen_out\r
+#endif\r
+ ret = rda_gpio_i2c_write_1_addr_2_data(RDA_WIFI_RF_ADDR, 0x22, temp_data);\r
+ if(ret)\r
+ goto err;\r
+ //read wlan version\r
+ ret = rda_gpio_i2c_read_1_addr_2_data(RDA_WIFI_RF_ADDR, 0x21, &temp_data);\r
+ if(ret)\r
+ goto err;\r
+ else\r
+ wlan_version = temp_data;\r
+ }\r
+ else\r
+ {\r
+ ret = rda_gpio_i2c_read_1_addr_2_data(RDA_WIFI_RF_ADDR, 0x28, &temp_data);\r
+ if(ret)\r
+ goto err;\r
+ if(temp_data&0x8000) // bt is on \r
+ {\r
+ goto out;\r
+ }\r
+ else\r
+ {\r
+ ret = rda_gpio_i2c_read_1_addr_2_data(RDA_WIFI_RF_ADDR, 0x22, &temp_data);\r
+ if(ret)\r
+ goto err;\r
+ temp_data&=0xfdff;\r
+\r
+ ret = rda_gpio_i2c_write_1_addr_2_data(RDA_WIFI_RF_ADDR, 0x22, temp_data);\r
+ if(ret)\r
+ goto err;\r
+ }\r
+ wlan_version = 0;\r
+ }\r
+ printk("rda5990_wf_setup_A2_power, version:%d", wlan_version);\r
+\r
+out:\r
+ ret = rda_gpio_i2c_write_1_addr_2_data(RDA_WIFI_RF_ADDR, 0x3f, 0x0000);\r
+ if(ret)\r
+ goto err;\r
+ printk("***rda5990_wf_setup_A2_power succeed! \n");\r
+ return 0;\r
+\r
+err:\r
+ printk("***rda5990_wf_setup_A2_power failed! \n");\r
+ return -1;\r
+}\r
+\r
+\r
+int rda_wifi_rf_init(void)\r
+{\r
+ unsigned int count = 0;\r
+ int ret = 0;\r
+ mutex_lock(&i2c_rw_lock);\r
+ if( (wlan_version&0x1f) == 7)\r
+ {\r
+ for(count = 0; count < sizeof(wifi_rf_init_data)/sizeof(wifi_rf_init_data[0]); count ++)\r
+ {\r
+ ret = rda_gpio_i2c_write_1_addr_2_data(RDA_WIFI_RF_ADDR, wifi_rf_init_data[count][0], wifi_rf_init_data[count][1]);\r
+ if(ret)\r
+ goto err;\r
+ }\r
+ }\r
+ else if((wlan_version&0x1f) == 4 || (wlan_version&0x1f)==5)\r
+ {\r
+ for(count = 0; count < sizeof(wifi_rf_init_data_verE)/sizeof(wifi_rf_init_data_verE[0]); count ++)\r
+ {\r
+ ret = rda_gpio_i2c_write_1_addr_2_data(RDA_WIFI_RF_ADDR, wifi_rf_init_data_verE[count][0], wifi_rf_init_data_verE[count][1]);\r
+ if(ret)\r
+ goto err;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ printk("unknown version of this 5990 chip\n");\r
+ goto err;\r
+ }\r
+ mutex_unlock(&i2c_rw_lock);\r
+ printk(KERN_INFO "***rda_wifi_rf_init_succceed \n");\r
+ msleep(5); //5ms delay\r
+ return 0;\r
+err:\r
+ mutex_unlock(&i2c_rw_lock);\r
+ printk(KERN_INFO "***rda_wifi_rf_init failed! \n");\r
+ return -1;\r
+}\r
+\r
+int rda_wifi_dc_cal(void)\r
+{\r
+ unsigned int count = 0;\r
+ int ret = 0;\r
+\r
+ mutex_lock(&i2c_rw_lock);\r
+ for(count = 0; count < sizeof(wifi_dc_cal_data)/sizeof(wifi_dc_cal_data[0]); count ++)\r
+ {\r
+ ret = rda_gpio_i2c_write_1_addr_2_data(RDA_WIFI_RF_ADDR, wifi_dc_cal_data[count][0], wifi_dc_cal_data[count][1]);\r
+ if(ret)\r
+ goto err;\r
+ }\r
+\r
+ mutex_unlock(&i2c_rw_lock);\r
+ printk(KERN_INFO "***rda_wifi_rf_dc_calsuccceed \n");\r
+ msleep(50); //50ms delay\r
+ return 0;\r
+\r
+err:\r
+ mutex_unlock(&i2c_rw_lock);\r
+ printk(KERN_INFO "***rda_wifi_rf_dc_calf_failed! \n");\r
+ return -1;\r
+}\r
+\r
+int rda_wifi_en(void)\r
+{\r
+ unsigned int count = 0;\r
+ int ret = 0;\r
+\r
+ mutex_lock(&i2c_rw_lock); \r
+ for(count = 0; count < sizeof(wifi_en_data)/sizeof(wifi_en_data[0]); count ++)\r
+ {\r
+ ret = rda_gpio_i2c_write_1_addr_2_data(RDA_WIFI_RF_ADDR, wifi_en_data[count][0], wifi_en_data[count][1]);\r
+ if(ret)\r
+ goto err;\r
+\r
+ if(wifi_en_data[count][0] == 0x31)\r
+ msleep(12);\r
+ }\r
+\r
+ ret=rda5990_wf_setup_A2_power(1); //en pa_reg for wf\r
+ if(ret)\r
+ goto err;\r
+\r
+ mutex_unlock(&i2c_rw_lock);\r
+ msleep(8); //8ms delay\r
+\r
+ printk(KERN_INFO "***rda_wifi_en_succceed \n");\r
+ return 0;\r
+err:\r
+ mutex_unlock(&i2c_rw_lock);\r
+ printk(KERN_INFO "***rda_wifi_power_on failed! \n");\r
+ return -1;\r
+}\r
+\r
+int rda_wifi_debug_en(void)\r
+{\r
+ unsigned int count = 0;\r
+ int ret = 0;\r
+ \r
+ mutex_lock(&i2c_rw_lock); \r
+ for(count = 0; count < sizeof(wifi_uart_debug_data)/sizeof(wifi_uart_debug_data[0]); count ++)\r
+ {\r
+ ret = rda_gpio_i2c_write_1_addr_2_data(RDA_WIFI_RF_ADDR, wifi_uart_debug_data[count][0], wifi_uart_debug_data[count][1]);\r
+ if(ret)\r
+ goto err;\r
+ }\r
+\r
+err:\r
+ mutex_unlock(&i2c_rw_lock);\r
+ return ret;\r
+}\r
+\r
+int rda_tm_wifi_en(void)\r
+{\r
+ unsigned int count = 0;\r
+ int ret = 0;\r
+ unsigned short temp_data;\r
+\r
+ for(count = 0; count < sizeof(wifi_tm_en_data)/sizeof(wifi_tm_en_data[0]); count ++)\r
+ {\r
+ ret = rda_gpio_i2c_write_1_addr_2_data(RDA_WIFI_RF_ADDR, wifi_tm_en_data[count][0], wifi_tm_en_data[count][1]);\r
+ if(ret)\r
+ goto err;\r
+ }\r
+\r
+ msleep(8); //8ms delay\r
+\r
+ ret = rda_gpio_i2c_write_1_addr_2_data(RDA_WIFI_RF_ADDR, 0x3f, 0x0001); //PAGE UP\r
+ if(ret)\r
+ goto err;\r
+ \r
+ ret = rda_gpio_i2c_read_1_addr_2_data(RDA_WIFI_RF_ADDR,0x21,&temp_data);\r
+ if(ret)\r
+ goto err;\r
+ else\r
+ wlan_version = temp_data;\r
+\r
+ ret = rda_gpio_i2c_write_1_addr_2_data(RDA_WIFI_RF_ADDR, 0x3f, 0x0000); //PAGE DOWN\r
+ if(ret)\r
+ goto err;\r
+\r
+ printk(KERN_INFO "***rda_wifi_en_succceed \n");\r
+ return 0;\r
+err:\r
+ printk(KERN_INFO "***rda_wifi_power_on failed! \n");\r
+ return -1;\r
+}\r
+\r
+int rda_tm_wifi_rf_init(void)\r
+{\r
+ unsigned int count = 0;\r
+ int ret = 0;\r
+\r
+ for(count = 0; count < sizeof(wifi_tm_rf_init_data)/sizeof(wifi_tm_rf_init_data[0]); count ++)\r
+ {\r
+ ret = rda_gpio_i2c_write_1_addr_2_data(RDA_WIFI_RF_ADDR, wifi_tm_rf_init_data[count][0], wifi_tm_rf_init_data[count][1]);\r
+ if(ret)\r
+ goto err;\r
+ }\r
+\r
+ printk(KERN_INFO "***rda_wifi_rf_init_succceed \n");\r
+ msleep(5); //5ms delay\r
+ return 0;\r
+\r
+err:\r
+ printk(KERN_INFO "***rda_wifi_rf_init failed! \n");\r
+ return -1;\r
+}\r
+/*houzhen add 2012 04 09\r
+ add to ensure wf dig powerup\r
+ */\r
+\r
+int rda_wifi_dig_reset(void)\r
+{\r
+ unsigned int count = 0;\r
+ int ret = 0;\r
+ msleep(8); //8ms delay\r
+ mutex_lock(&i2c_rw_lock);\r
+\r
+ for(count = 0; count < sizeof(wifi_dig_reset_data)/sizeof(wifi_dig_reset_data[0]); count ++)\r
+ {\r
+ ret = rda_gpio_i2c_write_1_addr_2_data(RDA_WIFI_RF_ADDR, wifi_dig_reset_data[count][0], wifi_dig_reset_data[count][1]);\r
+ if(ret)\r
+ goto err;\r
+ }\r
+\r
+ mutex_unlock(&i2c_rw_lock);\r
+ msleep(8); //8ms delay\r
+ printk(KERN_INFO "***rda_wifi_dig_reset \n");\r
+ return 0;\r
+err:\r
+ mutex_unlock(&i2c_rw_lock);\r
+ printk(KERN_INFO "***rda_wifi_dig_reset failed! \n"); \r
+ return -1;\r
+}\r
+\r
+int rda_wlan_version(void)\r
+{\r
+ printk("******version %x \n", wlan_version);\r
+ return wlan_version;\r
+}\r
+\r
+int rda_wifi_power_off(void)\r
+{\r
+ unsigned int count = 0;\r
+ int ret = 0;\r
+ u16 temp=0x0000;\r
+ printk(KERN_INFO "rda_wifi_power_off \n");\r
+\r
+\r
+ mutex_lock(&i2c_rw_lock);\r
+ ret=rda5990_wf_setup_A2_power(0); //disable pa_reg for wf\r
+ if(ret)\r
+ goto err;\r
+\r
+ ret = rda_gpio_i2c_write_1_addr_2_data(RDA_WIFI_RF_ADDR, 0x3f, 0x0001); //page up\r
+ if(ret)\r
+ goto err;\r
+\r
+ ret = rda_gpio_i2c_read_1_addr_2_data(RDA_WIFI_RF_ADDR, 0x28, &temp); //poll bt status\r
+ if(ret)\r
+ goto err;\r
+\r
+ if(temp&0x8000)\r
+ {\r
+ ret = rda_gpio_i2c_write_1_addr_2_data(RDA_WIFI_RF_ADDR, 0x3f, 0x0000); //page down\r
+ if(ret)\r
+ goto err;\r
+\r
+ ret = rda_gpio_i2c_write_1_addr_2_data(RDA_WIFI_RF_ADDR, 0x0f, 0x2223); // set antenna for bt\r
+ if(ret)\r
+ goto err;\r
+\r
+ }\r
+\r
+\r
+ for(count = 0; count < sizeof(wifi_off_data)/sizeof(wifi_off_data[0]); count ++)\r
+ {\r
+ ret = rda_gpio_i2c_write_1_addr_2_data(RDA_WIFI_RF_ADDR, wifi_off_data[count][0], wifi_off_data[count][1]);\r
+ if(ret)\r
+ goto err;\r
+ }\r
+ printk(KERN_INFO "***rda_wifi_power_off success!!! \n");\r
+\r
+\r
+\r
+ mutex_unlock(&i2c_rw_lock);\r
+ return 0;\r
+\r
+err:\r
+ mutex_unlock(&i2c_rw_lock);\r
+ printk(KERN_INFO "***rda_wifi_power_off failed! \n");\r
+ return -1;\r
+\r
+}\r
+\r
+int rda_wifi_power_on(void)\r
+{\r
+ int ret;\r
+ char retry = 3;\r
+\r
+\r
+_retry:\r
+\r
+ if(!wifi_in_test_mode)\r
+ {\r
+ ret = rda_wifi_en(); \r
+ if(ret < 0)\r
+ goto err;\r
+\r
+ ret = rda_wifi_rf_init(); \r
+ if(ret < 0)\r
+ goto err;\r
+\r
+ ret = rda_wifi_dc_cal(); \r
+ if(ret < 0)\r
+ goto err;\r
+\r
+ msleep(20); //20ms delay\r
+ ret=rda_wifi_dig_reset(); //houzhen add to ensure wf power up safely\r
+\r
+ if(ret < 0)\r
+ goto err;\r
+ msleep(20); //20ms delay\r
+ }\r
+ else\r
+ {\r
+ ret = rda_tm_wifi_en();\r
+ if(ret < 0)\r
+ goto err;\r
+\r
+ ret = rda_tm_wifi_rf_init();\r
+ if(ret < 0)\r
+ goto err;\r
+ }\r
+ printk(KERN_INFO "rda_wifi_power_on_succeed!! \n");\r
+\r
+ return 0;\r
+\r
+err:\r
+ printk(KERN_INFO "rda_wifi_power_on_failed retry:%d \n", retry);\r
+ if(retry -- > 0)\r
+ { \r
+ rda_wifi_power_off();\r
+ goto _retry;\r
+ }\r
+\r
+ return -1;\r
+}\r
+\r
+int rda_fm_power_on(void)\r
+{\r
+ int ret = 0;\r
+ u16 temp = 0;\r
+\r
+\r
+ ret = rda_gpio_i2c_write_1_addr_2_data(RDA_WIFI_RF_ADDR, 0x3f, 0x0001); // page down\r
+ if(ret < 0){\r
+ printk(KERN_INFO "%s() write address(0x%02x) with value(0x%04x) failed! \n", __func__, 0x3f, 0x0001);\r
+ return -1;\r
+ }\r
+ ret = rda_gpio_i2c_read_1_addr_2_data(RDA_WIFI_RF_ADDR, 0x22, &temp); //read 0xA2\r
+ if(ret < 0){\r
+ printk(KERN_INFO "%s() read from address(0x%02x) failed! \n", __func__, 0x22);\r
+ return -1;\r
+ }\r
+ temp = temp & (~(1 << 15)); //clear bit[15]\r
+ ret = rda_gpio_i2c_write_1_addr_2_data(RDA_WIFI_RF_ADDR, 0x22, temp); //write back\r
+ if(ret < 0){\r
+ printk(KERN_INFO "%s() write address(0x%02x) with value(0x%04x) failed! \n", __func__, 0x3f, 0x0001);\r
+ return -1;\r
+ }\r
+ ret = rda_gpio_i2c_write_1_addr_2_data(RDA_WIFI_RF_ADDR, 0x3f, 0x0000); // page up\r
+ if(ret < 0){\r
+ printk(KERN_INFO "%s() write address(0x%02x) with value(0x%04x) failed! \n", __func__, 0x3f, 0x0001);\r
+ return -1;\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+int rda_fm_power_off(void)\r
+{\r
+ int ret = 0;\r
+ u16 temp = 0;\r
+\r
+\r
+ ret = rda_gpio_i2c_write_1_addr_2_data(RDA_WIFI_RF_ADDR, 0x3f, 0x0001); // page down\r
+ if(ret < 0){\r
+ printk(KERN_INFO "%s() write address(0x%02x) with value(0x%04x) failed! \n", __func__, 0x3f, 0x0001);\r
+ return -1;\r
+ }\r
+ ret = rda_gpio_i2c_read_1_addr_2_data(RDA_WIFI_RF_ADDR, 0x22, &temp); //read 0xA2\r
+ if(ret < 0){\r
+ printk(KERN_INFO "%s() read from address(0x%02x) failed! \n", __func__, 0x22);\r
+ return -1;\r
+ }\r
+ temp = temp | (1 << 15); //set bit[15]\r
+ ret = rda_gpio_i2c_write_1_addr_2_data(RDA_WIFI_RF_ADDR, 0x22, temp); //write back\r
+ if(ret < 0){\r
+ printk(KERN_INFO "%s() write address(0x%02x) with value(0x%04x) failed! \n", __func__, 0x3f, 0x0001);\r
+ return -1;\r
+ }\r
+ ret = rda_gpio_i2c_write_1_addr_2_data(RDA_WIFI_RF_ADDR, 0x3f, 0x0000); // page up\r
+ if(ret < 0){\r
+ printk(KERN_INFO "%s() write address(0x%02x) with value(0x%04x) failed! \n", __func__, 0x3f, 0x0001);\r
+ return -1;\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+\r
+u16 rda_5990_bt_off_data[][2] = \r
+{\r
+ {0x3f, 0x0001 }, //pageup\r
+ {0x28, 0x00A1 }, //power off bt\r
+ {0x3f, 0x0000 }, //pagedown\r
+};\r
+\r
+/*houzhen update 2012 03 06*/\r
+u16 rda_5990_bt_en_data[][2] = \r
+{\r
+ {0x3f, 0x0001 }, //pageup\r
+#ifdef RDA5990_USE_DCDC \r
+ {0x23, 0x8FA1}, // //20111001 higher AVDD voltage to improve EVM\r
+#else\r
+ {0x23, 0x0FA1},\r
+#endif \r
+ {0x24, 0x80C8}, // ;//freq_osc_in[1:0]00 \r
+ {0x26, 0x47A5}, // reg_vbit_normal_bt[2:0] =111\r
+ {0x27, 0x4925}, // //for ver.c20111109, txswitch\r
+ {0x29, 0x111F}, // // rden4in_ldoon_bt=1 \r
+ {0x32, 0x0111}, // set_ rdenout_ldooff_wf=0; \r
+ {0x39, 0x0000}, // //uart switch to bt\r
+\r
+ {0x28, 0x80A1}, // bt en\r
+ {0x3f, 0x0000}, //pagedown\r
+};\r
+\r
+\r
+u16 rda_5990_bt_dc_cal[][2] = \r
+{\r
+ {0x3f, 0x0000 }, \r
+ {0x30, 0x0129 },\r
+ {0x30, 0x012B },\r
+ {0x3f, 0x0000 }, \r
+};\r
+\r
+\r
+u16 rda_5990_bt_set_rf_switch_data[][2] = \r
+{\r
+ {0x3f, 0x0000 }, \r
+ {0x0F, 0x2223 },\r
+ {0x3f, 0x0000 }, \r
+};\r
+\r
+\r
+u16 RDA5990_bt_enable_clk_data[][2] = \r
+{\r
+ {0x3f, 0x0000 }, \r
+ {0x30, 0x0040 },\r
+ {0x2a, 0x285d },\r
+ {0x3f, 0x0000 }, \r
+};\r
+\r
+u16 RDA5990_bt_dig_reset_data[][2] = \r
+{\r
+ {0x3f, 0x0001 }, //pageup\r
+ {0x28, 0x86A1 },\r
+ {0x28, 0x87A1 },\r
+ {0x28, 0x85A1 },\r
+ {0x3f, 0x0000 }, //pagedown\r
+};\r
+\r
+/*houzhen update 2012 03 06*/\r
+u16 rda_5990_bt_rf_data[][2] = \r
+{\r
+ {0x3f, 0x0000}, //pagedown\r
+ {0x01, 0x1FFF},\r
+ {0x06, 0x07F7},\r
+ {0x08, 0x29E7},\r
+ {0x09, 0x0520},\r
+ {0x0B, 0x03DF},\r
+ {0x0C, 0x85E8},\r
+ {0x0F, 0x0DBC},\r
+ {0x12, 0x07F7},\r
+ {0x13, 0x0327},\r
+ {0x14, 0x0CCC},\r
+ {0x15, 0x0526},\r
+ {0x16, 0x8918},\r
+ {0x18, 0x8800},\r
+ {0x19, 0x10C8},\r
+ {0x1A, 0x9078},\r
+ {0x1B, 0x80E2},\r
+ {0x1C, 0x361F},\r
+ {0x1D, 0x4363},\r
+ {0x1E, 0x303F},\r
+ {0x23, 0x2222},\r
+ {0x24, 0x359D},\r
+ {0x27, 0x0011},\r
+ {0x28, 0x124F},\r
+ {0x39, 0xA5FC},\r
+ {0x3f, 0x0001}, //page 1\r
+ {0x00, 0x043F},\r
+ {0x01, 0x467F},\r
+ {0x02, 0x28FF},\r
+ {0x03, 0x67FF},\r
+ {0x04, 0x57FF},\r
+ {0x05, 0x7BFF},\r
+ {0x06, 0x3FFF},\r
+ {0x07, 0x7FFF},\r
+ {0x18, 0xF3F5},\r
+ {0x19, 0xF3F5},\r
+ {0x1A, 0xE7F3},\r
+ {0x1B, 0xF1FF},\r
+ {0x1C, 0xFFFF},\r
+ {0x1D, 0xFFFF},\r
+ {0x1E, 0xFFFF},\r
+ {0x1F, 0xFFFF},\r
+ // {0x22, 0xD3C7}, \r
+ // {0x23, 0x8fa1},\r
+ // {0x24, 0x80c8},\r
+ // {0x26, 0x47A5},\r
+ // {0x27, 0x4925},\r
+ // {0x28, 0x85a1},\r
+ // {0x29, 0x111f},\r
+ // {0x32, 0x0111},\r
+ // {0x39, 0x0000},\r
+ {0x3f, 0x0000}, //pagedown\r
+};\r
+\r
+/*houzhen update Mar 15 2012\r
+ should be called when power up/down bt\r
+ */\r
+static int rda5990_bt_setup_A2_power(int enable)\r
+{\r
+ int ret;\r
+ u16 temp_data=0;\r
+\r
+ ret = rda_gpio_i2c_write_1_addr_2_data(RDA_BT_RF_ADDR, 0x3f, 0x0001);\r
+ if(ret)\r
+ goto err;\r
+\r
+ if(enable)\r
+ {\r
+ ret = rda_gpio_i2c_read_1_addr_2_data(RDA_BT_RF_ADDR, 0x22, &temp_data);\r
+ if(ret)\r
+ goto err;\r
+ printk(KERN_INFO "***0xA2 readback value:0x%X \n", temp_data);\r
+\r
+ temp_data |=0x0200; /*en reg4_pa bit*/\r
+\r
+ ret = rda_gpio_i2c_write_1_addr_2_data(RDA_BT_RF_ADDR, 0x22, temp_data);\r
+ if(ret)\r
+ goto err; \r
+ }\r
+ else\r
+ {\r
+ ret = rda_gpio_i2c_read_1_addr_2_data(RDA_BT_RF_ADDR, 0x31, &temp_data);\r
+ if(ret)\r
+ goto err;\r
+ if(temp_data&0x8000) // wf is on \r
+ {\r
+ goto out;\r
+ }\r
+ else\r
+ {\r
+ ret = rda_gpio_i2c_read_1_addr_2_data(RDA_BT_RF_ADDR, 0x22, &temp_data);\r
+ if(ret)\r
+ goto err;\r
+ temp_data&=0xfdff;\r
+\r
+ ret = rda_gpio_i2c_write_1_addr_2_data(RDA_BT_RF_ADDR, 0x22, temp_data);\r
+ if(ret)\r
+ goto err;\r
+ }\r
+\r
+ }\r
+\r
+\r
+out:\r
+ ret = rda_gpio_i2c_write_1_addr_2_data(RDA_BT_RF_ADDR, 0x3f, 0x0000);\r
+ if(ret)\r
+ goto err;\r
+ return 0;\r
+\r
+err:\r
+ printk(KERN_INFO "***rda5990_bt_setup_A2_power failed! \n");\r
+ return -1;\r
+}\r
+\r
+int rda_bt_power_off(void);\r
+\r
+int rda_bt_power_on(void)\r
+{\r
+ unsigned int count = 0;\r
+ int ret = 0;\r
+\r
+ printk(KERN_INFO "rda_bt_power_on \n");\r
+\r
+\r
+ mutex_lock(&i2c_rw_lock);\r
+\r
+ for(count = 0; count < sizeof(rda_5990_bt_en_data)/sizeof(rda_5990_bt_en_data[0]); count ++)\r
+ {\r
+ ret = rda_gpio_i2c_write_1_addr_2_data(RDA_BT_RF_ADDR, rda_5990_bt_en_data[count][0], rda_5990_bt_en_data[count][1]);\r
+\r
+ if(ret)\r
+ goto err;\r
+ }\r
+\r
+ ret=rda5990_bt_setup_A2_power(1); \r
+ if(ret)\r
+ { \r
+ printk(KERN_INFO "***rda5990_bt_setup_A2_power fail!!! \n");\r
+ goto err;\r
+ }\r
+\r
+ printk(KERN_INFO "***rda_bt_power_on success!!! \n");\r
+\r
+ mutex_unlock(&i2c_rw_lock);\r
+ /*houzhen update 2012 03 06*/\r
+ msleep(10); //delay 10 ms after power on\r
+\r
+\r
+ return 0;\r
+err:\r
+ mutex_unlock(&i2c_rw_lock);\r
+ printk(KERN_INFO "***rda_bt_power_on failed! \n");\r
+ return -1;\r
+\r
+}\r
+\r
+int rda_bt_power_off(void)\r
+{\r
+ unsigned int count = 0;\r
+ int ret = 0;\r
+ printk(KERN_INFO "rda_bt_power_off \n");\r
+\r
+\r
+ mutex_lock(&i2c_rw_lock);\r
+ for(count = 0; count < sizeof(rda_5990_bt_off_data)/sizeof(rda_5990_bt_off_data[0]); count ++)\r
+ {\r
+ ret = rda_gpio_i2c_write_1_addr_2_data(RDA_BT_RF_ADDR, rda_5990_bt_off_data[count][0], rda_5990_bt_off_data[count][1]);\r
+ if(ret)\r
+ goto err;\r
+ }\r
+ msleep(10); //10ms\r
+ printk(KERN_INFO "***rda_bt_power_off success!!! \n");\r
+\r
+ ret=rda5990_bt_setup_A2_power(0);//disable ldo_pa reg \r
+ if(ret)\r
+ goto err;\r
+\r
+\r
+\r
+ mutex_unlock(&i2c_rw_lock); \r
+ return 0;\r
+\r
+err:\r
+ mutex_unlock(&i2c_rw_lock);\r
+ printk(KERN_INFO "***rda_bt_power_off failed! \n");\r
+ return -1;\r
+\r
+}\r
+\r
+\r
+int RDA5990_bt_rf_init(void)\r
+{\r
+ unsigned int count = 0;\r
+ int ret = 0;\r
+ printk(KERN_INFO "RDA5990_bt_rf_init \n");\r
+\r
+\r
+ mutex_lock(&i2c_rw_lock);\r
+ for(count = 0; count < sizeof(rda_5990_bt_rf_data)/sizeof(rda_5990_bt_rf_data[0]); count ++)\r
+ {\r
+ ret = rda_gpio_i2c_write_1_addr_2_data(RDA_BT_RF_ADDR, rda_5990_bt_rf_data[count][0], rda_5990_bt_rf_data[count][1]);\r
+ if(ret)\r
+ goto err;\r
+ }\r
+\r
+ mutex_unlock(&i2c_rw_lock);\r
+ printk(KERN_INFO "***RDA5990_bt_rf_init success!!! \n");\r
+ msleep(5); //5ms\r
+ return 0;\r
+\r
+err:\r
+ mutex_unlock(&i2c_rw_lock);\r
+ printk(KERN_INFO "***RDA5990_bt_rf_init failed! \n");\r
+ return -1;\r
+\r
+}\r
+\r
+\r
+\r
+/*houzhen add 2012 04 09\r
+ add to ensure bt dig powerup\r
+ */\r
+\r
+int RDA5990_bt_dig_reset(void)\r
+{\r
+ unsigned int count = 0;\r
+ int ret = 0;\r
+\r
+ printk(KERN_INFO "RDA5990_bt_dig_reset \n");\r
+\r
+ mutex_lock(&i2c_rw_lock);\r
+ for(count = 0; count < sizeof(RDA5990_bt_dig_reset_data)/sizeof(RDA5990_bt_dig_reset_data[0]); count ++)\r
+ {\r
+ ret = rda_gpio_i2c_write_1_addr_2_data(RDA_BT_RF_ADDR, RDA5990_bt_dig_reset_data[count][0], RDA5990_bt_dig_reset_data[count][1]);\r
+ if(ret)\r
+ goto err;\r
+ }\r
+\r
+ mutex_unlock(&i2c_rw_lock);\r
+ printk(KERN_INFO "***RDA5990_bt_dig_reset success!!! \n");\r
+ msleep(5); //5ms\r
+ return 0;\r
+\r
+err:\r
+ mutex_unlock(&i2c_rw_lock);\r
+ printk(KERN_INFO "***RDA5990_bt_dig_reset failed! \n");\r
+ return -1;\r
+\r
+}\r
+\r
+\r
+int RDA5990_bt_dc_cal(void)\r
+{\r
+ unsigned int count = 0;\r
+ int ret = 0;\r
+ printk(KERN_INFO "rda_bt_dc_cal \n");\r
+\r
+ mutex_lock(&i2c_rw_lock);\r
+\r
+ for(count = 0; count < sizeof(rda_5990_bt_dc_cal)/sizeof(rda_5990_bt_dc_cal[0]); count ++)\r
+ {\r
+ ret = rda_gpio_i2c_write_1_addr_2_data(RDA_BT_RF_ADDR, rda_5990_bt_dc_cal[count][0], rda_5990_bt_dc_cal[count][1]);\r
+ if(ret)\r
+ goto err;\r
+ }\r
+\r
+ mutex_unlock(&i2c_rw_lock);\r
+ printk(KERN_INFO "***rda_bt_dc_cal success!!! \n");\r
+ msleep(200); //200ms\r
+\r
+ return 0;\r
+\r
+err:\r
+ mutex_unlock(&i2c_rw_lock);\r
+ printk(KERN_INFO "***rda_bt_dc_cal failed! \n");\r
+ return -1;\r
+\r
+}\r
+\r
+\r
+\r
+/*houzhen update Mar 15 2012 \r
+ bypass RDA5990_bt_set_rf_switch when wf is already on\r
+ */\r
+\r
+int RDA5990_bt_set_rf_switch(void)\r
+{\r
+ unsigned int count = 0;\r
+ int ret = 0;\r
+ u16 temp_data=0;\r
+ printk(KERN_INFO "RDA5990_bt_set_rf_switch \n");\r
+\r
+\r
+ mutex_lock(&i2c_rw_lock);\r
+\r
+ ret = rda_gpio_i2c_write_1_addr_2_data(RDA_BT_RF_ADDR, 0x3f, 0x0001);\r
+ if(ret)\r
+ goto err; \r
+\r
+ ret = rda_gpio_i2c_read_1_addr_2_data(RDA_BT_RF_ADDR, 0x31, &temp_data);\r
+\r
+ if(ret)\r
+ goto err; \r
+\r
+ if(temp_data&0x8000) // if wf is already on\r
+ {\r
+\r
+ printk(KERN_INFO "wf already en, bypass RDA5990_bt_set_rf_switch function \n");\r
+ ret = rda_gpio_i2c_write_1_addr_2_data(RDA_BT_RF_ADDR, 0x3f, 0x0000);\r
+ if(ret)\r
+ goto err; \r
+ mutex_unlock(&i2c_rw_lock); \r
+ return 0;\r
+ }\r
+\r
+ for(count = 0; count < sizeof(rda_5990_bt_set_rf_switch_data)/sizeof(rda_5990_bt_set_rf_switch_data[0]); count ++)\r
+ {\r
+ ret = rda_gpio_i2c_write_1_addr_2_data(RDA_WIFI_RF_ADDR, rda_5990_bt_set_rf_switch_data[count][0], rda_5990_bt_set_rf_switch_data[count][1]);\r
+ if(ret)\r
+ goto err; \r
+ }\r
+\r
+ mutex_unlock(&i2c_rw_lock);\r
+ printk(KERN_INFO "***RDA5990_bt_set_rf_switch success!!! \n");\r
+ msleep(50); //50ms\r
+ return 0;\r
+\r
+err:\r
+ mutex_unlock(&i2c_rw_lock);\r
+ printk(KERN_INFO "***RDA5990_bt_set_rf_switch failed! \n");\r
+ return -1;\r
+\r
+}\r
+\r
+\r
+/*houzhen update Mar 15 2012 \r
+ bypass RDA5990_bt_enable_clk when wf is already on\r
+ */\r
+\r
+int RDA5990_bt_enable_clk(void)\r
+{\r
+ unsigned int count = 0;\r
+ int ret = 0;\r
+ u16 temp_data=0;\r
+ printk(KERN_INFO "RDA5990_bt_enable_clk \n");\r
+\r
+ mutex_lock(&i2c_rw_lock);\r
+ ret = rda_gpio_i2c_write_1_addr_2_data(RDA_BT_RF_ADDR, 0x3f, 0x0001);\r
+ if(ret)\r
+ goto err; \r
+\r
+ ret = rda_gpio_i2c_read_1_addr_2_data(RDA_BT_RF_ADDR, 0x31, &temp_data);\r
+\r
+ if(ret)\r
+ goto err; \r
+\r
+ if(temp_data&0x8000) // if wf is already on\r
+ {\r
+\r
+ printk(KERN_INFO "wf already en, bypass RDA5990_bt_enable_clk function \n");\r
+ ret = rda_gpio_i2c_write_1_addr_2_data(RDA_BT_RF_ADDR, 0x3f, 0x0000);\r
+ if(ret)\r
+ goto err; \r
+ mutex_unlock(&i2c_rw_lock);\r
+ return 0;\r
+ }\r
+\r
+\r
+ for(count = 0; count < sizeof(RDA5990_bt_enable_clk_data)/sizeof(RDA5990_bt_enable_clk_data[0]); count ++)\r
+ {\r
+ ret = rda_gpio_i2c_write_1_addr_2_data(RDA_WIFI_RF_ADDR, RDA5990_bt_enable_clk_data[count][0], RDA5990_bt_enable_clk_data[count][1]);\r
+ if(ret)\r
+ goto err; \r
+ }\r
+\r
+ mutex_unlock(&i2c_rw_lock);\r
+ printk(KERN_INFO "***RDA5990_bt_enable_clk success!!! \n");\r
+ msleep(50); //50ms\r
+ return 0;\r
+\r
+err:\r
+ mutex_unlock(&i2c_rw_lock);\r
+ printk(KERN_INFO "***RDA5990_bt_enable_clk failed! \n");\r
+ return -1;\r
+\r
+}\r
+\r
+extern void mt_combo_bgf_enable_irq(void);\r
+extern void mt_combo_bgf_disable_irq(void);\r
+\r
+\r
+#define RDA_BT_IOCTL_MAGIC 'u'\r
+#define RDA_BT_POWER_ON_IOCTL _IO(RDA_BT_IOCTL_MAGIC ,0x01)\r
+#define RD_BT_RF_INIT_IOCTL _IO(RDA_BT_IOCTL_MAGIC ,0x02)\r
+#define RD_BT_DC_CAL_IOCTL _IO(RDA_BT_IOCTL_MAGIC ,0x03)\r
+#define RD_BT_SET_RF_SWITCH_IOCTL _IO(RDA_BT_IOCTL_MAGIC ,0x04)\r
+#define RDA_BT_POWER_OFF_IOCTL _IO(RDA_BT_IOCTL_MAGIC ,0x05)\r
+#define RDA_BT_EN_CLK _IO(RDA_BT_IOCTL_MAGIC ,0x06)\r
+#define RD_BT_DC_DIG_RESET_IOCTL _IO(RDA_BT_IOCTL_MAGIC ,0x07)\r
+\r
+#define RDA_WIFI_POWER_ON_IOCTL _IO(RDA_BT_IOCTL_MAGIC ,0x10)\r
+#define RDA_WIFI_POWER_OFF_IOCTL _IO(RDA_BT_IOCTL_MAGIC ,0x11)\r
+#define RDA_WIFI_POWER_SET_TEST_MODE_IOCTL _IO(RDA_BT_IOCTL_MAGIC ,0x12)\r
+#define RDA_WIFI_POWER_CANCEL_TEST_MODE_IOCTL _IO(RDA_BT_IOCTL_MAGIC ,0x13)\r
+#define RDA_WIFI_DEBUG_MODE_IOCTL _IO(RDA_BT_IOCTL_MAGIC ,0x14)\r
+\r
+static int rda_5990_pw_ioctl(struct file *file, unsigned int cmd, unsigned long arg)\r
+{\r
+ int ret = 0;\r
+\r
+ switch(cmd)\r
+ {\r
+ case RDA_WIFI_POWER_ON_IOCTL:\r
+ ret = rda_wifi_power_on();\r
+ break;\r
+\r
+ case RDA_WIFI_POWER_OFF_IOCTL:\r
+ ret = rda_wifi_power_off();\r
+ break;\r
+\r
+ case RDA_WIFI_POWER_SET_TEST_MODE_IOCTL:\r
+ wifi_in_test_mode = 1;\r
+ printk("****set rda wifi in test mode");\r
+ break;\r
+\r
+ case RDA_WIFI_POWER_CANCEL_TEST_MODE_IOCTL:\r
+ wifi_in_test_mode = 0;\r
+ printk("****set rda wifi in normal mode");\r
+ break;\r
+\r
+ case RDA_WIFI_DEBUG_MODE_IOCTL:\r
+ ret = rda_wifi_debug_en();\r
+ break;\r
+ case RDA_BT_POWER_ON_IOCTL:\r
+ {\r
+ ret = rda_bt_power_on();\r
+ mt_combo_bgf_enable_irq();\r
+ }\r
+ break;\r
+\r
+ /* should call thif function after bt_power_on*/\r
+ case RDA_BT_EN_CLK:\r
+ ret = RDA5990_bt_enable_clk();\r
+ break;\r
+\r
+ case RD_BT_RF_INIT_IOCTL:\r
+ ret = RDA5990_bt_rf_init();\r
+ break;\r
+\r
+ case RD_BT_DC_CAL_IOCTL: \r
+ ret = RDA5990_bt_dc_cal();\r
+ break;\r
+\r
+ case RD_BT_DC_DIG_RESET_IOCTL: \r
+ ret = RDA5990_bt_dig_reset();\r
+ break;\r
+\r
+ case RD_BT_SET_RF_SWITCH_IOCTL:\r
+ ret = RDA5990_bt_set_rf_switch(); \r
+ break;\r
+\r
+ case RDA_BT_POWER_OFF_IOCTL:\r
+ {\r
+ mt_combo_bgf_disable_irq();\r
+ ret = rda_bt_power_off(); \r
+ }\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+\r
+ printk(KERN_INFO "rda_bt_pw_ioctl cmd=0x%02x \n", cmd);\r
+\r
+ return ret;\r
+} \r
+\r
+static int rda_5990_major;\r
+static struct class *rda_5990_class = NULL;\r
+static const struct file_operations rda_5990_operations = {\r
+ .owner = THIS_MODULE,\r
+ .unlocked_ioctl = rda_5990_pw_ioctl,\r
+ .release = NULL\r
+};\r
+\r
+void rda_5990_sleep_worker_task(struct work_struct *work)\r
+{\r
+ printk("---rda_5990_sleep_worker_task end");\r
+ wake_unlock(&rda_5990_wake_lock);\r
+}\r
+\r
+void rda_5990_set_wake_lock(void)\r
+{\r
+ wake_lock(&rda_5990_wake_lock);\r
+ cancel_delayed_work(&rda_5990_sleep_worker);\r
+ schedule_delayed_work(&rda_5990_sleep_worker, 6*HZ);\r
+}\r
+\r
+int rda_5990_power_ctrl_init(void)\r
+{\r
+ int ret = 0;\r
+\r
+ printk("rda_5990_power_ctrl_init begin\n");\r
+\r
+ rda_5990_major = register_chrdev(0, "rda5990_power_ctrl", &rda_5990_operations);\r
+ if(rda_5990_major < 0)\r
+ {\r
+ printk(KERN_INFO "register rdabt_power_ctrl failed!!! \n");\r
+ return rda_5990_major;\r
+ }\r
+\r
+ rda_5990_class = class_create(THIS_MODULE, "rda_combo");\r
+ if(IS_ERR(rda_5990_class))\r
+ {\r
+ unregister_chrdev(rda_5990_major, "rdabt_power_ctrl");\r
+ return PTR_ERR(rda_5990_class);\r
+ }\r
+\r
+ device_create(rda_5990_class, NULL, MKDEV(rda_5990_major, 0), NULL, "rdacombo");\r
+\r
+\r
+ INIT_DELAYED_WORK(&rda_5990_sleep_worker, rda_5990_sleep_worker_task);\r
+ wake_lock_init(&rda_5990_wake_lock, WAKE_LOCK_SUSPEND, "RDA_sleep_worker_wake_lock");\r
+\r
+ mutex_init(&i2c_rw_lock); \r
+ printk("rda_5990_power_ctrl_init end\n");\r
+ return 0;\r
+}\r
+\r
+void rda_5990_power_ctrl_exit(void)\r
+{\r
+\r
+ unregister_chrdev(rda_5990_major, "rdabt_power_ctrl");\r
+ if(rda_5990_class)\r
+ class_destroy(rda_5990_class); \r
+\r
+ cancel_delayed_work_sync(&rda_5990_sleep_worker);\r
+ wake_lock_destroy(&rda_5990_wake_lock);\r
+}\r
+\r
+unsigned char rda_5990_wifi_in_test_mode(void)\r
+{\r
+ return wifi_in_test_mode;\r
+}\r
+\r
+\r
+static __inline__ void cfmakeraw(struct termios *s)\r
+{\r
+ s->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);\r
+ s->c_oflag &= ~OPOST;\r
+ s->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);\r
+ s->c_cflag &= ~(CSIZE|PARENB);\r
+ s->c_cflag |= CS8;\r
+}\r
+\r
+static __inline__ int cfsetospeed(struct termios *s, speed_t speed)\r
+{\r
+ s->c_cflag = (s->c_cflag & ~CBAUD) | (speed & CBAUD);\r
+ return 0;\r
+}\r
+\r
+static __inline__ int cfsetispeed(struct termios *s, speed_t speed)\r
+{\r
+ s->c_cflag = (s->c_cflag & ~CBAUD) | (speed & CBAUD);\r
+ return 0;\r
+}\r
+\r
+static int rda_wifi_init_uart(char *dev)\r
+{\r
+ int errno;\r
+ struct termios ti;\r
+ struct serial_struct ss;\r
+ int fd;\r
+\r
+ fd = sys_open(dev, O_RDWR | O_NOCTTY, 0);\r
+ if (fd < 0) {\r
+ printk("Can't open serial port");\r
+ return -1;\r
+ }\r
+\r
+ sys_ioctl(fd, TCFLSH, TCIOFLUSH);\r
+\r
+ /* Clear the cust flag */\r
+ if((errno = sys_ioctl(fd, TIOCGSERIAL, &ss))<0){\r
+ printk("BAUD: error to get the serial_struct info:%s\n", errno);\r
+ goto err;\r
+ }\r
+\r
+ if (ss.flags & ASYNC_SPD_CUST) {\r
+ printk("clear ASYNC_SPD_CUST\r\n");\r
+ ss.flags &= ~ASYNC_SPD_CUST;\r
+ }\r
+ if((errno = sys_ioctl(fd, TIOCSSERIAL, &ss))<0){\r
+ printk("BAUD: error to set serial_struct:%s\n", errno);\r
+ goto err;\r
+ }\r
+\r
+ if ((errno = sys_ioctl(fd, TCGETS, (long)&ti)) < 0) {\r
+ printk("unable to get UART port setting");\r
+ printk("Can't get port settings");\r
+ goto err;\r
+ }\r
+\r
+ cfmakeraw(&ti);\r
+\r
+ ti.c_cflag |= CLOCAL;\r
+ ti.c_cflag &= ~CRTSCTS;\r
+ ti.c_lflag = 0;\r
+ ti.c_cc[VTIME] = 5; /* 0.5 sec */\r
+ ti.c_cc[VMIN] = 0;\r
+\r
+ /* Set initial baudrate */\r
+ cfsetospeed(&ti, B115200);\r
+ cfsetispeed(&ti, B115200);\r
+\r
+ if ((errno = sys_ioctl(fd, TCSETS, (long)&ti)) < 0) {\r
+ printk("unable to set UART port setting");\r
+ printk("Can't set port settings");\r
+ goto err;\r
+ }\r
+\r
+ errno = sys_ioctl(fd, TCFLSH, TCIOFLUSH);\r
+ if(errno < 0)\r
+ goto err;\r
+\r
+ return fd;\r
+\r
+err:\r
+ if(fd > 0)\r
+ sys_close(fd);\r
+\r
+ return -1;\r
+} \r
+\r
+EXPORT_SYMBOL(rda_wlan_version);\r
+EXPORT_SYMBOL(rda_wifi_init_uart);\r
+EXPORT_SYMBOL(rda_5990_wifi_in_test_mode);\r
+\r
+EXPORT_SYMBOL(rda_5990_set_wake_lock);\r
+EXPORT_SYMBOL(rda_wifi_power_off);\r
+EXPORT_SYMBOL(rda_wifi_power_on);\r
+EXPORT_SYMBOL(rda_fm_power_on);\r
+EXPORT_SYMBOL(rda_fm_power_off);\r
+\r
+module_init(rda_5990_power_ctrl_init);\r
+module_exit(rda_5990_power_ctrl_exit);\r
+\r
+MODULE_LICENSE("GPL");\r
+\r
--- /dev/null
+# 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.
+
+
+# Makefile generated by Mediatek
+
+obj-y += rda_gpio_i2c.o
+
--- /dev/null
+/*
+ * =====================================================================================
+ *
+ * Filename: rda_gpio_i2c.c
+ *
+ * Description:
+ *
+ * Version: 1.0
+ * Created: 04/19/2012 11:24:48 PM
+ * Revision: none
+ * Compiler: gcc
+ *
+ * Author: Allen_Hu
+ * Organization: RDA Inc.
+ *
+ * =====================================================================================
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+
+#include <mach/mt6575_gpio.h>
+#include <mach/mtk_rtc.h>
+
+#define RDA5990_WIFI_32K_FLAG 0x00000001
+#define RDA5990_BT_32K_FLAG 0x00000002
+#define RDA5990_FM_32K_FLAG 0x00000004
+
+//#define DELAY 10
+#define DELAY 2
+// FM
+#define SCL GPIO149
+#define SDA GPIO150
+//
+/* WIFI
+#define SCL GPIO104
+#define SDA GPIO102
+*/
+
+#define u8 unsigned char
+
+//Data storage mode
+static u8 isBigEnded = 0;
+
+//The global variable
+static unsigned int gpioInitialized = 0;
+static unsigned int rda5990_32k_state = 0;
+
+#define GPIO_MODE_00 0
+#define GPIO_DIR_OUT 1
+#define GPIO_DIR_IN 0
+#define GPIO_OUT_ONE 1
+#define GPIO_OUT_ZERO 0
+
+void set_SDA_output(void)
+{
+ mt_set_gpio_mode(SDA, GPIO_MODE_00);
+ mt_set_gpio_dir(SDA, GPIO_DIR_OUT);
+}
+
+void set_SDA_input(void)
+{
+ mt_set_gpio_mode(SDA, GPIO_MODE_00);
+ mt_set_gpio_dir(SDA, GPIO_DIR_IN);
+}
+
+void set_SCL_output(void)
+{
+ mt_set_gpio_mode(SCL, GPIO_MODE_00);
+ mt_set_gpio_dir(SCL, GPIO_DIR_OUT);
+}
+
+void set_SDA_high(void)
+{
+ mt_set_gpio_out(SDA, GPIO_OUT_ONE);
+}
+
+void set_SDA_low(void)
+{
+ mt_set_gpio_out(SDA, GPIO_OUT_ZERO);
+}
+
+void set_SCL_high(void)
+{
+ mt_set_gpio_out(SCL, GPIO_OUT_ONE);
+}
+
+void set_SCL_low(void)
+{
+ mt_set_gpio_out(SCL, GPIO_OUT_ZERO);
+}
+
+u8 get_SDA_bit(void)
+{
+ return mt_get_gpio_in(SDA);
+}
+
+void i2c_delay(unsigned short cnt)
+{
+ udelay(cnt);
+}
+
+//如果32k不能出来,请修改以下配置使能。
+void enable_32k_rtc(void)
+{
+ printk("enable 32k rtc called\n");
+ rtc_gpio_enable_32k(RTC_GPIO_USER_GPS);
+ //rtc_gpio_enable_32k(RTC_GPIO_USER_WIFI);
+ //rtc_gpio_enable_32k(RTC_GPIO_USER_BT);
+ //rtc_gpio_enable_32k(RTC_GPIO_USER_WIFI);
+ rtc_gpio_enable_32k(RTC_GPIO_USER_FM);
+ msleep(100);
+}
+
+void disable_32k_rtc(void)
+{
+ //rtc_gpio_disable_32k(RTC_GPIO_USER_WIFI);
+ rtc_gpio_enable_32k(RTC_GPIO_USER_GPS);
+ rtc_gpio_disable_32k(RTC_GPIO_USER_FM);
+ msleep(50);
+}
+
+void i2c_start(void)
+{
+ set_SDA_output();
+ set_SCL_output();
+
+ set_SDA_high();
+ i2c_delay(DELAY);
+ set_SCL_high();
+ i2c_delay(DELAY);
+
+ set_SDA_low();
+ i2c_delay(DELAY);
+ set_SCL_low();
+ i2c_delay(DELAY);
+}
+
+void i2c_stop(void)
+{
+ set_SDA_output();
+ set_SCL_output();
+ set_SDA_low();
+ i2c_delay(DELAY);
+ set_SCL_high();
+ i2c_delay(4*DELAY);
+ set_SDA_high();
+ i2c_delay(4*DELAY);
+}
+
+
+/*
+ * return value:
+ * 0 --- 收到ACK
+ * 1 --- 没收到ACK
+ */
+u8 i2c_send_byte(u8 send_byte)
+{
+ u8 rc = 0;
+ u8 out_mask = 0x80;
+ u8 value;
+ u8 count = 8;
+
+ set_SDA_output();
+ set_SCL_output();
+
+ while(count > 0) {
+ set_SCL_low();
+ i2c_delay(DELAY);
+ value = ((send_byte & out_mask) ? 1 : 0);
+ if (value == 1) {
+ set_SDA_high();
+ }
+ else {
+ set_SDA_low();
+ }
+ send_byte <<= 1;
+ i2c_delay(DELAY);
+
+ set_SCL_high();
+ i2c_delay(DELAY);
+
+ count--;
+ }
+ set_SCL_low();
+ set_SDA_input();
+ i2c_delay(4*DELAY);
+ set_SCL_high();
+ i2c_delay(DELAY);
+ rc = get_SDA_bit();
+ i2c_delay(DELAY);
+ set_SCL_low();
+
+ return rc;
+}
+
+/*
+ * ack = 0 发送ACK
+ * ack = 1 不发送ACK
+ */
+void i2c_read_byte(u8 *buffer, u8 ack)
+{
+ u8 count = 0x08;
+ u8 data = 0x00;
+ u8 temp = 0;
+
+ set_SCL_output();
+ while(count > 0) {
+ set_SCL_low();
+ i2c_delay(2*DELAY);
+ if(count == 8)
+ set_SDA_input();
+ i2c_delay(DELAY);
+ set_SCL_high();
+ i2c_delay(2*DELAY);
+ temp = get_SDA_bit();
+ data <<= 1;
+ if (temp)
+ data |= 0x01;
+
+ i2c_delay(DELAY);
+ count--;
+ }
+
+ set_SCL_low();
+ i2c_delay(2*DELAY);
+ set_SDA_output();
+ i2c_delay(DELAY);
+ if(ack){
+ set_SDA_high();
+ }else{
+ set_SDA_low();
+ }
+ i2c_delay(DELAY);
+ set_SCL_high();
+ i2c_delay(2*DELAY);
+
+ *buffer = data;
+ set_SCL_low();
+}
+
+/*
+* write data to the I2C bus by GPIO simulated of a digital device rountine.
+*
+* @param
+* chipAddr: address of the device
+* regAddr: address of register within device
+* data: the data to be written
+* len: the data length
+*
+*/
+int rda_gpio_i2c_write_1_addr_2_data(u8 chipAddr, u8 regAddr, unsigned short data)
+{
+ u8 acknowledge;
+ int ret = 0;
+ i2c_start();
+
+ acknowledge = i2c_send_byte((chipAddr << 1) | 0x00);
+ if(acknowledge == 1){
+ // return -1;
+ ret = -1;
+ goto out;
+ }
+
+ acknowledge = i2c_send_byte(regAddr);
+ if(acknowledge == 1){
+ ret = -1;
+ goto out;
+ }
+
+ acknowledge = i2c_send_byte(data>>8);
+ if(acknowledge == 1){
+ ret = -1;
+ goto out;
+ }
+ acknowledge = i2c_send_byte(data);
+ ret = acknowledge;
+
+out:
+ i2c_stop();
+
+ //return acknowledge;
+ return ret;
+}
+/*
+* read data from the I2C bus by GPIO simulated of a digital device rountine.
+*
+* @param
+* chipAddr: address of the device
+* regAddr: address of register within device
+* buffer: the data to be stored
+* len: the data length
+*
+*/
+int rda_gpio_i2c_read_1_addr_2_data(u8 chipAddr, u8 regAddr, unsigned short *buffer)
+{
+ u8 tempdata, acknowledge;
+ int ret = 0;
+
+ i2c_start();
+ acknowledge = i2c_send_byte( (chipAddr << 1) | 0x00 );
+ if(acknowledge == 1){
+ ret = -1;
+ goto out;
+ }
+ acknowledge = i2c_send_byte(regAddr);
+ if(acknowledge == 1){
+ ret = -1;
+ goto out;
+ }
+
+ i2c_start();//restart
+ acknowledge = i2c_send_byte( (chipAddr << 1) | 0x01 );
+ if(acknowledge == 1){
+ ret = -1;
+ goto out;
+ }
+
+ i2c_read_byte(&tempdata, 0);
+ *buffer = (tempdata<<8);
+ i2c_read_byte(&tempdata, 1);
+ *buffer |= tempdata;
+
+out:
+ i2c_stop();
+// return acknowledge;
+ return ret;
+}
+
+u8 rda_gpio_i2c_write_4_addr_4_data(u8 chipAddr, unsigned int regAddr, unsigned int data)
+{
+ u8 acknowledge;
+ i2c_start();
+
+ acknowledge = i2c_send_byte((chipAddr << 1) | 0x00);
+ acknowledge = i2c_send_byte(regAddr>>24);
+ acknowledge = i2c_send_byte(regAddr>>16);
+ acknowledge = i2c_send_byte(regAddr>>8);
+ acknowledge = i2c_send_byte(regAddr);
+
+ acknowledge = i2c_send_byte((chipAddr << 1) | 0x00);
+
+ acknowledge = i2c_send_byte(data>>24);
+ acknowledge = i2c_send_byte(data>>16);
+ acknowledge = i2c_send_byte(data>>8);
+ acknowledge = i2c_send_byte(data);
+
+ i2c_stop();
+ return acknowledge;
+}
+
+u8 rda_gpio_i2c_read_4_addr_4_data(u8 chipAddr, unsigned int regAddr, unsigned int *buffer)
+{
+ u8 tempdata, acknowledge;
+ u8 i = 0;
+
+ i2c_start();
+ acknowledge = i2c_send_byte( (chipAddr << 1) | 0x00 );
+ acknowledge = i2c_send_byte(regAddr>>24);
+ acknowledge = i2c_send_byte(regAddr>>16);
+ acknowledge = i2c_send_byte(regAddr>>8);
+ acknowledge = i2c_send_byte(regAddr);
+
+ i2c_start();//restart
+ acknowledge = i2c_send_byte( (chipAddr << 1) | 0x01 );
+
+ i2c_read_byte(&tempdata, 0);
+ *buffer = (tempdata<<24);
+ i2c_read_byte(&tempdata, 0);
+ *buffer |= (tempdata<<16);
+ i2c_read_byte(&tempdata, 0);
+ *buffer |= (tempdata<<8);
+ i2c_read_byte(&tempdata, 1);
+ *buffer |= tempdata;
+
+ i2c_stop();
+ return acknowledge;
+}
+
+void rda_gpio_i2c_enable_32k(unsigned int flag)
+{
+ if(rda5990_32k_state == 0 )
+ {
+ enable_32k_rtc();
+ }
+ rda5990_32k_state |= (flag&0x07);
+}
+
+void rda_gpio_i2c_disable_32k(unsigned int flag)
+{
+ rda5990_32k_state &= (~flag);
+ if(rda5990_32k_state == 0)
+ disable_32k_rtc();
+}
+
+/*
+* initializes I2C interface routine.
+*
+* @return value:
+* 0--success;
+* 1--error.
+*
+*/
+static int __init rda_gpio_i2c_init(void)
+{
+ if(gpioInitialized == 0){
+ printk(KERN_INFO "RDA GPIO control for I2C Driver \n");
+
+ unsigned char *temp = NULL;
+ unsigned short testData = 0xaa55;
+ temp = (unsigned char *)&testData;
+ if(*temp == 0x55){
+ isBigEnded = 0;
+ }else{
+ isBigEnded = 1;
+ }
+
+
+ gpioInitialized = 1;
+ rda_gpio_i2c_enable_32k(RDA5990_FM_32K_FLAG);
+
+ /* FM
+ unsigned short regValue = 0;
+ rda_gpio_i2c_read_1_addr_2_data(0x11, 0x0C, ®Value);
+ printk(KERN_ALERT "####[%s, %d], Addr=%02X, value=%04X\n", __func__, __LINE__, 0x0C, regValue);
+ */
+ /*WIFI
+ unsigned short regValue = 0x0001;
+ rda_gpio_i2c_write_1_addr_2_data(0x14, 0x3f, regValue);
+ regValue = 0;
+ rda_gpio_i2c_read_1_addr_2_data(0x14, 0x3f, ®Value);
+ printk(KERN_ALERT "####[%s, %d], Addr=%02X, value=%04X\n", __func__, __LINE__, 0x3f, regValue);
+ regValue = 0;
+ rda_gpio_i2c_read_1_addr_2_data(0x14, 0x20, ®Value);
+ printk(KERN_ALERT "####[%s, %d], Addr=%02X, value=%04X\n", __func__, __LINE__, 0x20, regValue);
+ */
+
+ return 0;
+ }else{
+ printk("RDA GPIO control for I2C has been initialized.\n");
+ return 0;
+ }
+}
+
+static void __exit rda_gpio_i2c_exit(void)
+{
+ gpioInitialized = 0;
+ rda_gpio_i2c_disable_32k(RDA5990_FM_32K_FLAG);
+}
+
+EXPORT_SYMBOL(rda_gpio_i2c_read_1_addr_2_data);
+EXPORT_SYMBOL(rda_gpio_i2c_write_1_addr_2_data);
+EXPORT_SYMBOL(rda_gpio_i2c_enable_32k);
+EXPORT_SYMBOL(rda_gpio_i2c_disable_32k);
+
+EXPORT_SYMBOL(rda_gpio_i2c_read_4_addr_4_data);
+EXPORT_SYMBOL(rda_gpio_i2c_write_4_addr_4_data);
+
+module_init(rda_gpio_i2c_init); /* load the module */
+module_exit(rda_gpio_i2c_exit); /* unload the module */
--- /dev/null
+obj-m := rda5890.o
+rda5890-objs := \
+ rda5890_if_sdio.o \
+ rda5890_dev.o \
+ rda5890_txrx.o \
+ rda5890_wid.o \
+ rda5890_wext.o \
+ rda5890_debugfs.o\
+ rda5890_sdio_patch.o\
+ rda5890_nvram.o\
+ rda5890_scan.o
+
+KERNEL_DIR = /home/dxj/share/rk2928/kernel
+
+all:
+ make -C $(KERNEL_DIR) M=`pwd` modules
+
+clean:
+ rm -f Module.symvers *.o modules.order *.ko wifi_launcher.mod.c
+ rm -rf .wifi* .tmp* wlan.mod.c
\ No newline at end of file
--- /dev/null
+MODULE_NAME = rda5890
+CONFIG_RDA5890 = m
+$(MODULE_NAME)-y += \
+ rda5890_if_sdio.o \
+ rda5890_dev.o \
+ rda5890_txrx.o \
+ rda5890_wid.o \
+ rda5890_wext.o \
+ rda5890_debugfs.o\
+ rda5890_sdio_patch.o\
+ rda5890_nvram.o\
+ rda5890_scan.o
+
+obj-$(CONFIG_RDA5890) += $(MODULE_NAME).o
+
+KERNEL_DIR = /home/dxj/share/rk2928/kernel
+
+all:
+ make -C $(KERNEL_DIR) M=`pwd` modules
+
+clean:
+ rm -f Module.symvers *.o modules.order *.ko wifi_launcher.mod.c
+ rm -rf .wifi* .tmp* wlan.mod.c
\ No newline at end of file
--- /dev/null
+#include <linux/module.h>
+#include <linux/dcache.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <net/iw_handler.h>
+
+#include "rda5890_defs.h"
+#include "rda5890_dev.h"
+
+static struct dentry *rda5890_dir = NULL;
+
+void dump_buf(char *data, size_t len)
+{
+ char temp_buf[64];
+ size_t i, off = 0;
+
+ memset(temp_buf, 0, 64);
+ for (i=0;i<len;i++) {
+ if(i%8 == 0) {
+ sprintf(&temp_buf[off], " ");
+ off += 2;
+ }
+ sprintf(&temp_buf[off], "%02x ", data[i]);
+ off += 3;
+ if((i+1)%16 == 0) {
+ RDA5890_DBGLAP(RDA5890_DA_ALL, RDA5890_DL_TRACE,
+ "%s\n", temp_buf);
+ memset(temp_buf, 0, 64);
+ off = 0;
+ }
+ }
+ RDA5890_DBGLAP(RDA5890_DA_ALL, RDA5890_DL_TRACE, "\n");
+}
+
+static int open_file_generic(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+#if 0
+static ssize_t rda5890_write_file_dummy(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ return -EINVAL;
+}
+#endif
+
+static ssize_t rda5890_debug_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ //struct rda5890_private *priv = file->private_data;
+ size_t pos = 0;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+ ssize_t res;
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
+ "%s\n", __func__);
+
+ pos += snprintf(buf+pos, PAGE_SIZE - pos, "state = %s\n",
+ "LWANG_TESTING");
+
+ res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+
+ free_page(addr);
+ return res;
+}
+
+static ssize_t rda5890_debug_write(struct file *file,
+ const char __user *user_buf, size_t count,
+ loff_t *ppos)
+{
+ //struct rda5890_private *priv = file->private_data;
+ ssize_t ret;
+ int p1, p2, p3, p4;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
+ "%s\n", __func__);
+
+ if (copy_from_user(buf, user_buf, count)) {
+ ret = -EFAULT;
+ goto out_unlock;
+ }
+ ret = sscanf(buf, "%d %d %d %d", &p1, &p2, &p3, &p4);
+ if (ret != 4) {
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
+ "input p1 = %d, p2 = %d, p3 = %d, p4 = %d\n",
+ p1, p2, p3, p4);
+
+ ret = count;
+out_unlock:
+ free_page(addr);
+ return ret;
+}
+
+static ssize_t rda5890_debugarea_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ //struct rda5890_private *priv = file->private_data;
+ size_t pos = 0;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+ ssize_t res;
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
+ "%s\n", __func__);
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
+ "get debug_area = 0x%x\n",rda5890_dbg_area);
+
+ pos += snprintf(buf+pos, PAGE_SIZE - pos, "%x\n",
+ rda5890_dbg_area);
+
+ res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+
+ free_page(addr);
+ return res;
+}
+
+static ssize_t rda5890_debugarea_write(struct file *file,
+ const char __user *user_buf, size_t count,
+ loff_t *ppos)
+{
+ //struct rda5890_private *priv = file->private_data;
+ ssize_t ret;
+ int debug_area;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
+ "%s\n", __func__);
+
+ 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;
+ }
+
+ rda5890_dbg_area = debug_area;
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
+ "set debug_area = 0x%x\n",rda5890_dbg_area);
+
+ ret = count;
+out_unlock:
+ free_page(addr);
+ return ret;
+}
+
+static ssize_t rda5890_debuglevel_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ //struct rda5890_private *priv = file->private_data;
+ size_t pos = 0;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+ ssize_t res;
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
+ "%s\n", __func__);
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
+ "get debug_level = 0x%x\n",rda5890_dbg_level);
+
+ pos += snprintf(buf+pos, PAGE_SIZE - pos, "%x\n",
+ rda5890_dbg_level);
+
+ res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+
+ free_page(addr);
+ return res;
+}
+
+static ssize_t rda5890_debuglevel_write(struct file *file,
+ const char __user *user_buf, size_t count,
+ loff_t *ppos)
+{
+ //struct rda5890_private *priv = file->private_data;
+ ssize_t ret;
+ int debug_level;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_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;
+ }
+
+ rda5890_dbg_level = debug_level;
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
+ "set debug_level = 0x%x\n",rda5890_dbg_level);
+
+ ret = count;
+out_unlock:
+ free_page(addr);
+ return ret;
+}
+
+static int debug_read_flag = 0;
+
+static ssize_t rda5890_sdio_read(struct file *file,
+ const char __user *user_buf, size_t count,
+ loff_t *ppos)
+{
+ //struct rda5890_private *priv = file->private_data;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+ int ret;
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
+ "%s\n", __func__);
+
+ if (copy_from_user(buf, user_buf, count)) {
+ ret = -EFAULT;
+ goto out_unlock;
+ }
+ ret = sscanf(buf, "%d", &debug_read_flag);
+ if (ret != 1) {
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+out_unlock:
+ free_page(addr);
+ return count;
+}
+
+static ssize_t rda5890_sdio_write(struct file *file,
+ const char __user *user_buf, size_t count,
+ loff_t *ppos)
+{
+ struct rda5890_private *priv = file->private_data;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+ int iter, len, i;
+ int ret;
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
+ "%s\n", __func__);
+
+ if (copy_from_user(buf, user_buf, count)) {
+ ret = -EFAULT;
+ goto out_unlock;
+ }
+ ret = sscanf(buf, "%d %d", &iter, &len);
+ if (ret != 2) {
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+ if (len > 1660) {
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+ for (i=0; i<len; i++) {
+ buf[i] = len - i - 1;
+ }
+
+ for (i=0;i<iter;i++) {
+ //RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
+ // "Host to Card, len = %d\n", len);
+
+ ret = priv->hw_host_to_card(priv, buf, len, DATA_REQUEST_PACKET);
+
+ //RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
+ // "Host to Card done, ret = %d\n", ret);
+ }
+
+out_unlock:
+ free_page(addr);
+ return count;
+}
+
+#define SDIO_TEST_CMD_MAGIC 0x55664433
+#define SDIO_TEST_CMD_LEN 16
+
+#define SDIO_TEST_CMD_TYPE_H2C_START 1
+#define SDIO_TEST_CMD_TYPE_H2C_STOP 2
+#define SDIO_TEST_CMD_TYPE_H2C_STATUS 3
+#define SDIO_TEST_CMD_TYPE_C2H_START 4
+#define SDIO_TEST_CMD_TYPE_C2H_PILOT 5
+#define SDIO_TEST_CMD_TYPE_C2H_END 6
+
+static int recv_time_start, recv_time_end;
+static int send_time_start, send_time_end;
+
+void rda5890_sdio_test_card_to_host(char *buf, unsigned short len)
+{
+ int i;
+ int cmd, cmd_iter, cmd_len;
+ int time_ms;
+ static int recv_pattern = 0;
+ static int recv_tput_flag = 0;
+ static int recv_pkts = 0;
+ static int recv_bytes = 0;
+
+ //RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
+ // "SDIO TEST Card to Host, len = %d\n", len);
+
+ if (debug_read_flag) {
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
+ "DEBUG RX, len = %d\n", len);
+ dump_buf(buf, len);
+ }
+
+ if ((*(volatile unsigned long *)buf == SDIO_TEST_CMD_MAGIC)
+ && len == SDIO_TEST_CMD_LEN) {
+ cmd = (int)(*(volatile unsigned long *)(buf + 4));
+ cmd_iter = (int)(*(volatile unsigned long *)(buf + 8));
+ cmd_len = (int)(*(volatile unsigned long *)(buf + 12));
+ //RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
+ // "SDIO TEST CMD: cmd = %d, iter = %d, len = %d\n",
+ // cmd, cmd_iter, cmd_len);
+ switch (cmd) {
+ case SDIO_TEST_CMD_TYPE_H2C_STATUS:
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
+ "H2C STATUS CMD \n");
+ time_ms = jiffies_to_msecs(send_time_end - send_time_start);
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
+ "SDIO H2C STATUS: pkts = %d, bytes = %d, time = %d ms\n",
+ cmd_iter, cmd_len, time_ms);
+ break;
+ case SDIO_TEST_CMD_TYPE_C2H_PILOT:
+ //RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
+ // "C2H PILOT CMD \n");
+ recv_pattern = 0;
+ recv_tput_flag = 1;
+ recv_pkts = 0;
+ recv_bytes = 0;
+ recv_time_start = jiffies;
+ break;
+ case SDIO_TEST_CMD_TYPE_C2H_END:
+ //RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
+ // "C2H END CMD \n");
+ recv_time_end = jiffies;
+ recv_tput_flag = 0;
+ time_ms = jiffies_to_msecs(recv_time_end - recv_time_start);
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
+ "SDIO C2H STATUS: pkts = %d, bytes = %d, time = %d ms\n",
+ recv_pkts, recv_bytes, time_ms);
+ break;
+ case SDIO_TEST_CMD_TYPE_H2C_START:
+ case SDIO_TEST_CMD_TYPE_H2C_STOP:
+ case SDIO_TEST_CMD_TYPE_C2H_START:
+ default:
+ RDA5890_ERRP("SDIO TEST CMD: Invalid cmd %d\n", cmd);
+ break;
+ }
+ return;
+ }
+
+ for (i=0;i<len;i++) {
+ if (recv_pattern == 0) {
+ if (buf[i] != (char)(i)) {
+ RDA5890_ERRP("data[%d] error, 0x%02x, should be 0x%02x, len = %d\n",
+ i, buf[i], (char)(i), len);
+ break;
+ }
+ }
+ else {
+ if (buf[i] != (char)(len - i - 1)) {
+ RDA5890_ERRP("data[%d] error, 0x%02x, should be 0x%02x, len = %d\n",
+ i, buf[i], (char)(len - i - 1), len);
+ break;
+ }
+ }
+ }
+
+ if (recv_tput_flag)
+ recv_pattern = !recv_pattern;
+
+ if (recv_tput_flag && i==len) {
+ recv_pkts ++;
+ recv_bytes += len;
+ }
+}
+
+static void sdio_tput_test_read(struct rda5890_private *priv, int iter, int len)
+{
+ char cmd[SDIO_TEST_CMD_LEN];
+ int ret;
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
+ "%s, iter = %d, len = %d\n", __func__, iter, len);
+
+ (*(volatile unsigned long *)(cmd + 0)) = SDIO_TEST_CMD_MAGIC;
+ (*(volatile unsigned long *)(cmd + 4)) = SDIO_TEST_CMD_TYPE_C2H_START;
+ (*(volatile unsigned long *)(cmd + 8)) = iter;
+ (*(volatile unsigned long *)(cmd + 12)) = len;
+ ret = priv->hw_host_to_card(priv, cmd, len ,SDIO_TEST_CMD_LEN);
+ if (ret) {
+ RDA5890_ERRP("START cmd send fail, ret = %d\n", ret);
+ }
+}
+
+static void sdio_tput_test_write(struct rda5890_private *priv, int iter, int len)
+{
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf_1 = (char *)addr;
+ char *buf_2 = (char *)addr + PAGE_SIZE/2;
+ char cmd[SDIO_TEST_CMD_LEN];
+ int i;
+ int ret;
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
+ "%s, iter = %d, len = %d\n", __func__, iter, len);
+
+ for (i=0; i<len; i++) {
+ buf_1[i] = len - i - 1;
+ buf_2[i] = i;
+ }
+
+ (*(volatile unsigned long *)(cmd + 0)) = SDIO_TEST_CMD_MAGIC;
+ (*(volatile unsigned long *)(cmd + 4)) = SDIO_TEST_CMD_TYPE_H2C_START;
+ (*(volatile unsigned long *)(cmd + 8)) = iter;
+ (*(volatile unsigned long *)(cmd + 12)) = len;
+ ret = priv->hw_host_to_card(priv, cmd, len,SDIO_TEST_CMD_LEN);
+ if (ret) {
+ RDA5890_ERRP("START cmd send fail, ret = %d\n", ret);
+ goto out;
+ }
+
+ send_time_start = jiffies;
+ for (i=0;i<iter;i++) {
+ if (!(i & 1))
+ ret = priv->hw_host_to_card(priv, buf_1, len, DATA_REQUEST_PACKET);
+ else
+ ret = priv->hw_host_to_card(priv, buf_2, len, DATA_REQUEST_PACKET);
+ if (ret) {
+ RDA5890_ERRP("packet %d send fail, ret = %d\n", i, ret);
+ goto out;
+ }
+ }
+ send_time_end = jiffies;
+
+ (*(volatile unsigned long *)(cmd + 0)) = SDIO_TEST_CMD_MAGIC;
+ (*(volatile unsigned long *)(cmd + 4)) = SDIO_TEST_CMD_TYPE_H2C_STOP;
+ (*(volatile unsigned long *)(cmd + 8)) = iter;
+ (*(volatile unsigned long *)(cmd + 12)) = len;
+ ret = priv->hw_host_to_card(priv, cmd, len, SDIO_TEST_CMD_LEN);
+ if (ret) {
+ RDA5890_ERRP("START cmd send fail, ret = %d\n", ret);
+ goto out;
+ }
+
+out:
+ free_page(addr);
+}
+
+static ssize_t rda5890_sdio_tput(struct file *file,
+ const char __user *user_buf, size_t count,
+ loff_t *ppos)
+{
+ struct rda5890_private *priv = file->private_data;
+ int ret;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+ int wr, iter, len;
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
+ "%s\n", __func__);
+
+ if (copy_from_user(buf, user_buf, count)) {
+ ret = -EFAULT;
+ goto out_unlock;
+ }
+ ret = sscanf(buf, "%d %d %d", &wr, &iter, &len);
+ if (ret != 3) {
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
+ "Error Input, format shall be [wr iter len]\n");
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
+ "input wr = %d, iter = %d, len = %d\n",
+ wr, iter, len);
+
+ if (wr)
+ sdio_tput_test_write(priv, iter, len);
+ else
+ sdio_tput_test_read(priv, iter, len);
+
+ ret = count;
+out_unlock:
+ free_page(addr);
+ return ret;
+}
+
+#define FOPS(fread, fwrite) { \
+ .owner = THIS_MODULE, \
+ .open = open_file_generic, \
+ .read = (fread), \
+ .write = (fwrite), \
+}
+
+struct rda5890_debugfs_files {
+ char *name;
+ int perm;
+ struct file_operations fops;
+};
+
+static struct rda5890_debugfs_files debugfs_files[] = {
+ { "debug", 0444, FOPS(rda5890_debug_read, rda5890_debug_write), },
+ { "debugarea", 0444, FOPS(rda5890_debugarea_read, rda5890_debugarea_write), },
+ { "debuglevel", 0444, FOPS(rda5890_debuglevel_read, rda5890_debuglevel_write), },
+ { "sdioread", 0444, FOPS(NULL, rda5890_sdio_read), },
+ { "sdiowrite", 0444, FOPS(NULL, rda5890_sdio_write), },
+ { "sdiotput", 0444, FOPS(NULL, rda5890_sdio_tput), },
+};
+
+void rda5890_debugfs_init(void)
+{
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
+ "%s\n", __func__);
+
+ if (!rda5890_dir)
+ rda5890_dir = debugfs_create_dir("rda5890", NULL);
+
+ return;
+}
+
+void rda5890_debugfs_remove(void)
+{
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
+ "%s\n", __func__);
+
+ if (rda5890_dir)
+ debugfs_remove(rda5890_dir);
+
+ return;
+}
+
+void rda5890_debugfs_init_one(struct rda5890_private *priv)
+{
+ int i;
+ struct rda5890_debugfs_files *files;
+ if (!rda5890_dir)
+ goto exit;
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
+ "%s\n", __func__);
+
+ priv->debugfs_dir = debugfs_create_dir("rda5890_dev", rda5890_dir);
+ if (!priv->debugfs_dir)
+ goto exit;
+
+ for (i=0; i<ARRAY_SIZE(debugfs_files); i++) {
+ files = &debugfs_files[i];
+ priv->debugfs_files[i] = debugfs_create_file(files->name,
+ files->perm,
+ priv->debugfs_dir,
+ priv,
+ &files->fops);
+ }
+
+exit:
+ return;
+}
+
+void rda5890_debugfs_remove_one(struct rda5890_private *priv)
+{
+ int i;
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
+ "%s\n", __func__);
+
+ for(i=0; i<ARRAY_SIZE(debugfs_files); i++)
+ debugfs_remove(priv->debugfs_files[i]);
+ debugfs_remove(priv->debugfs_dir);
+}
+
--- /dev/null
+#ifndef _RDA5890_DEBUGFS_H_
+#define _RDA5890_DEBUGFS_H_
+
+void rda5890_debugfs_init(void);
+void rda5890_debugfs_remove(void);
+
+void rda5890_debugfs_init_one(struct rda5890_private *priv);
+void rda5890_debugfs_remove_one(struct rda5890_private *priv);
+
+/* This is for SDIO testing */
+void rda5890_sdio_test_card_to_host(char *buf, unsigned short len);
+
+#endif
--- /dev/null
+#ifndef _RDA5890_DEFS_H_
+#define _RDA5890_DEFS_H_
+
+#include <linux/spinlock.h>
+
+#define RDA5890_SDIOWIFI_VER_MAJ 0
+#define RDA5890_SDIOWIFI_VER_MIN 3
+#define RDA5890_SDIOWIFI_VER_BLD 1
+
+#define WIFI_POWER_MANAGER //if need wifi sleep for power save should open this
+
+
+#define WIFI_UNLOCK_SYSTEM
+#define GET_SCAN_FROM_NETWORK_INFO
+
+#define USE_MAC_DYNAMIC_ONCE
+//#define WIFI_TEST_MODE
+
+#define DEBUG
+
+extern int rda5890_dbg_level;
+extern int rda5890_dbg_area;
+
+typedef enum {
+ RDA5890_DL_ALL = 0,
+ RDA5890_DL_CRIT = 1,
+ RDA5890_DL_TRACE = 2,
+ RDA5890_DL_NORM = 3,
+ RDA5890_DL_DEBUG = 4,
+ RDA5890_DL_VERB = 5,
+} RDA5890_DBG_LEVEL;
+
+#define RDA5890_DA_MAIN (1 << 0)
+#define RDA5890_DA_SDIO (1 << 1)
+#define RDA5890_DA_ETHER (1 << 2)
+#define RDA5890_DA_WID (1 << 3)
+#define RDA5890_DA_WEXT (1 << 4)
+#define RDA5890_DA_TXRX (1 << 5)
+#define RDA5890_DA_PM (1 << 6)
+#define RDA5890_DA_ALL 0x0000007f
+
+#define RDA5890_LOG "RDA5890: "
+#ifndef DEBUG
+#define DEBUG
+#endif
+
+#ifdef DEBUG
+#define RDA5890_DBGLA(area, lvl) \
+ (((lvl)<=rda5890_dbg_level) && ((area)&rda5890_dbg_area))
+#define RDA5890_DBGLAP(area,lvl, x...) \
+ do{ \
+ if (((lvl)<=rda5890_dbg_level) && ((area)&rda5890_dbg_area)) \
+ printk(KERN_INFO RDA5890_LOG x ); \
+ }while(0)
+#define RDA5890_DBGP(x...) \
+ do{ \
+ printk(KERN_INFO RDA5890_LOG x ); \
+ }while(0)
+#else
+#define RDA5890_DBGLA(area, lvl) 0
+#define RDA5890_DBGLAP(area,lvl, x...) do {} while (0)
+#define RDA5890_DBGP(x...) do {} while (0)
+#endif
+
+#define RDA5890_ERRP(fmt, args...) \
+ do{ \
+ printk(KERN_ERR RDA5890_LOG "%s: "fmt, __func__, ## args ); \
+ }while(0)
+
+#endif
+
--- /dev/null
+/**
+ * This file contains the major functions in WLAN
+ * driver. It includes init, exit, open, close and main
+ * thread etc..
+ */
+
+#include <linux/moduleparam.h>
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/kthread.h>
+#include <linux/kfifo.h>
+#include <linux/stddef.h>
+#include <linux/mmc/sdio_func.h>
+
+
+#include <net/iw_handler.h>
+#include <linux/jiffies.h>
+
+
+#include "rda5890_defs.h"
+#include "rda5890_dev.h"
+#include "rda5890_ioctl.h"
+#include "rda5890_wid.h"
+#include "rda5890_wext.h"
+#include "rda5890_txrx.h"
+#include "rda5890_if_sdio.h"
+
+int rda5890_sleep_flags = RDA_SLEEP_ENABLE | RDA_SLEEP_PREASSO;
+
+#ifdef WIFI_UNLOCK_SYSTEM
+atomic_t wake_lock_counter;
+struct wake_lock sleep_worker_wake_lock;
+#endif
+
+
+int rda5890_init_pm(struct rda5890_private *priv)
+{
+#ifdef WIFI_POWER_MANAGER
+ int ret = 0;
+ struct if_sdio_card *card = (struct if_sdio_card *)priv->card;
+
+#ifdef WIFI_TEST_MODE
+ if(rda_5990_wifi_in_test_mode())
+ return 0;
+#endif
+ if (rda5890_sleep_flags & RDA_SLEEP_ENABLE)
+ {
+ ret = rda5890_set_pm_mode(priv, 2);
+ if(ret < 0)
+ goto err;
+ }
+ if (rda5890_sleep_flags & RDA_SLEEP_PREASSO)
+ {
+ ret = rda5890_set_preasso_sleep(priv, 0x00800080);
+ if(ret < 0)
+ goto err;
+ }
+
+ sdio_claim_host(card->func);
+ sdio_writeb(card->func, 1, IF_SDIO_FUN1_INT_TO_DEV, &ret);
+ sdio_release_host(card->func);
+ if (ret) {
+ RDA5890_ERRP("write FUN1_INT_TO_DEV reg fail\n");
+ }
+
+ atomic_inc(&priv->sleep_flag);
+
+err:
+ return ret;
+#else
+ return 0;
+#endif
+}
+
+
+int rda5890_disable_self_cts(struct rda5890_private *priv)
+{
+ int ret = 0;
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_TRACE,
+ "Set rda5890_disable_self_cts 0x%02x\n", 0);
+
+ ret = rda5890_generic_set_uchar(priv, WID_PTA_MODE, 0);
+ if(ret < 0)
+ goto err;
+ return 0;
+
+err:
+ return ret;
+}
+
+int rda5890_disable_block_bt(struct rda5890_private *priv)
+{
+ int ret = 0;
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_TRACE,
+ "Set rda5890_disable_block_bt 0x%02x\n", 0);
+
+ ret = rda5890_generic_set_uchar(priv, WID_PTA_BLOCK_BT, 0);
+ if(ret < 0)
+ goto err;
+
+ return 0;
+
+err:
+ return ret;
+}
+
+//rda5890_set_scan_timeout has defined WID_ACTIVE_SCAN_TIME so if you call that func, not need call this
+int rda5890_set_active_scan_time(struct rda5890_private *priv)
+{
+ int ret = 0;
+ ret= rda5890_generic_set_ushort(priv, WID_ACTIVE_SCAN_TIME, 200);
+ if(ret < 0)
+ goto err;
+ return 0;
+ err:
+ return ret;
+}
+
+/**
+ * @brief This function opens the ethX or mshX interface
+ *
+ * @param dev A pointer to net_device structure
+ * @return 0 or -EBUSY if monitor mode active
+ */
+static int rda5890_dev_open(struct net_device *dev)
+{
+ struct rda5890_private *priv = (struct rda5890_private *)netdev_priv(dev);
+ int ret = 0;
+
+ RDA5890_DBGLAP(RDA5890_DA_ETHER, RDA5890_DL_DEBUG,
+ "%s >>>\n", __func__);
+
+ if (priv->connect_status == MAC_CONNECTED)
+ netif_carrier_on(dev);
+ else
+ netif_carrier_off(dev);
+
+ RDA5890_DBGLAP(RDA5890_DA_ETHER, RDA5890_DL_DEBUG,
+ "%s <<<\n", __func__);
+ return ret;
+}
+
+/**
+ * @brief This function closes the ethX interface
+ *
+ * @param dev A pointer to net_device structure
+ * @return 0
+ */
+static int rda5890_eth_stop(struct net_device *dev)
+{
+ //struct rda5890_private *priv = (struct rda5890_private *) dev->priv;
+
+ RDA5890_DBGLAP(RDA5890_DA_ETHER, RDA5890_DL_DEBUG,
+ "%s >>>\n", __func__);
+
+ netif_stop_queue(dev);
+
+ RDA5890_DBGLAP(RDA5890_DA_ETHER, RDA5890_DL_DEBUG,
+ "%s <<<\n", __func__);
+ return 0;
+}
+
+static void rda5890_tx_timeout(struct net_device *dev)
+{
+ //struct rda5890_private *priv = (struct rda5890_private *) dev->priv;
+
+ RDA5890_DBGLAP(RDA5890_DA_ETHER, RDA5890_DL_DEBUG,
+ "%s >>>\n", __func__);
+
+ RDA5890_DBGLAP(RDA5890_DA_ETHER, RDA5890_DL_DEBUG,
+ "%s <<<\n", __func__);
+}
+
+/**
+ * @brief This function returns the network statistics
+ *
+ * @param dev A pointer to struct lbs_private structure
+ * @return A pointer to net_device_stats structure
+ */
+static struct net_device_stats *rda5890_get_stats(struct net_device *dev)
+{
+ struct rda5890_private *priv = (struct rda5890_private *) netdev_priv(dev);
+
+ RDA5890_DBGLAP(RDA5890_DA_ETHER, RDA5890_DL_DEBUG,
+ "%s >>>\n", __func__);
+
+ RDA5890_DBGLAP(RDA5890_DA_ETHER, RDA5890_DL_DEBUG,
+ "%s <<<\n", __func__);
+ return &priv->stats;
+}
+
+static int rda5890_set_mac_address(struct net_device *dev, void *addr)
+{
+ int ret = 0;
+ struct rda5890_private *priv = (struct rda5890_private *) netdev_priv(dev);
+ struct sockaddr *phwaddr = addr;
+
+ RDA5890_DBGLAP(RDA5890_DA_ETHER, RDA5890_DL_DEBUG,
+ "%s >>>\n", __func__);
+
+ ret = rda5890_set_mac_addr(priv, phwaddr->sa_data);
+ if (ret) {
+ goto done;
+ }
+ memcpy(priv->dev->dev_addr, phwaddr->sa_data, ETH_ALEN);
+
+done:
+ RDA5890_DBGLAP(RDA5890_DA_ETHER, RDA5890_DL_DEBUG,
+ "%s <<<\n", __func__);
+ return ret;
+}
+
+static void rda5890_set_multicast_list(struct net_device *dev)
+{
+ //struct rda5890_private *priv = dev->priv;
+
+ RDA5890_DBGLAP(RDA5890_DA_ETHER, RDA5890_DL_DEBUG,
+ "%s >>>\n", __func__);
+
+ //schedule_work(&priv->mcast_work);
+
+ RDA5890_DBGLAP(RDA5890_DA_ETHER, RDA5890_DL_DEBUG,
+ "%s <<<\n", __func__);
+}
+
+/**
+ * @brief This function checks the conditions and sends packet to IF
+ * layer if everything is ok.
+ *
+ * @param priv A pointer to struct lbs_private structure
+ * @param skb A pointer to skb which includes TX packet
+ * @return 0 or -1
+ */
+int rda5890_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct rda5890_private *priv = (struct rda5890_private*)netdev_priv(dev);
+#ifdef WIFI_TEST_MODE
+ if(rda_5990_wifi_in_test_mode())
+ return 0;
+#endif //end WIFI_TEST_MODE
+ return rda5890_data_tx(priv, skb, dev);
+}
+
+static int rda5890_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ int ret = 0;
+ struct rda5890_private *priv = netdev_priv(dev);
+ unsigned long value;
+ char in_buf[MAX_CMD_LEN + 4], out_buf[MAX_CMD_LEN + 4];
+ unsigned short in_len, out_len, out_len_ret;
+
+ RDA5890_DBGLAP(RDA5890_DA_ETHER, RDA5890_DL_DEBUG,
+ "%s >>>, cmd = %x\n", __func__, cmd);
+
+ switch (cmd) {
+ case IOCTL_RDA5890_GET_MAGIC:
+ RDA5890_DBGLAP(RDA5890_DA_ETHER, RDA5890_DL_DEBUG,
+ "IOCTL_RDA5890_GET_MAGIC\n");
+ value = RDA5890_MAGIC;
+ if (copy_to_user(rq->ifr_data, &value, sizeof(value)))
+ ret = -EFAULT;
+ break;
+ case IOCTL_RDA5890_GET_DRIVER_VER:
+ RDA5890_DBGLAP(RDA5890_DA_ETHER, RDA5890_DL_DEBUG,
+ "IOCTL_RDA5890_GET_DRIVER_VER\n");
+ value = RDA5890_SDIOWIFI_VER_MAJ << 16 |
+ RDA5890_SDIOWIFI_VER_MIN << 8 |
+ RDA5890_SDIOWIFI_VER_BLD;
+ if (copy_to_user(rq->ifr_data, &value, sizeof(value)))
+ ret = -EFAULT;
+ break;
+ case IOCTL_RDA5890_MAC_GET_FW_VER:
+ RDA5890_DBGLAP(RDA5890_DA_ETHER, RDA5890_DL_DEBUG,
+ "IOCTL_RDA5890_MAC_GET_FW_VER\n");
+ ret = rda5890_get_fw_ver(priv, &value);
+ if (ret)
+ break;
+ if (copy_to_user(rq->ifr_data, &value, sizeof(value)))
+ ret = -EFAULT;
+ break;
+ case IOCTL_RDA5890_MAC_WID:
+ RDA5890_DBGLAP(RDA5890_DA_ETHER, RDA5890_DL_DEBUG,
+ "IOCTL_RDA5890_MAC_WID\n");
+ if (copy_from_user(in_buf, rq->ifr_data, 4)) {
+ ret = -EFAULT;
+ break;
+ }
+ in_len = (unsigned short)(in_buf[0] + (in_buf[1] << 8));
+ out_len = (unsigned short)(in_buf[2] + (in_buf[3] << 8));
+ RDA5890_DBGLAP(RDA5890_DA_ETHER, RDA5890_DL_DEBUG,
+ " in_len = %d, out_len = %d\n", in_len, out_len);
+ if (copy_from_user(in_buf, rq->ifr_data, 4 + in_len)) {
+ ret = -EFAULT;
+ break;
+ }
+ out_len_ret = MAX_CMD_LEN;
+ ret = rda5890_wid_request(priv, in_buf + 4, in_len, out_buf + 4, &out_len_ret);
+ if (ret) {
+ RDA5890_ERRP("rda5890_wid_request, ret = %d\n", ret);
+ break;
+ }
+ RDA5890_DBGLAP(RDA5890_DA_ETHER, RDA5890_DL_DEBUG,
+ " out_len_ret = %d\n", out_len_ret);
+ if (out_len_ret > out_len) {
+ RDA5890_ERRP("No enough buf for wid response\n");
+ ret = -ENOMEM;
+ break;
+ }
+ out_buf[2] = (char)(out_len_ret&0x00FF);
+ out_buf[3] = (char)((out_len_ret&0xFF00) >> 8);
+ if (copy_to_user(rq->ifr_data, out_buf, 4 + out_len_ret))
+ ret = -EFAULT;
+ break;
+ case IOCTL_RDA5890_SET_WAPI_ASSOC_IE:
+ if(copy_from_user(in_buf, rq->ifr_data, 100)) {
+ ret = -EFAULT;
+ break;
+ }
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_TRACE,
+ "IOCTL_RDA5890_SET_WAPI_ASSOC_IE is %x %x %x %x \n",
+ in_buf[0], in_buf[1],in_buf[2],in_buf[3]);
+ rda5890_generic_set_str(priv, WID_WAPI_ASSOC_IE, in_buf ,100);
+ break;
+ case IOCTL_RDA5890_GET_WAPI_ASSOC_IE:
+ rda5890_generic_get_str(priv, WID_WAPI_ASSOC_IE, out_buf, 100);
+ if (copy_to_user(rq->ifr_data, out_buf, 100))
+ ret = -EFAULT;
+ break;
+ default:
+ RDA5890_ERRP("unknown cmd 0x%x\n", cmd);
+ ret = -EFAULT;
+ break;
+ }
+
+ RDA5890_DBGLAP(RDA5890_DA_ETHER, RDA5890_DL_DEBUG,
+ "%s <<<\n", __func__);
+ return ret;
+}
+
+static int rda5890_init_adapter(struct rda5890_private *priv)
+{
+ int ret = 0;
+ size_t bufsize;
+ int i;
+
+ mutex_init(&priv->wid_lock);
+#ifdef WIFI_POWER_MANAGER
+ atomic_set(&priv->sleep_flag, 0);
+#endif
+ priv->wid_pending = 0;
+ priv->wid_msg_id = 0;
+
+ /* Allocate buffer to store the BSSID list */
+ bufsize = RDA5890_MAX_NETWORK_NUM * sizeof(struct bss_descriptor);
+ priv->networks = kzalloc(bufsize, GFP_KERNEL);
+ if (!priv->networks) {
+ RDA5890_ERRP("Out of memory allocating beacons\n");
+ ret = -1;
+ goto out;
+ }
+
+ /* Initialize scan result lists */
+ INIT_LIST_HEAD(&priv->network_free_list);
+ INIT_LIST_HEAD(&priv->network_list);
+ for (i = 0; i < RDA5890_MAX_NETWORK_NUM; i++) {
+ list_add_tail(&priv->networks[i].list,
+ &priv->network_free_list);
+ }
+ priv->scan_running = 0;
+
+ /* Initialize delayed work workers and thread */
+ priv->work_thread = create_singlethread_workqueue("rda5890_worker");
+ INIT_DELAYED_WORK(&priv->scan_work, rda5890_scan_worker);
+ INIT_DELAYED_WORK(&priv->assoc_work, rda5890_assoc_worker);
+ INIT_DELAYED_WORK(&priv->assoc_done_work, rda5890_assoc_done_worker);
+ INIT_DELAYED_WORK(&priv->wlan_connect_work, rda5890_wlan_connect_worker);
+
+ /* Initialize status */
+ priv->connect_status = MAC_DISCONNECTED;
+ memset(&priv->curbssparams, 0, sizeof(priv->curbssparams));
+ memset(&priv->wstats, 0, sizeof(priv->wstats));
+
+ /* Initialize sec related status */
+ priv->assoc_flags = 0;
+ priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
+ memset(&priv->wep_keys, 0, sizeof(priv->wep_keys));
+ memset(&priv->wpa_ie[0], 0, sizeof(priv->wpa_ie));
+ priv->wpa_ie_len = 0;
+ priv->first_init = 1;
+
+out:
+ return ret;
+}
+
+static void rda5890_free_adapter(struct rda5890_private *priv)
+{
+ cancel_delayed_work_sync(&priv->assoc_done_work);
+ cancel_delayed_work_sync(&priv->assoc_work);
+ cancel_delayed_work_sync(&priv->scan_work);
+ cancel_delayed_work_sync(&priv->wlan_connect_work);
+ destroy_workqueue(priv->work_thread);
+
+ if(priv->networks)
+ kfree(priv->networks);
+ priv->networks = NULL;
+}
+
+static const struct net_device_ops rda_netdev_ops = {
+ .ndo_open = rda5890_dev_open,
+ .ndo_stop = rda5890_eth_stop,
+ .ndo_start_xmit = rda5890_hard_start_xmit,
+ .ndo_set_mac_address = rda5890_set_mac_address,
+ .ndo_tx_timeout = rda5890_tx_timeout,
+ .ndo_get_stats = rda5890_get_stats,
+ .ndo_do_ioctl = rda5890_ioctl
+};
+
+/**
+ * @brief This function adds the card. it will probe the
+ * card, allocate the lbs_priv and initialize the device.
+ *
+ * @param card A pointer to card
+ * @return A pointer to struct lbs_private structure
+ */
+struct rda5890_private *rda5890_add_card(void *card)
+{
+ struct net_device *dev = NULL;
+ struct rda5890_private *priv = NULL;
+
+ RDA5890_DBGLAP(RDA5890_DA_ETHER, RDA5890_DL_DEBUG,
+ "%s >>>\n", __func__);
+
+ /* Allocate an Ethernet device and register it */
+ dev = alloc_netdev_mq(sizeof(struct rda5890_private), "wlan%d", ether_setup, 1);
+ if (!dev) {
+ RDA5890_ERRP("alloc_etherdev failed\n");
+ goto done;
+ }
+ priv = netdev_priv(dev);
+
+ if(rda5890_init_adapter(priv)){
+ RDA5890_ERRP("rda5890_init_adapter failed\n");
+ goto err_init_adapter;
+ }
+
+ priv->dev = dev;
+ priv->card = card;
+
+ /* Setup the OS Interface to our functions */
+ dev->netdev_ops = &rda_netdev_ops;
+ dev->watchdog_timeo = msecs_to_jiffies(450); //450ms
+
+ //dev->ethtool_ops = &lbs_ethtool_ops;
+#ifdef WIRELESS_EXT
+ dev->wireless_handlers = (struct iw_handler_def *)&rda5890_wext_handler_def;
+#endif
+ dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
+
+ goto done;
+
+err_init_adapter:
+ if(priv)
+ rda5890_free_adapter(priv);
+ if(dev)
+ free_netdev(dev);
+ priv = NULL;
+
+done:
+ RDA5890_DBGLAP(RDA5890_DA_ETHER, RDA5890_DL_DEBUG,
+ "%s <<<\n", __func__);
+ return priv;
+}
+
+void rda5890_remove_card(struct rda5890_private *priv)
+{
+ struct net_device *dev = priv->dev;
+
+ RDA5890_DBGLAP(RDA5890_DA_ETHER, RDA5890_DL_DEBUG,
+ "%s >>>\n", __func__);
+
+ dev = priv->dev;
+
+ rda5890_free_adapter(priv);
+
+ priv->dev = NULL;
+ if(dev)
+ free_netdev(dev);
+
+ RDA5890_DBGLAP(RDA5890_DA_ETHER, RDA5890_DL_DEBUG,
+ "%s <<<\n", __func__);
+}
+
+int rda5890_start_card(struct rda5890_private *priv)
+{
+ struct net_device *dev = priv->dev;
+ int ret = 0;
+ unsigned char mac_addr[ETH_ALEN];
+
+ RDA5890_DBGLAP(RDA5890_DA_ETHER, RDA5890_DL_DEBUG,
+ "%s <<<\n", __func__);
+
+#ifdef WIFI_TEST_MODE
+ if(!rda_5990_wifi_in_test_mode())
+ {
+#endif
+
+#ifdef USE_MAC_DYNAMIC_ONCE
+ if(rda5890_read_mac(mac_addr) != ETH_ALEN)
+ {
+ random_ether_addr(mac_addr);
+ rda5890_write_mac(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 = rda5890_set_mac_addr(priv, mac_addr);
+ if (ret)
+ {
+ goto done;
+ }
+
+ ret = rda5890_get_mac_addr(priv, mac_addr);
+ if (ret) {
+ goto done;
+ }
+ memcpy(priv->dev->dev_addr, mac_addr, ETH_ALEN);
+
+#ifdef WIFI_TEST_MODE
+ }
+#endif
+
+ if (register_netdev(dev)) {
+ RDA5890_ERRP("register_netdev failed\n");
+ goto done;
+ }
+
+#ifdef WIFI_TEST_MODE
+ if(!rda_5990_wifi_in_test_mode())
+ {
+#endif
+
+ rda5890_set_preamble(priv, G_AUTO_PREAMBLE);
+
+ rda5890_indicate_disconnected(priv);
+#ifdef WIFI_TEST_MODE
+ }
+#endif
+
+
+done:
+ RDA5890_DBGLAP(RDA5890_DA_ETHER, RDA5890_DL_DEBUG,
+ "%s >>>\n", __func__);
+ return ret;
+}
+
+void rda5890_stop_card(struct rda5890_private *priv)
+{
+ struct net_device *dev = priv->dev;
+
+ RDA5890_DBGLAP(RDA5890_DA_ETHER, RDA5890_DL_DEBUG,
+ "%s >>>\n", __func__);
+
+ rda5890_indicate_disconnected(priv);
+ unregister_netdev(dev);
+
+ RDA5890_DBGLAP(RDA5890_DA_ETHER, RDA5890_DL_DEBUG,
+ "%s <<<\n", __func__);
+}
+
+void rda5890_shedule_timeout(int msecs)
+{
+ int timeout = 0, expires = 0;
+ expires = jiffies + msecs_to_jiffies(msecs);
+ timeout = msecs;
+
+ while(timeout)
+ {
+ timeout = schedule_timeout(timeout);
+
+ if(time_after(jiffies, expires))
+ break;
+ }
+}
+
+#ifdef WIFI_UNLOCK_SYSTEM
+
+void rda5990_wakeLock(void)
+{
+ if(atomic_read(&wake_lock_counter) == 0)
+ wake_lock(&sleep_worker_wake_lock);
+ atomic_inc(&wake_lock_counter);
+}
+
+void rda5990_wakeUnlock(void)
+{
+
+ if(atomic_read(&wake_lock_counter) == 1)
+ {
+ atomic_set(&wake_lock_counter, 0);
+ wake_unlock(&sleep_worker_wake_lock);
+ }
+ else if(atomic_read(&wake_lock_counter) > 0)
+ {
+ atomic_dec(&wake_lock_counter);
+ }
+
+}
+
+void rda5990_wakeLock_destroy(void)
+{
+ if(atomic_read(&wake_lock_counter) > 0)
+ {
+ atomic_set(&wake_lock_counter, 0);
+ wake_unlock(&sleep_worker_wake_lock);
+ }
+
+ wake_lock_destroy(&sleep_worker_wake_lock);
+
+}
+
+#endif
+
--- /dev/null
+/**
+ * This file contains definitions and data structures specific
+ * to Marvell 802.11 NIC. It contains the Device Information
+ * structure struct lbs_private..
+ */
+#ifndef _RDA5890_DEV_H_
+#define _RDA5890_DEV_H_
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+#include <linux/ethtool.h>
+#include <linux/delay.h>
+#include <linux/debugfs.h>
+#include <linux/wakelock.h>
+#include "rda5890_defs.h"
+//#include "hif_sdio.h"
+
+
+#ifndef MAX_WPA_IE_LEN
+#define MAX_WPA_IE_LEN 100
+#endif
+
+#ifndef MAX_RATES
+#define MAX_RATES 14
+#endif
+
+#define DEV_NAME_LEN 32
+
+#define RDA5890_MAX_NETWORK_NUM 32
+
+/** RSSI related MACRO DEFINITIONS */
+#define RDA5890_NF_DEFAULT_SCAN_VALUE (-96)
+#define PERFECT_RSSI ((u8)50)
+#define WORST_RSSI ((u8)0)
+#define RSSI_DIFF ((u8)(PERFECT_RSSI - WORST_RSSI))
+
+/** RTS/FRAG related defines */
+#define RDA5890_RTS_MIN_VALUE 0
+#define RDA5890_RTS_MAX_VALUE 2347
+#define RDA5890_FRAG_MIN_VALUE 256
+#define RDA5890_FRAG_MAX_VALUE 2346
+
+#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 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 RDA_SLEEP_ENABLE BIT0
+#define RDA_SLEEP_PREASSO BIT1
+
+//#define WIFI_UNIT_TEST
+
+/** 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
+};
+
+/* RDA5890 defined bss descriptor, 44 bytes for each bss */
+struct rda5890_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];
+} __attribute__ ((packed));
+
+/**
+ * @brief Structure used to store information for each beacon/probe response
+ */
+struct bss_descriptor {
+ struct rda5890_bss_descriptor data;
+
+ 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[MAX_WPA_IE_LEN];
+ size_t wpa_ie_len;
+ u8 rsn_ie[MAX_WPA_IE_LEN];
+ size_t rsn_ie_len;
+
+ u8 wapi_ie[100];
+ size_t wapi_ie_len; //wapi valid payload length
+
+ unsigned long last_scanned;
+
+
+ struct list_head list;
+};
+
+/* 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];
+};
+
+struct rda5890_802_11_security {
+ u8 WPAenabled;
+ u8 WPA2enabled;
+ u8 wep_enabled;
+ u8 auth_mode;
+ u32 key_mgmt;
+ u32 cipther_type;
+};
+
+/** Private structure for the rda5890 device */
+struct rda5890_private {
+ char name[DEV_NAME_LEN];
+
+ void *card;
+ struct net_device *dev;
+
+ struct net_device_stats stats;
+
+ /** current ssid/bssid related parameters and status */
+ int connect_status;
+ struct rda5890_bss_descriptor curbssparams;
+ struct iw_statistics wstats;
+
+ /** association flags */
+ unsigned char assoc_ssid[IW_ESSID_MAX_SIZE + 1];
+ unsigned char assoc_bssid[6];
+ unsigned char assoc_ssid_len;
+#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
+
+ unsigned long assoc_flags;
+ unsigned char imode;
+ unsigned char authtype;
+
+ /** debugfs */
+ struct dentry *debugfs_dir;
+ struct dentry *debugfs_files[6];
+
+ /** for wid request and response */
+ struct mutex wid_lock;
+ struct completion wid_done;
+ int wid_pending;
+ char *wid_rsp;
+ unsigned short wid_rsp_len;
+ char wid_msg_id;
+
+ /** delayed worker */
+ struct workqueue_struct *work_thread;
+ struct delayed_work scan_work;
+ struct delayed_work assoc_work;
+ struct delayed_work assoc_done_work;
+ struct delayed_work wlan_connect_work;
+
+ /** Hardware access */
+ int (*hw_host_to_card) (struct rda5890_private *priv, u8 *payload, u16 nb,
+ unsigned char packet_type);
+
+ /** Scan results list */
+ int scan_running;
+ struct list_head network_list;
+ struct list_head network_free_list;
+ struct bss_descriptor *networks;
+
+ /** Encryption parameter */
+ struct rda5890_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;
+ /** sleep/awake flag */
+#ifdef WIFI_POWER_MANAGER
+ atomic_t sleep_flag;
+#endif
+ u8 first_init;
+ u16 version;
+};
+
+extern int rda5890_sleep_flags;
+
+#ifdef WIFI_TEST_MODE
+extern unsigned char rda_5990_wifi_in_test_mode(void);
+#endif
+
+#ifdef WIFI_UNLOCK_SYSTEM
+extern atomic_t wake_lock_counter;
+extern struct wake_lock sleep_worker_wake_lock;
+extern void rda5990_wakeLock(void);
+extern void rda5990_wakeUnlock(void);
+extern void rda5990_wakeLock_destroy(void);
+#endif
+
+struct rda5890_private *rda5890_add_card(void *card);
+void rda5890_remove_card(struct rda5890_private *priv);
+int rda5890_start_card(struct rda5890_private *priv);
+void rda5890_stop_card(struct rda5890_private *priv);
+int rda5890_sdio_core_wake_mode(struct rda5890_private *priv);
+int rda5890_sdio_core_sleep_mode(struct rda5890_private *priv);
+int rda5890_sdio_core_wake_mode_polling(struct rda5890_private *priv);
+
+void rda5890_sdio_set_notch_by_channel(struct rda5890_private *priv, unsigned int channel);
+void rda5890_rssi_up_to_200(struct rda5890_private *priv);
+void rda5990_assoc_power_save(struct rda5890_private *priv);
+unsigned char is_sdio_init_complete(void);
+unsigned char is_sdio_patch_complete(void);
+int rda5890_sdio_init(struct rda5890_private *priv);
+int rda5890_init_pm(struct rda5890_private *priv);
+void rda5890_shedule_timeout(int msecs);
+int rda5890_read_mac(char* buf);
+int rda5890_write_mac(char * buf);
+int rda5890_disable_block_bt(struct rda5890_private *priv);
+int rda5890_disable_self_cts(struct rda5890_private *priv);
+int rda5890_set_active_scan_time(struct rda5890_private *priv);
+int rda5890_set_test_mode(struct rda5890_private *priv);
+int rda5890_get_fw_version_polling(struct rda5890_private *priv, unsigned int* version);
+#endif
--- /dev/null
+#include <linux/moduleparam.h>
+#include <linux/firmware.h>
+#include <linux/netdevice.h>
+#include <linux/delay.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/sched.h>
+
+#include "rda5890_defs.h"
+#include "rda5890_dev.h"
+#include "rda5890_if_sdio.h"
+#include "rda5890_wid.h"
+#include "rda5890_debugfs.h"
+
+int rda5890_dbg_level = RDA5890_DL_CRIT;
+int rda5890_dbg_area = RDA5890_DA_MAIN
+ | RDA5890_DA_SDIO
+ //| RDA5890_DA_ETHER
+ | RDA5890_DA_WID
+ | RDA5890_DA_WEXT
+ //| RDA5890_DA_TXRX
+ //| RDA5890_DA_PM
+ ;
+
+void export_msdc_clk_always_on(void)
+{
+ // todo...
+}
+
+void export_msdc_clk_always_on_off(void)
+{
+ // todo...
+}
+
+extern void rk29_sdio_irq_enable(int enable);
+void export_wifi_eirq_enable(void)
+{
+ // todo...
+ rk29_sdio_irq_enable(1);
+}
+
+void export_wifi_eirq_disable(void)
+{
+ // todo...
+ rk29_sdio_irq_enable(0);
+}
+
+/* Module parameters */
+module_param_named(debug_level, rda5890_dbg_level, int, 0644);
+module_param_named(debug_area, rda5890_dbg_area, int, 0644);
+int sdio_test_flag = 0;
+module_param_named(sdio_test, sdio_test_flag, int, 0644);
+
+#define SDIO_VENDOR_ID_RDA5890 0x5449
+#define SDIO_DEVICE_ID_RDA5890 0x0145
+
+static const struct sdio_device_id if_sdio_ids[] = {
+ { SDIO_DEVICE(SDIO_VENDOR_ID_RDA5890, SDIO_DEVICE_ID_RDA5890) },
+ { /* end: all zeroes */ },
+};
+
+MODULE_DEVICE_TABLE(sdio, if_sdio_ids);
+
+struct if_sdio_packet {
+ struct if_sdio_packet *next;
+ unsigned char packet_type;
+ u16 nb;
+ u8 buffer[0] __attribute__((aligned(4)));
+};
+
+int if_sdio_card_to_host(struct if_sdio_card *card)
+{
+ int ret = 0;
+ struct rda5890_private *priv = card->priv;
+ u8 size_l = 0, size_h = 0;
+ u16 size, chunk;
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
+ "%s <<< \n", __func__);
+
+ size_l = sdio_readb(card->func, IF_SDIO_AHB2SDIO_PKTLEN_L, &ret);
+ if (ret) {
+ RDA5890_ERRP("read PKTLEN_L reg fail\n");
+ goto out;
+ }
+ else
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_NORM,"read PKTLEN_L reg size_l:%d \n", size_l);
+
+ size_h = sdio_readb(card->func, IF_SDIO_AHB2SDIO_PKTLEN_H, &ret);
+ if (ret) {
+ RDA5890_ERRP("read PKTLEN_H reg fail\n");
+ goto out;
+ }
+ else
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_NORM,"read PKTLEN_H reg size_h:%d\n",size_h);
+
+ size = (size_l | ((size_h & 0x7f) << 8)) * 4;
+ if (size < 4) {
+ RDA5890_ERRP("invalid packet size (%d bytes) from firmware\n", size);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* alignment is handled on firmside */
+ //chunk = sdio_align_size(card->func, size);
+ chunk = size;
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_NORM,
+ "if_sdio_card_to_host, size = %d, aligned size = %d\n", size, chunk);
+
+ /* TODO: handle multiple packets here */
+ ret = sdio_readsb(card->func, card->buffer, IF_SDIO_FUN1_FIFO_RD, chunk);
+ if (ret) {
+ RDA5890_ERRP("sdio_readsb fail, ret = %d\n", ret);
+ goto out;
+ }
+
+#if 1
+ if(priv->version == 7)
+ {
+ sdio_writeb(card->func, 0x20 ,IF_SDIO_FUN1_INT_PEND, &ret);
+ if(ret) {
+ RDA5890_ERRP("clear SDIO Tx Complete flag failed\n");
+ goto out;
+ }
+ }
+#endif
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_VERB,
+ "if_sdio_card_to_host, read done\n");
+
+ if (sdio_test_flag) {
+ rda5890_sdio_test_card_to_host(card->buffer, chunk);
+ goto out;
+ }
+
+ /* TODO: this chunk size need to be handled here */
+ rda5890_card_to_host(priv, card->buffer, chunk);
+
+out:
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
+ "if_sdio_card_to_host >>>\n");
+ return ret;
+}
+
+#ifdef WIFI_POWER_MANAGER
+void if_sdio_sleep_worker(struct work_struct *work)
+{
+ struct if_sdio_card *card = NULL;
+ int ret = 0;
+ struct rda5890_private *priv = NULL;
+
+ card = container_of(work, struct if_sdio_card,
+ sleep_work.work);
+
+ if(card)
+ priv = card->priv;
+ else
+ goto out;
+
+ if(!priv)
+ goto out;
+
+ RDA5890_DBGLAP(RDA5890_DA_PM, RDA5890_DL_CRIT, "Sleep\n");
+
+ /* clear IF_SDIO_FUN1_INT_PEND, this allow device to sleep */
+ sdio_claim_host(card->func);
+ sdio_writeb(card->func, IF_SDIO_HOST_TX_FLAG ,IF_SDIO_FUN1_INT_PEND, &ret);
+ sdio_release_host(card->func);
+ if (ret)
+ {
+ RDA5890_ERRP("clear IF_SDIO_HOST_TX_FLAG failed\n");
+ }
+ atomic_inc(&card->priv->sleep_flag);
+
+out:
+
+ atomic_set(&card->sleep_work_is_active, 0);
+#ifdef WIFI_UNLOCK_SYSTEM
+ rda5990_wakeUnlock();
+#endif
+ return;
+}
+
+static int if_sdio_wakeup_card(struct if_sdio_card *card)
+{
+ struct rda5890_private *priv = card->priv;
+ int ret = 0;
+
+#ifdef WIFI_TEST_MODE
+ if(rda_5990_wifi_in_test_mode())
+ return 0;
+#endif
+ sdio_claim_host(card->func);
+ sdio_writeb(card->func, 1, IF_SDIO_FUN1_INT_TO_DEV, &ret);
+ sdio_release_host(card->func);
+ if (ret) {
+ RDA5890_ERRP("write FUN1_INT_TO_DEV reg fail\n");
+ goto out;
+ }
+ atomic_set(&priv->sleep_flag, 0);
+
+ RDA5890_DBGLAP(RDA5890_DA_PM, RDA5890_DL_CRIT, "wake up \n");
+ // wait 15ms, hardware need 13ms to wakeup
+ rda5890_shedule_timeout(8);
+out:
+ return ret;
+}
+
+#endif //WIFI_POWER_MANAGER
+
+static void if_sdio_host_to_card_worker(struct work_struct *work)
+{
+ struct if_sdio_card *card = NULL;
+ struct rda5890_private *priv = NULL;
+ struct if_sdio_packet *packet = NULL;
+ int ret;
+ unsigned long flags;
+ u16 size;
+ u32 retries = 500;
+ u8 size_l, size_h, write_status = 0;
+#define SDIO_HOST_WRITE_BATCH_SIZE 512
+ u16 bytes_left, offset, batch;
+
+ card = container_of(work, struct if_sdio_card, packet_worker);
+ priv = card->priv;
+
+
+#ifdef WIFI_POWER_MANAGER
+ if(is_sdio_init_complete())
+ {
+ if(atomic_read(&card->sleep_work_is_active))
+ {
+ cancel_delayed_work(&card->sleep_work);
+#ifdef WIFI_UNLOCK_SYSTEM
+ rda5990_wakeUnlock();
+#endif
+ atomic_set(&card->sleep_work_is_active, 0);
+ }
+ }
+#endif
+
+ while (1)
+ {
+ retries = 500;
+
+ spin_lock_irqsave(&card->lock, flags);
+ packet = card->packets;
+ if (packet)
+ card->packets = packet->next;
+ spin_unlock_irqrestore(&card->lock, flags);
+
+ if (!packet)
+ break;
+
+#ifdef WIFI_POWER_MANAGER
+ if (atomic_read(&priv->sleep_flag))
+ {
+ /* Deivce maybe sleep, wakeup it. */
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_NORM, "Wakeup\n");
+ ret = if_sdio_wakeup_card(card);
+ if (ret)
+ {
+ RDA5890_ERRP("wakeup card fail\n");
+ goto out;
+ }
+ }
+#endif
+ while(retries && is_sdio_patch_complete()) //check write flow ctrl
+ {
+ sdio_claim_host(card->func);
+ write_status = sdio_readb(card->func, IF_SDIO_FUN1_INT_PEND, &ret);
+ sdio_release_host(card->func);
+ if(ret)
+ {
+ RDA5890_ERRP("read IF_SDIO_FUN1_INT_PEND failed\n");
+ goto release;
+ }
+ if((write_status & IF_SDIO_INT_RXCMPL) == 0)
+ {
+ //RDA5890_ERRP("**** sdio is busy retry next time \n ");
+ retries --;
+ schedule();
+ }
+ else
+ {
+ sdio_claim_host(card->func);
+ sdio_writeb(card->func, IF_SDIO_INT_RXCMPL, IF_SDIO_FUN1_INT_PEND, &ret);
+ sdio_release_host(card->func);
+ if(ret)
+ {
+ RDA5890_ERRP("write IF_SDIO_FUN1_INT_PEND failed\n");
+ goto release;
+ }
+ break;
+ }
+ }
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
+ "if_sdio_host_to_card_worker, send one packet, size = %d\n", packet->nb);
+ /* write length */
+ size = packet->nb/4;
+ size_l = (u8)(size & 0xff);
+ size_h = (u8)((size >> 8) & 0x7f);
+ size_h |= 0x80;
+
+ sdio_claim_host(card->func);
+ sdio_writeb(card->func, size_l, IF_SDIO_SDIO2AHB_PKTLEN_L, &ret);
+ sdio_release_host(card->func);
+ if (ret) {
+ RDA5890_ERRP("write PKTLEN_L reg fail\n");
+ goto release;
+ }
+ sdio_claim_host(card->func);
+ sdio_writeb(card->func, size_h, IF_SDIO_SDIO2AHB_PKTLEN_H, &ret);
+ sdio_release_host(card->func);
+ if (ret) {
+ RDA5890_ERRP("write PKTLEN_H reg fail\n");
+ goto release;
+ }
+
+ /* write data */
+ bytes_left = packet->nb;
+ offset = 0;
+ while(bytes_left)
+ {
+ batch = (bytes_left < SDIO_HOST_WRITE_BATCH_SIZE)?
+ bytes_left:SDIO_HOST_WRITE_BATCH_SIZE;
+
+ sdio_claim_host(card->func);
+ ret = sdio_writesb(card->func, IF_SDIO_FUN1_FIFO_WR,
+ packet->buffer + offset, batch);
+ sdio_release_host(card->func);
+ if (ret) {
+ RDA5890_ERRP("sdio_writesb fail, ret = %d\n", ret);
+ goto release;
+ }
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
+ "write batch %d, offset = %d\n", batch, offset);
+
+ offset += batch;
+ bytes_left -= batch;
+ }
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
+ "if_sdio_host_to_card_worker, send one packet done\n");
+
+release:
+
+ kfree(packet);
+ packet = NULL;
+ }
+
+out:
+
+ if(is_sdio_init_complete()) //init complete should start sleep_work
+ {
+#ifdef WIFI_UNLOCK_SYSTEM
+ rda5990_wakeLock();
+#endif
+
+#ifdef WIFI_POWER_MANAGER
+#ifdef WIFI_TEST_MODE
+ if(rda_5990_wifi_in_test_mode())
+ return;
+#endif //end WIFI_TEST_MODE
+ atomic_set(&card->sleep_work_is_active, 1);
+ queue_delayed_work(priv->work_thread, &card->sleep_work, HZ/5); // 100ms
+#endif //end WIFI_POWER_MANAGER
+ }
+}
+
+/*******************************************************************/
+/* RDA5890 callbacks */
+/*******************************************************************/
+
+static int if_sdio_host_to_card(struct rda5890_private *priv,
+ u8 *buf, u16 nb, unsigned char packet_type)
+{
+ int ret = 0;
+ struct if_sdio_card *card;
+ struct if_sdio_packet *packet, *cur;
+ u16 size;
+ unsigned long flags;
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
+ "%s >>>\n", __func__);
+
+ card = priv->card;
+
+ if (nb > (65536 - sizeof(struct if_sdio_packet))) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ //size = sdio_align_size(card->func, nb);
+ size = nb;
+ if(size%4)
+ {
+ size += (4-size%4);
+ }
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_NORM,
+ "if_sdio_host_to_card, size = %d, aligned size = %d\n", nb, size);
+
+ packet = kzalloc(sizeof(struct if_sdio_packet) + size,
+ GFP_ATOMIC);
+ if (!packet) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ packet->next = NULL;
+ packet->nb = size;
+ packet->packet_type = packet_type;
+
+ memcpy(packet->buffer, buf, nb);
+
+ spin_lock_irqsave(&card->lock, flags);
+
+ if (!card->packets)
+ card->packets = packet;
+ else {
+ cur = card->packets;
+ while (cur->next)
+ cur = cur->next;
+ cur->next = packet;
+ }
+
+ spin_unlock_irqrestore(&card->lock, flags);
+
+ queue_work(card->work_thread, &card->packet_worker);
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
+ "%s <<<\n", __func__);
+
+ ret = 0;
+
+out:
+ return ret;
+}
+
+static void if_sdio_interrupt(struct sdio_func *func)
+{
+ int ret = 0;
+ struct if_sdio_card *card;
+ struct rda5890_private *priv;
+ u8 status;
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
+ "%s >>>\n", __func__);
+
+ card = sdio_get_drvdata(func);
+ if(!card)
+ return;
+
+ priv = card->priv;
+
+ status = sdio_readb(card->func, IF_SDIO_FUN1_INT_STAT, &ret);
+ if (ret)
+ goto out;
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_VERB,
+ "if_sdio_interrupt, status = 0x%02x\n", status);
+
+ if (status & IF_SDIO_INT_AHB2SDIO)
+ if_sdio_card_to_host(card);
+
+ if (status & IF_SDIO_INT_ERROR)
+ {
+ sdio_writeb(card->func, IF_SDIO_INT_ERROR, IF_SDIO_FUN1_INT_PEND, &ret);
+ if (ret)
+ {
+ RDA5890_ERRP("write FUN1_INT_STAT reg fail\n");
+ goto out;
+ }
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
+ "%s, INT_ERROR\n", __func__);
+ }
+
+out:
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
+ "%s <<< ret=%d \n", __func__, ret);
+ return ret;
+}
+
+
+static int if_sdio_probe(struct sdio_func *func,
+ const struct sdio_device_id *id)
+{
+ struct if_sdio_card *card = NULL;
+ struct rda5890_private *priv = NULL;
+ struct if_sdio_packet *packet = NULL;
+ int ret = -1;
+ unsigned long flags;
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
+ "%s >>>\n", __func__);
+
+ //SMC_MSG("[rda_debug] sunximmc_probe, set clk.\n");
+
+ //mmc_set_clock(mmc, 4000000);
+
+
+ if(id->vendor != 0x5449)
+ {
+ RDA5890_ERRP("rda5890 sdio not corrent vendor:%x \n", id->vendor);
+ goto out;
+ }
+
+ card = kzalloc(sizeof(struct if_sdio_card), GFP_KERNEL);
+ if (!card) {
+ RDA5890_ERRP("kzalloc fail\n");
+ return -ENOMEM;
+ }
+
+ card->func = func;
+ spin_lock_init(&card->lock);
+ atomic_set(&card->wid_complete_flag, 0);
+ INIT_WORK(&card->packet_worker, if_sdio_host_to_card_worker);
+ card->work_thread = create_singlethread_workqueue("rda5890_if_sdio_worker");
+
+#ifdef WIFI_POWER_MANAGER
+ atomic_set(&card->sleep_work_is_active, 0);
+ INIT_DELAYED_WORK(&card->sleep_work, if_sdio_sleep_worker);
+#endif
+
+#ifdef WIFI_UNLOCK_SYSTEM
+ atomic_set(&wake_lock_counter, 0);
+ wake_lock_init(&sleep_worker_wake_lock, WAKE_LOCK_SUSPEND, "RDA_sleep_worker_wake_lock");
+#endif
+
+ sdio_claim_host(func);
+ ret = sdio_enable_func(func);
+ if (ret) {
+ RDA5890_ERRP("sdio_enable_func fail, ret = %d\n", ret);
+ goto release;
+ }
+
+ ret = sdio_claim_irq(func, if_sdio_interrupt);
+ if (ret) {
+ RDA5890_ERRP("sdio_claim_irq fail, ret = %d\n", ret);
+ goto disable;
+ }
+
+ sdio_release_host(func);
+ sdio_set_drvdata(func, card);
+
+ priv = rda5890_add_card(card);
+ if (!priv) {
+ RDA5890_ERRP("rda5890_add_card fail\n");
+ ret = -ENOMEM;
+ goto release_int;
+ }
+ rda5890_debugfs_init_one(priv);
+
+ card->priv = priv;
+ priv->card = card;
+ priv->hw_host_to_card = if_sdio_host_to_card;
+
+ /*
+ * Enable interrupts now that everything is set up
+ */
+ sdio_claim_host(func);
+ sdio_writeb(func, 0x7, IF_SDIO_FUN1_INT_MASK, &ret);
+ sdio_release_host(func);
+ if (ret) {
+ RDA5890_ERRP("enable func interrupt fail\n");
+ goto remove_card;
+ }
+#ifdef WIFI_TEST_MODE
+ if(!rda_5990_wifi_in_test_mode())
+ {
+#endif
+ ret = rda5890_sdio_init(priv);
+ if(ret < 0)
+ goto remove_card;
+
+ ret=rda5890_disable_self_cts(priv);
+ if(ret < 0)
+ goto remove_card;
+
+ ret=rda5890_disable_block_bt(priv);
+ if(ret < 0)
+ goto remove_card;
+
+ ret = rda5890_set_scan_timeout(priv);
+ if (ret) {
+ RDA5890_ERRP("rda5890_set_scan_timeout fail, ret = %d\n", ret);
+ goto remove_card;
+ }
+
+ ret= rda5890_set_listen_interval(priv, 0x06);
+ if(ret < 0)
+ goto remove_card;
+
+ ret = rda5890_set_link_loss_threshold(priv, 0x06);
+ if(ret < 0)
+ goto remove_card;
+
+ ret = rda5890_init_pm(priv);
+ if(ret < 0)
+ goto remove_card;
+
+#ifdef WIFI_TEST_MODE
+ }
+ else
+ {
+ ret = rda5890_set_test_mode(priv);
+ if(ret < 0)
+ goto remove_card;
+ }
+#endif
+
+ if (sdio_test_flag) {
+ unsigned char mac_addr[6];
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
+ "SDIO TESTING MODE\n");
+
+
+ ret = rda5890_get_mac_addr(priv, mac_addr);
+ printk(KERN_INFO "Test rda5890_get_mac_addr %x:%x:%x:%x:%x:%x", mac_addr[0],mac_addr[1],mac_addr[2],mac_addr[3],mac_addr[4],mac_addr[5]);
+ goto done;
+ }
+
+ ret = rda5890_start_card(priv);
+ if (ret) {
+ RDA5890_ERRP("rda5890_start_card fail, ret = %d\n", ret);
+ goto remove_card;
+ }
+
+done:
+ printk(KERN_INFO "RDA5890: SDIO card started\n");
+
+out:
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
+ "%s ret:%d <<<\n", __func__, ret);
+ return ret;
+
+release_int:
+ sdio_claim_host(func);
+ sdio_release_irq(func);
+disable:
+ sdio_disable_func(func);
+release:
+ sdio_release_host(func);
+
+remove_card:
+
+ if (atomic_read(&card->wid_complete_flag) && priv)
+ {
+ complete(&priv->wid_done);
+ printk(KERN_INFO "*****RDA5890: probe send wid complete\n");
+ }
+ flush_work(&card->packet_worker);
+ cancel_work_sync(&card->packet_worker);
+
+#ifdef WIFI_POWER_MANAGER
+ cancel_delayed_work(&card->sleep_work);
+#endif
+ destroy_workqueue(card->work_thread);
+
+ if(priv)
+ rda5890_remove_card(priv);
+
+ while (card->packets) {
+ packet = card->packets;
+ card->packets = card->packets->next;
+ kfree(packet);
+ }
+
+ kfree(card);
+ goto out;
+}
+
+static void if_sdio_remove(struct sdio_func *func)
+{
+ struct if_sdio_card *card;
+ struct if_sdio_packet *packet;
+ unsigned char count = 20;
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
+ "%s >>>\n", __func__);
+
+ printk(KERN_INFO "RDA5890: SDIO card detached\n");
+
+ card = sdio_get_drvdata(func);
+ if(!card)
+ return;
+ while(card->priv->scan_running && count--)
+ {
+ rda5890_shedule_timeout(100);
+ printk("remove card wait scan complete \n");
+ }
+
+#ifdef WIFI_POWER_MANAGER
+ cancel_delayed_work_sync(&card->sleep_work);
+#endif
+ cancel_work_sync(&card->packet_worker);
+
+ if (atomic_read(&card->wid_complete_flag) && card->priv)
+ {
+ complete(&card->priv->wid_done);
+ printk(KERN_INFO "*****RDA5890: send wid complete\n");
+ }
+
+ netif_stop_queue(card->priv->dev);
+ netif_carrier_off(card->priv->dev);
+ rda5890_stop_card(card->priv);
+ rda5890_debugfs_remove_one(card->priv);
+ destroy_workqueue(card->work_thread);
+ rda5890_remove_card(card->priv);
+
+ while (card->packets) {
+ packet = card->packets;
+ card->packets = card->packets->next;
+ kfree(packet);
+ }
+
+ kfree(card);
+
+#ifdef WIFI_UNLOCK_SYSTEM
+ rda5990_wakeLock_destroy();
+#endif
+
+ printk(KERN_INFO "RDA5890: SDIO card removed\n");
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
+ "%s <<<\n", __func__);
+ return;
+}
+
+static struct sdio_driver if_sdio_driver = {
+ .name = "rda5890_sdio",
+ .id_table = if_sdio_ids,
+ .probe = if_sdio_probe,
+ .remove = if_sdio_remove,
+};
+
+/*******************************************************************/
+/* Module functions */
+/*******************************************************************/
+extern void mmc_rescan_slot(int id);
+
+static int __init if_sdio_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",
+ RDA5890_SDIOWIFI_VER_MAJ,
+ RDA5890_SDIOWIFI_VER_MIN,
+ RDA5890_SDIOWIFI_VER_BLD);
+
+ printk("@@@@@@@@@@@@@@@22222 rda5990 start\n");
+
+ msleep(1000);
+
+ printk("@@@@@@@@@@@@@@ mmc_rescan_slot\n");
+ mmc_rescan_slot(0);
+ msleep(1000);
+
+ rda5890_debugfs_init();
+ ret = sdio_register_driver(&if_sdio_driver);
+
+ if (ret)
+ {
+ printk(KERN_INFO "\nif_sdio_init_module: register fail. \n");
+ //sunximmc_rescan_card(SDIOID,0);
+ }
+
+ printk(KERN_INFO "\n if_sdio_init_module: register successful. \n");
+
+ return ret;
+}
+
+extern void mmc_remove(int id);
+static void __exit if_sdio_exit_module(void)
+{
+ printk(KERN_INFO "\n if_sdio_exit_module. \n");
+ mmc_remove(0);
+ rda5890_debugfs_remove();
+ sdio_unregister_driver(&if_sdio_driver);
+}
+
+
+module_init(if_sdio_init_module);
+module_exit(if_sdio_exit_module);
+
+MODULE_DESCRIPTION("RDA5890 SDIO WLAN Driver");
+MODULE_AUTHOR("lwang");
+MODULE_LICENSE("GPL");
--- /dev/null
+#ifndef _RDA5890_IF_SDIO_H
+#define _RDA5890_IF_SDIO_H
+
+#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
+
+struct if_sdio_card {
+ struct sdio_func *func;
+ struct rda5890_private *priv;
+
+ u8 buffer[2048];
+
+ spinlock_t lock;
+ struct if_sdio_packet *packets;
+ struct work_struct packet_worker;
+
+ struct workqueue_struct *work_thread;
+ atomic_t wid_complete_flag;
+#ifdef WIFI_POWER_MANAGER
+ atomic_t sleep_work_is_active;
+ struct delayed_work sleep_work;
+#endif
+};
+
+void export_msdc_clk_always_on(void);
+void export_msdc_clk_always_on_off(void);
+void export_wifi_eirq_enable(void);
+void export_wifi_eirq_disable(void);
+
+#endif
--- /dev/null
+#ifndef _RDA5890_IOCTL_H_\r
+#define _RDA5890_IOCTL_H_\r
+\r
+#include "linux/sockios.h"\r
+\r
+#define IOCTL_RDA5890_BASE SIOCDEVPRIVATE\r
+#define IOCTL_RDA5890_GET_MAGIC IOCTL_RDA5890_BASE\r
+#define IOCTL_RDA5890_GET_DRIVER_VER (IOCTL_RDA5890_BASE + 1)\r
+#define IOCTL_RDA5890_MAC_GET_FW_VER (IOCTL_RDA5890_BASE + 2)\r
+#define IOCTL_RDA5890_MAC_WID (IOCTL_RDA5890_BASE + 3)\r
+#define IOCTL_RDA5890_SET_WAPI_ASSOC_IE (IOCTL_RDA5890_BASE + 4)\r
+#define IOCTL_RDA5890_GET_WAPI_ASSOC_IE (IOCTL_RDA5890_BASE + 5)\r
+\r
+#define RDA5890_MAGIC 0x5890face\r
+\r
+#endif /* _RDA5890_IOCTL_H_ */\r
+ \r
--- /dev/null
+#include <linux/fs.h>\r
+#include <asm/uaccess.h>\r
+\r
+#define WIFI_NVRAM_FILE_NAME "/data/nvram/APCFG/APRDEB/RDAWIFI"\r
+\r
+static int nvram_read(char *filename, char *buf, ssize_t len, int offset)\r
+{ \r
+ struct file *fd;\r
+ //ssize_t ret;\r
+ int retLen = -1;\r
+ \r
+ mm_segment_t old_fs = get_fs();\r
+ set_fs(KERNEL_DS);\r
+ \r
+ fd = filp_open(filename, O_WRONLY|O_CREAT, 0644);\r
+ \r
+ if(IS_ERR(fd)) {\r
+ printk("[rda5890][nvram_read] : failed to open!!\n");\r
+ return -1;\r
+ }\r
+ do{\r
+ if ((fd->f_op == NULL) || (fd->f_op->read == NULL))\r
+ {\r
+ printk("[rda5890][nvram_read] : file can not be read!!\n");\r
+ break;\r
+ } \r
+ \r
+ if (fd->f_pos != offset) {\r
+ if (fd->f_op->llseek) {\r
+ if(fd->f_op->llseek(fd, offset, 0) != offset) {\r
+ printk("[rda5890][nvram_read] : failed to seek!!\n");\r
+ break;\r
+ }\r
+ } else {\r
+ fd->f_pos = offset;\r
+ }\r
+ } \r
+ \r
+ retLen = fd->f_op->read(fd,\r
+ buf,\r
+ len,\r
+ &fd->f_pos); \r
+ \r
+ }while(false);\r
+ \r
+ filp_close(fd, NULL);\r
+ \r
+ set_fs(old_fs);\r
+ \r
+ return retLen;\r
+}\r
+\r
+static int nvram_write(char *filename, char *buf, ssize_t len, int offset)\r
+{ \r
+ struct file *fd;\r
+ int retLen = -1;\r
+ \r
+ mm_segment_t old_fs = get_fs();\r
+ set_fs(KERNEL_DS);\r
+ \r
+ fd = filp_open(filename, O_WRONLY|O_CREAT, 0644);\r
+ \r
+ if(IS_ERR(fd)) {\r
+ printk("[rda5890][nvram_write] : failed to open!!\n");\r
+ return -1;\r
+ }\r
+ do{\r
+ if ((fd->f_op == NULL) || (fd->f_op->write == NULL))\r
+ {\r
+ printk("[rda5890][nvram_write] : file can not be write!!\n");\r
+ break;\r
+ } /* End of if */\r
+ \r
+ if (fd->f_pos != offset) {\r
+ if (fd->f_op->llseek) {\r
+ if(fd->f_op->llseek(fd, offset, 0) != offset) {\r
+ printk("[rda5890][nvram_write] : failed to seek!!\n");\r
+ break;\r
+ }\r
+ } else {\r
+ fd->f_pos = offset;\r
+ }\r
+ } \r
+ \r
+ retLen = fd->f_op->write(fd,\r
+ buf,\r
+ len,\r
+ &fd->f_pos); \r
+ \r
+ }while(false);\r
+ \r
+ filp_close(fd, NULL);\r
+ \r
+ set_fs(old_fs);\r
+ \r
+ return retLen;\r
+}\r
+\r
+int rda5890_read_mac(char* buf)\r
+{\r
+ return nvram_read(WIFI_NVRAM_FILE_NAME, buf, 6, 0);\r
+}\r
+\r
+int rda5890_write_mac(char * buf)\r
+{\r
+ return nvram_write(WIFI_NVRAM_FILE_NAME, buf, 6, 0);\r
+}\r
+\r
--- /dev/null
+#include <linux/types.h>\r
+#include <linux/kernel.h>\r
+#include <linux/ieee80211.h>
+#include <net/iw_handler.h>
+#include <linux/etherdevice.h>
+
+\r
+#include "rda5890_dev.h"\r
+#include "rda5890_defs.h"
+\r
+//#define SCAN_RESULT_DEBUG\r
+\r
+//added by xiongzhi for wapi\r
+#ifndef FCS_LEN\r
+#define FCS_LEN 4
+#endif\r
+\r
+/* 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;
+\r
+unsigned char* get_ie_elem(unsigned char* msa, ELEMENTID_T elm_id,
+ unsigned short rx_len,unsigned short tag_param_offset)
+{
+ unsigned short 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. */
+unsigned char get_from_ds(unsigned char* 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. */
+unsigned char get_to_ds(unsigned char* 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(unsigned char* msa, unsigned char* 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(unsigned char* msa, unsigned char* 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(unsigned char* msa, unsigned char* 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(unsigned char* data, unsigned char* 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);
+}
+
+extern int is_same_network(struct bss_descriptor *src,
+ struct bss_descriptor *dst);
+extern void clear_bss_descriptor(struct bss_descriptor *bss);
+void rda5890_network_information(struct rda5890_private *priv,
+ char *info, unsigned short info_len)
+{\r
+ union iwreq_data wrqu;\r
+ struct bss_descriptor *iter_bss;\r
+ struct bss_descriptor *safe;\r
+ struct bss_descriptor bss_desc;\r
+ struct bss_descriptor * bss = &bss_desc;\r
+\r
+ unsigned char *pos, *end, *p;\r
+ unsigned char n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0;\r
+ struct ieee_ie_country_info_set *pcountryinfo;\r
+ int ret;\r
+ unsigned char* msa = &info[9];
+ unsigned short msa_len = info[6] | (info[7] << 8);
+\r
+ if(!priv->scan_running)\r
+ goto done;\r
+ \r
+ if((msa_len - 1 + 9 ) != info_len)
+ {
+ RDA5890_ERRP("rda5890_network_information verify lengh feild failed \n");
+ }
+
+ memset(bss, 0, sizeof (struct bss_descriptor));\r
+ bss->rssi = info[8];\r
+ msa_len -= 1; // has rssi\r
+
+ get_BSSID(msa, bss->bssid);\r
+\r
+ end = msa + msa_len;\r
+ \r
+ //mac head\r
+ pos = msa + 24;\r
+ //time stamp\r
+ pos += 8;\r
+ //beacon\r
+ bss->beaconperiod = *(pos) | (*(pos + 1) << 8);\r
+ pos += 2 ;\r
+ //capability\r
+ bss->capability = *(pos) | (*(pos + 1) << 8);\r
+ pos += 2;\r
+\r
+ if (bss->capability & WLAN_CAPABILITY_IBSS)\r
+ bss->mode = IW_MODE_ADHOC;\r
+ else\r
+ bss->mode = IW_MODE_INFRA;\r
+\r
+ /* process variable IE */\r
+ while (pos + 2 <= end) {\r
+ if (pos + pos[1] > end) {\r
+#ifdef SCAN_RESULT_DEBUG \r
+ RDA5890_DBGP("process_bss: error in processing IE, "\r
+ "bytes left < IE length\n");\r
+#endif\r
+ break;\r
+ }\r
+\r
+ switch (pos[0]) {\r
+ case WLAN_EID_SSID:\r
+ bss->ssid_len = min_t(int, IEEE80211_MAX_SSID_LEN, pos[1]);\r
+ memcpy(bss->ssid, pos + 2, bss->ssid_len);\r
+#ifdef SCAN_RESULT_DEBUG \r
+ RDA5890_DBGP("got SSID IE: '%s', len %u %d\n",\r
+ bss->ssid,\r
+ bss->ssid_len, pos[1]);\r
+#endif\r
+ break;\r
+\r
+ case WLAN_EID_SUPP_RATES:\r
+ n_basic_rates = min_t(uint8_t, MAX_RATES, pos[1]);\r
+ memcpy(bss->rates, pos + 2, n_basic_rates);\r
+ got_basic_rates = 1;\r
+#ifdef SCAN_RESULT_DEBUG \r
+ RDA5890_DBGP("got RATES IE\n");\r
+#endif\r
+ break;\r
+\r
+ case WLAN_EID_FH_PARAMS:\r
+#ifdef SCAN_RESULT_DEBUG \r
+ RDA5890_DBGP("got FH IE\n");\r
+#endif\r
+ break;\r
+\r
+ case WLAN_EID_DS_PARAMS:\r
+#ifdef SCAN_RESULT_DEBUG \r
+ RDA5890_DBGP("got DS IE\n");\r
+#endif\r
+ break;\r
+\r
+ case WLAN_EID_CF_PARAMS:\r
+#ifdef SCAN_RESULT_DEBUG \r
+ RDA5890_DBGP("got CF IE\n");\r
+#endif\r
+ break;\r
+\r
+ case WLAN_EID_IBSS_PARAMS:\r
+#ifdef SCAN_RESULT_DEBUG \r
+ RDA5890_DBGP("got IBSS IE\n");\r
+#endif\r
+ break;\r
+\r
+ case WLAN_EID_COUNTRY:\r
+ pcountryinfo = (struct ieee_ie_country_info_set *) pos;\r
+#ifdef SCAN_RESULT_DEBUG \r
+ RDA5890_DBGP("got COUNTRY IE\n");\r
+#endif\r
+ break;\r
+\r
+ case WLAN_EID_EXT_SUPP_RATES:\r
+ /* only process extended supported rate if data rate is\r
+ * already found. Data rate IE should come before\r
+ * extended supported rate IE\r
+ */\r
+#ifdef SCAN_RESULT_DEBUG \r
+ RDA5890_DBGP("got RATESEX IE\n");\r
+#endif\r
+ if (!got_basic_rates) {\r
+#ifdef SCAN_RESULT_DEBUG \r
+ RDA5890_DBGP("... but ignoring it\n");\r
+#endif\r
+ break;\r
+ }\r
+\r
+ n_ex_rates = pos[1];\r
+ if (n_basic_rates + n_ex_rates > MAX_RATES)\r
+ n_ex_rates = MAX_RATES - n_basic_rates;\r
+\r
+ p = bss->rates + n_basic_rates;\r
+ memcpy(p, pos + 2, n_ex_rates);\r
+ break;\r
+\r
+ case WLAN_EID_GENERIC:\r
+ if (pos[1] >= 4 &&\r
+ pos[2] == 0x00 && pos[3] == 0x50 &&\r
+ pos[4] == 0xf2 && pos[5] == 0x01) {\r
+ bss->wpa_ie_len = min(pos[1] + 2, MAX_WPA_IE_LEN);\r
+ memcpy(bss->wpa_ie, pos, bss->wpa_ie_len);\r
+#ifdef SCAN_RESULT_DEBUG \r
+ RDA5890_DBGP("got WPA IE \n");\r
+#endif\r
+ }
+ else {\r
+#ifdef SCAN_RESULT_DEBUG \r
+ RDA5890_DBGP("got generic IE: %02x:%02x:%02x:%02x, len %d\n",\r
+ pos[2], pos[3],\r
+ pos[4], pos[5],\r
+ pos[1]);\r
+#endif\r
+ }\r
+ break;\r
+\r
+ case WLAN_EID_RSN:\r
+#ifdef SCAN_RESULT_DEBUG \r
+ RDA5890_DBGP("got RSN IE\n");\r
+#endif\r
+ bss->rsn_ie_len = min(pos[1] + 2, MAX_WPA_IE_LEN);\r
+ memcpy(bss->rsn_ie, pos, bss->rsn_ie_len);\r
+ break;\r
+\r
+ case IWAPI:\r
+#ifdef SCAN_RESULT_DEBUG \r
+ RDA5890_DBGP("got WAPI IE\n");\r
+#endif\r
+ bss->wapi_ie_len = min(pos[1] + 2, 100);\r
+ memcpy(bss->wapi_ie, pos, bss->wapi_ie_len);\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+\r
+ pos += pos[1] + 2;\r
+ }\r
+ \r
+ bss->last_scanned = jiffies;\r
+\r
+ /* add scaned bss into list */\r
+ if (1) {\r
+ struct bss_descriptor *found = NULL;\r
+ struct bss_descriptor *oldest = NULL;\r
+\r
+ /* Try to find this bss in the scan table */\r
+ list_for_each_entry (iter_bss, &priv->network_list, list) {\r
+ if (is_same_network(iter_bss, bss)) {\r
+ found = iter_bss;
+ break;
+ }
+
+ if ((oldest == NULL) ||
+ (iter_bss->last_scanned < oldest->last_scanned))
+ oldest = iter_bss;
+ }
+\r
+ if (found) {
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE,
+ "FOUND SAME %s, update\n", found->ssid);
+ /* found, clear it */
+ clear_bss_descriptor(found);
+ } else if (!list_empty(&priv->network_free_list)) {
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE,
+ "FOUND NEW %s, add\n", bss->ssid);\r
+ /* Pull one from the free list */
+ found = list_entry(priv->network_free_list.next,
+ struct bss_descriptor, list);
+ list_move_tail(&found->list, &priv->network_list);
+ } else if (oldest) {
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE,
+ "FOUND NEW %s, no space, replace oldest %s\n",
+ bss->ssid, oldest->ssid);
+ /* If there are no more slots, expire the oldest */
+ found = oldest;
+ clear_bss_descriptor(found);
+ list_move_tail(&found->list, &priv->network_list);
+ } else {
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE,
+ "FOUND NEW but no space to store\n");
+ }
+
+ /* Copy the locally created newbssentry to the scan table */
+ memcpy(found, bss, offsetof(struct bss_descriptor, list));\r
+ }\r
+\r
+done:\r
+#ifdef SCAN_RESULT_DEBUG \r
+ RDA5890_DBGP("rda5890_network_information ret %d \n", ret);\r
+#endif\r
+ return;\r
+}
+\r
+\r
+\r
--- /dev/null
+#include "rda5890_dev.h"
+#include "rda5890_wid.h"
+#include "rda5890_defs.h"
+
+#ifdef WIFI_TEST_MODE
+#include <linux/nfs_fs.h>
+#include <linux/nfs_fs_sb.h>
+#include <linux/nfs_mount.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/tty.h>
+#include <linux/syscalls.h>
+#include <asm/termbits.h>
+#include <linux/serial.h>
+#endif
+
+static u8 sdio_patch_complete = 0;
+static u8 sdio_init_complete = 0;
+
+//#define dig_access_pmu_cancel
+const u32 wifi_core_patch_data_32[][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, 0xEA0402C5},
+ {0x0010814C, 0xE59F600C},
+ {0x00108150, 0xE3A04000},
+ {0x00108154, 0xE5C64000},
+ {0x00108158, 0xE59F6004},
+ {0x0010815C, 0xE59FF004},
+ {0x00108160, 0x0010200B},
+ {0x00108164, 0x0010121D},
+ {0x00108168, 0x00007634},
+ {0x0010816C, 0xEAFFFFEC},
+ {0x00108170, 0xEA03E0FF},
+ {0x00108174, 0x13A00000},
+ {0x00108178, 0x1B000001},
+ {0x0010817C, 0x15C57005},
+ {0x00108180, 0xE59FF004},
+ {0x00108184, 0xE51FF004},
+ {0x00108188, 0x000024DC},
+ {0x0010818C, 0x0000FD74},
+ {0x001087B0, 0xEA0403A4},
+ {0x001087B4, 0x08BD4010},
+ {0x001087B8, 0x0A000002},
+ {0x001087BC, 0x13A00001},
+ {0x001087C0, 0x18BD4010},
+ {0x001087C4, 0x1A000001},
+ {0x001087C8, 0xE51FF004},
+ {0x001087CC, 0x0000D470},
+ {0x001087D0, 0xE51FF004},
+ {0x001087D4, 0x0000D2C0},
+ {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, 0x00007630},
+ {0x2004012C, 0x00108148},
+ {0x20040110, 0x00017158},
+ {0x20040130, 0x0010816C},
+ {0x20040114, 0x0000FD70},
+ {0x20040134, 0x00108170},
+ {0x20040118, 0x0000791C},
+ {0x20040138, 0x001087B0},
+ {0x20040000, 0x00007FFF},
+
+};
+
+const u32 wifi_core_patch_data_32_E[][2] =
+{
+ {0x00108000, 0xEA04012F},
+ {0x00108004, 0x1A000001},
+ {0x00108008, 0xE8BD4010},
+ {0x0010800C, 0xEA000001},
+ {0x00108010, 0xE51FF004},
+ {0x00108014, 0x0000D4AC},
+ {0x00108018, 0xE51FF004},
+ {0x0010801C, 0x0000D654},
+ {0x00108020, 0xEA0401F4},
+ {0x00108024, 0xE59F600C},
+ {0x00108028, 0xE3A04000},
+ {0x0010802C, 0xE5C64000},
+ {0x00108030, 0xE59F6004},
+ {0x00108034, 0xE59FF004},
+ {0x00108038, 0x00101CE7},
+ {0x0010803C, 0x00101039},
+ {0x00108040, 0x00007850},
+ {0x00108044, 0xEAFFFFEC},
+ {0x00108048, 0xEA03E034},
+ {0x0010804C, 0x13A00000},
+ {0x00108050, 0x1B000001},
+ {0x00108054, 0x15C57005},
+ {0x00108058, 0xE59FF004},
+ {0x0010805C, 0xE51FF004},
+ {0x00108060, 0x000024E0},
+ {0x00108064, 0x0000FF78},
+ {0x20040004, 0x00007B40},
+ {0x20040024, 0x00108000},
+ {0x20040008, 0x0000784C},
+ {0x20040028, 0x00108020},
+ {0x2004000C, 0x00017518},
+ {0x2004002C, 0x00108044},
+ {0x20040010, 0x0000FF74},
+ {0x20040030, 0x00108048},
+ {0x20040000, 0x0000000D},
+
+};
+
+const u8 wifi_core_patch_data_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
+
+const u32 wifi_core_init_data_32[][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 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_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 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, 0x780369AF }, //disable tports wait 100ms;
+ { 0x30000010, 0x7000FFFF },//wait 500ms;
+ { 0x5000050c, 0x00008000 },// for association power save
+};
+
+u32 wifi_notch_data[][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, 0x076794b4},
+ {0x001009d8, 0x50090044},
+ {0x001009dc, 0x10000000},
+ //ch 6
+ {0x00100a10, 0x50090040},
+ {0x00100a14, 0x077c71de},
+ {0x00100a18, 0x50090044},
+ {0x00100a1c, 0x046d242e},
+ //ch 7
+ {0x00100a50, 0x50090040},
+ {0x00100a54, 0x10000000},
+ {0x00100a58, 0x50090044},
+ {0x00100a5c, 0x057e7ec0},
+ //ch 8
+ {0x00100a90, 0x50090040},
+ {0x00100a94, 0x077c7e22},
+ {0x00100a98, 0x50090044},
+ {0x00100a9c, 0x046d2bd2},
+ //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, 0x07764310},
+ {0x00100b98, 0x50090044},
+ {0x00100b9c, 0x10000000},
+ //ch 13
+ {0x00100bd0, 0x50090040},
+ {0x00100bd4, 0x056794b4},
+ {0x00100bd8, 0x50090044},
+ {0x00100bdc, 0x10000000},
+ //ch 14
+ {0x00100c10, 0x50090040},
+ {0x00100c14, 0x0779c279},
+ {0x00100c18, 0x50090044},
+ {0x00100c1c, 0x0779cd87},
+};
+
+u32 wifi_notch_data_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, 0x076794b4},
+ {0x00100894, 0x50090044},
+ {0x00100898, 0x10000000},
+ //ch 6
+ {0x001008BC, 0x50090040},
+ {0x001008C0, 0x077c71de},
+ {0x001008C4, 0x50090044},
+ {0x001008C8, 0x046d242e},
+ //ch 7
+ {0x001008EC, 0x50090040},
+ {0x001008F0, 0x10000000},
+ {0x001008F4, 0x50090044},
+ {0x001008F8, 0x057e7140},
+ //ch 8
+ {0x0010091C, 0x50090040},
+ {0x00100920, 0x077c7e22},
+ {0x00100924, 0x50090044},
+ {0x00100928, 0x046d2bd2},
+ //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, 0x07764310},
+ {0x001009E4, 0x50090044},
+ {0x001009E8, 0x10000000},
+ //ch 13
+ {0x00100A0C, 0x50090040},
+ {0x00100A10, 0x056794b4},
+ {0x00100A14, 0x50090044},
+ {0x00100A18, 0x10000000},
+ //ch 14
+ {0x00100A3C, 0x50090040},
+ {0x00100A40, 0x0779c279},
+ {0x00100A44, 0x50090044},
+ {0x00100A4c, 0x0779cd87},
+};
+
+//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},
+};
+
+int rda5890_get_fw_version_polling(struct rda5890_private *priv, unsigned int* version)
+{
+ int ret = -1;
+ char wid_req[255];
+ unsigned short wid_req_len = 6;
+ char wid_rsp[32];
+ unsigned short wid_rsp_len = 32;
+ unsigned short wid;
+ char wid_msg_id = priv->wid_msg_id++;
+ unsigned char *ptr_payload;
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_DEBUG,
+ "%s <<< \n", __func__);
+
+ 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 = WID_SYS_FW_VER;
+ wid_req[4] = (char)(wid&0x00FF);
+ wid_req[5] = (char)((wid&0xFF00) >> 8);
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_TRACE,
+ "__func__ <<<\n" );
+
+ ret = rda5890_wid_request_polling(priv, wid_req, wid_req_len,
+ wid_rsp, &wid_rsp_len);
+ if (ret) {
+ goto out;
+ }
+
+ ret = rda5890_check_wid_response(priv->wid_rsp, priv->wid_rsp_len, wid, wid_msg_id,
+ 4, &ptr_payload);
+
+ if(!ret)
+ {
+ memcpy((unsigned char *)version, ptr_payload, 4);
+ }
+ else
+ *version = 0;
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_TRACE,
+ "__func__ version: %x >>> \n" , *version);
+
+out:
+ return ret;
+}
+
+
+int rda5890_write_sdio32_polling(struct rda5890_private *priv,const unsigned int (*data)[2], unsigned int size)
+{
+ int count = size, index = 0;
+ int ret = 0;
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
+ "%s >>> \n", __func__);
+
+ for(index = 0; index < count/8; index ++) //each time write five init data
+ {
+ ret = rda5890_set_core_init_polling(priv, data[8*index], 8);
+ if(ret < 0)
+ goto err;
+ }
+
+ if(count%8 > 0)
+ {
+ ret = rda5890_set_core_init_polling(priv, data[8*index], count%8);
+ if(ret < 0)
+ goto err;
+ }
+err:
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
+ "%s :ret=%d <<< \n", __func__, ret);
+ return ret;
+}
+
+int rda5890_write_sdio32(struct rda5890_private *priv, const unsigned int (*data)[2], unsigned int size)
+{
+ int count = size, index = 0;
+ int ret = 0;
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
+ "%s >>> \n", __func__);
+
+ for(index = 0; index < count/8; index ++) //each time write five init data
+ {
+ ret = rda5890_set_core_init(priv, data[8*index], 8);
+ if(ret < 0)
+ goto err;
+ }
+
+ if(count%8 > 0)
+ {
+ ret = rda5890_set_core_init(priv, data[8*index], count%8);
+ if(ret < 0)
+ goto err;
+ }
+err:
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
+ "%s :ret=%d <<< \n", __func__, ret);
+ return ret;
+}
+
+int rda5890_write_sdio8_polling(struct rda5890_private *priv, const unsigned char (*data)[2], unsigned int size)
+{
+ int count = size, index = 0;
+ int ret = 0;
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
+ "%s >>> \n", __func__);
+
+ for(index = 0; index < count/8; index ++) //each time write five init data
+ {
+ ret = rda5890_set_core_patch_polling(priv, data[8*index], 8);
+ if(ret < 0)
+ goto err;
+ }
+
+ if(count%8 > 0)
+ {
+ ret = rda5890_set_core_patch_polling(priv, data[8*index], count%8);
+ if(ret < 0)
+ goto err;
+ }
+err:
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
+ "%s :ret=%d <<< \n", __func__, ret);
+ return ret;
+}
+
+
+int rda5890_write_sdio8(struct rda5890_private *priv ,const unsigned char (*data)[2], unsigned int size)
+{
+ int count = size, index = 0;
+ int ret = 0;
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
+ "%s >>> \n", __func__);
+
+ for(index = 0; index < count/8; index ++) //each time write five init data
+ {
+ ret = rda5890_set_core_patch(priv, data[8*index], 8);
+ if(ret < 0)
+ goto err;
+ }
+
+ if(count%8 > 0)
+ {
+ ret = rda5890_set_core_patch(priv, data[8*index], count%8);
+ if(ret < 0)
+ goto err;
+ }
+err:
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
+ "%s :ret=%d <<< \n", __func__, ret);
+ return ret;
+}
+
+int rda5890_sdio_patch_core_32(struct rda5890_private *priv)
+{
+ int ret = 0;
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
+ "%s >>> \n", __func__);
+
+ if(priv->version == 7)
+ ret = rda5890_write_sdio32_polling(priv,wifi_core_patch_data_32,
+ sizeof(wifi_core_patch_data_32)/sizeof(wifi_core_patch_data_32[0]));
+ else if(priv->version == 4 || priv->version == 5)
+ ret = rda5890_write_sdio32_polling(priv,wifi_core_patch_data_32_E,
+ sizeof(wifi_core_patch_data_32_E)/sizeof(wifi_core_patch_data_32_E[0]));
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
+ "%s <<< \n", __func__);
+ return ret;
+}
+
+
+int rda5890_sdio_init_core(struct rda5890_private *priv)
+{
+ int ret = 0;
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
+ "%s <<< \n", __func__);
+ if(priv->version == 7)
+ ret = rda5890_write_sdio32(priv, wifi_core_init_data_32,
+ sizeof(wifi_core_init_data_32)/sizeof(wifi_core_init_data_32[0]));
+ else if(priv->version == 4 || priv->version == 5)
+ ret = rda5890_write_sdio32(priv, wifi_core_init_data_32_E,
+ sizeof(wifi_core_init_data_32_E)/sizeof(wifi_core_init_data_32_E[0]));
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
+ "%s >>> \n", __func__);
+
+ return ret;
+}
+
+int rda5890_sdio_init_core_polling(struct rda5890_private *priv)
+{
+ int ret = 0;
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
+ "%s <<< \n", __func__);
+ if(priv->version == 7)
+ ret = rda5890_write_sdio32_polling(priv, wifi_core_init_data_32,
+ sizeof(wifi_core_init_data_32)/sizeof(wifi_core_init_data_32[0]));
+ else if(priv->version == 4 || priv->version == 5)
+ ret = rda5890_write_sdio32_polling(priv, wifi_core_init_data_32_E,
+ sizeof(wifi_core_init_data_32_E)/sizeof(wifi_core_init_data_32_E[0]));
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
+ "%s >>> \n", __func__);
+ return ret;
+}
+
+
+int rda5890_sdio_patch_core_8(struct rda5890_private *priv)
+{
+ int ret = 0;
+ //for patch in byte mode
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
+ "%s <<< \n", __func__);
+
+ ret = rda5890_write_sdio8(priv, wifi_core_patch_data_8,
+ sizeof(wifi_core_patch_data_8)/sizeof(wifi_core_patch_data_8[0]));
+
+ //for patch in wake continue clock mode
+ ret = rda5890_sdio_core_wake_mode(priv);
+ if(ret < 0)
+ goto err;
+
+err:
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
+ "%s >>> \n", __func__);
+ return ret;
+}
+
+int rda5890_sdio_patch_core_8_polling(struct rda5890_private *priv)
+{
+ int ret = 0;
+ //for patch in byte mode
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
+ "%s <<< \n", __func__);
+
+ ret = rda5890_write_sdio8_polling(priv, wifi_core_patch_data_8,
+ sizeof(wifi_core_patch_data_8)/sizeof(wifi_core_patch_data_8[0]));
+ if(ret < 0)
+ goto err;
+
+ //for patch in wake continue clock mode
+ ret = rda5890_sdio_core_wake_mode_polling(priv);
+ if(ret < 0)
+ goto err;
+
+err:
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
+ "%s >>> \n", __func__);
+ return ret;
+}
+
+int rda5890_sdio_set_default_notch(struct rda5890_private *priv)
+{
+ int ret = 0;
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
+ "%s <<< \n", __func__);
+
+ if(priv->version == 7)
+ ret = rda5890_write_sdio32(priv, wifi_notch_data,
+ sizeof(wifi_notch_data)/sizeof(wifi_notch_data[0]));
+ else if(priv->version == 4 || priv->version == 5)
+ ret = rda5890_write_sdio32(priv, wifi_notch_data_E,
+ sizeof(wifi_notch_data_E)/sizeof(wifi_notch_data_E[0]));
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
+ "%s <<< \n", __func__);
+ return ret;
+}
+
+int rda5890_sdio_set_default_notch_polling(struct rda5890_private *priv)
+{
+ int ret = 0;
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
+ "%s <<< \n", __func__);
+ if(priv->version == 7)
+ ret = rda5890_write_sdio32_polling(priv, wifi_notch_data,
+ sizeof(wifi_notch_data)/sizeof(wifi_notch_data[0]));
+ else if(priv->version == 4 || priv->version == 5)
+ ret = rda5890_write_sdio32_polling(priv, wifi_notch_data_E,
+ sizeof(wifi_notch_data_E)/sizeof(wifi_notch_data_E[0]));
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
+ "%s <<< \n", __func__);
+ return ret;
+}
+
+
+//
+unsigned char rssi_switch_default_data_u8[][2] =
+{
+ {0x25, 0x00}
+};
+
+void rda5890_sdio_set_notch_by_channel(struct rda5890_private *priv, unsigned int channel)
+{
+#if 0
+ int count = 0, index = 0;
+
+ if(priv->version == 7)
+ count = sizeof(wifi_notch_data)/(sizeof(wifi_notch_data[0]) * 4);
+ else if(priv->version == 4 || priv->version == 5)
+ count = sizeof(wifi_notch_data_E)/(sizeof(wifi_notch_data_E[0]) * 4);
+ channel = channel % count;
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
+ "%s >>> \n", __func__);
+
+ if(channel > 1)
+ channel -= 1;
+
+ if(priv->version == 7)
+ {
+ rda5890_set_core_init(priv, wifi_notch_data[4*channel], 4);
+ rda5890_set_core_patch(priv, rssi_switch_default_data_u8, 1);
+ }
+ else if(priv->version == 4 || priv->version == 5)
+ {
+ rda5890_set_core_init(priv, wifi_notch_data_E[4*channel], 4);
+ rda5890_set_core_patch(priv, rssi_switch_default_data_u8, 1);
+ }
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
+ "%s <<< ch = %d \n", __func__, channel + 1);
+#endif
+}
+
+int rda5890_sdio_core_wake_mode(struct rda5890_private *priv)
+{
+ int ret = 0;
+
+ ret = rda5890_write_sdio32(priv, wifi_core_data_wake,
+ sizeof(wifi_core_data_wake)/sizeof(wifi_core_data_wake[0]));
+
+ return ret;
+}
+
+int rda5890_sdio_core_wake_mode_polling(struct rda5890_private *priv)
+{
+ int ret = 0;
+
+ ret = rda5890_write_sdio32_polling(priv, wifi_core_data_wake,
+ sizeof(wifi_core_data_wake)/sizeof(wifi_core_data_wake[0]));
+ return ret;
+}
+
+int rda5890_sdio_core_sleep_mode(struct rda5890_private *priv)
+{
+ int ret = 0;
+
+ ret = rda5890_write_sdio32(priv,wifi_core_data_sleep,
+ sizeof(wifi_core_data_sleep)/sizeof(wifi_core_data_sleep[0]));
+ return ret;
+}
+
+extern void export_wifi_eirq_enable();
+int rda5890_sdio_init(struct rda5890_private *priv)
+{
+ int ret = 0;
+ unsigned long para = 0;
+
+ sdio_init_complete = 0;
+ sdio_patch_complete = 0;
+
+ printk(KERN_INFO " rda5890_sdio_init <<< \n");
+
+ ret = rda5890_sdio_patch_core_32(priv);
+ if(ret < 0)
+ goto err;
+
+ printk(KERN_INFO "sdio_patch_complete wid_msg = %d \n", priv->wid_msg_id);
+ rda5890_shedule_timeout(10); //10ms delay
+ sdio_patch_complete = 1;
+
+#if 0
+ ret = rda5890_sdio_init_core(priv);
+ if(ret < 0)
+ goto err;
+
+ ret = rda5890_sdio_patch_core_8(priv);
+ if(ret < 0)
+ goto err;
+
+ ret = rda5890_sdio_set_default_notch(priv);
+ if(ret < 0)
+ goto err;
+#else
+
+ ret = rda5890_sdio_init_core_polling(priv);
+ if(ret < 0)
+ goto err;
+
+ ret = rda5890_sdio_patch_core_8_polling(priv);
+ if(ret < 0)
+ goto err;
+
+ ret = rda5890_sdio_set_default_notch_polling(priv);
+ if(ret < 0)
+ goto err;
+
+#endif
+ export_wifi_eirq_enable();
+
+#if 0
+ rda5890_generic_set_ulong(priv, WID_MEMORY_ADDRESS, 0x30010008);
+ rda5890_generic_get_ulong(priv, WID_MEMORY_ACCESS_32BIT, ¶);
+ printk(KERN_INFO "rda5890_sdio_init para = %x \n", para);
+ para |= 0x200;
+ rda5890_generic_set_ulong(priv, WID_MEMORY_ACCESS_32BIT, para);
+
+ rda5890_generic_set_ulong(priv, WID_MEMORY_ADDRESS, 0x30010010);
+ rda5890_generic_get_ulong(priv, WID_MEMORY_ACCESS_32BIT, ¶);
+ printk(KERN_INFO "rda5890_sdio_init para1 = %x \n", para);
+ para &= ~0x200;
+ rda5890_generic_set_ulong(priv, WID_MEMORY_ACCESS_32BIT, para);
+#endif
+
+ sdio_init_complete = 1;
+
+err:
+ return ret;
+}
+
+//rssi > 200
+u32 rssi_switch_data_u32[][2] =
+{
+ {0x50090040, 0x10000000},
+ {0x50090044, 0x10000000},
+};
+
+u8 rssi_switch_data_u8[][2] =
+{
+ {0x25, 0x18}
+};
+
+void rda5890_rssi_up_to_200(struct rda5890_private *priv)
+{
+#if 0
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
+ "%s >>> \n", __func__);
+ rda5890_set_core_init(priv, rssi_switch_data_u32, 2);
+ rda5890_set_core_patch(priv, rssi_switch_data_u8, 1);
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
+ "%s <<< \n", __func__);
+#endif
+}
+
+u32 rda5990_assoc_power_save_data32[][2] =
+{
+ { 0x5000050c, 0x00008000 }// for association power save
+};
+
+void rda5990_assoc_power_save(struct rda5890_private *priv)
+{
+ rda5890_set_core_init(priv, rda5990_assoc_power_save_data32, 1);
+}
+
+unsigned char is_sdio_init_complete(void)
+{
+ return sdio_init_complete;
+}
+unsigned char is_sdio_patch_complete(void) //after patch complete need check write flow
+{
+ return sdio_patch_complete;
+}
+
+#ifdef WIFI_TEST_MODE
+
+static unsigned int wifi_test_mode_rx_notch_32[][2] =
+{
+ //item:notch_filter_5
+ {0x50090040,0x076794b4},//8m
+ {0x50090044,0x10000000},
+ //item:notch_filter_6
+ {0x50090040,0x077c71de},//3m
+ {0x50090044,0x046d242e},//7m
+ //item:notch_filter_7
+ {0x50090040,0x077e7ec0},//2m
+ {0x50090044,0x077e7140},//-2m
+ //item:notch_filter_8
+ {0x50090040,0x077c7e22},//3m
+ {0x50090044,0x046d2bd2},//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 unsigned int wifi_test_mode_agc_patch32[][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 unsigned int rda5990_test_mode_digital32[][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
+};
+
+int rda5890_set_test_mode(struct rda5890_private *priv)
+{
+ int ret = 0;
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_CRIT,
+ "%s >>> \n", __func__);
+
+ sdio_init_complete = 0;
+ sdio_patch_complete = 0;
+ ret = rda5890_sdio_patch_core_32(priv);
+ if(ret < 0)
+ goto err;
+ sdio_patch_complete = 1;
+
+ ret = rda5890_write_sdio8_polling(priv, wifi_core_patch_data_8,
+ sizeof(wifi_core_patch_data_8)/sizeof(wifi_core_patch_data_8[0]));
+ if(ret < 0)
+ goto err;
+
+ ret = rda5890_write_sdio32_polling(priv, rda5990_test_mode_digital32,
+ sizeof(rda5990_test_mode_digital32)/sizeof(rda5990_test_mode_digital32[0]));
+ if(ret < 0)
+ goto err;
+
+ ret = rda5890_write_sdio32_polling(priv, wifi_test_mode_agc_patch32,
+ sizeof(wifi_test_mode_agc_patch32)/sizeof(wifi_test_mode_agc_patch32[0]));
+ if(ret < 0)
+ goto err;
+
+ ret = rda5890_write_sdio32_polling(priv, wifi_test_mode_rx_notch_32,
+ sizeof(wifi_test_mode_rx_notch_32)/sizeof(wifi_test_mode_rx_notch_32[0]));
+ if(ret < 0)
+ goto err;
+
+
+ ret = rda5890_sdio_set_default_notch_polling(priv);
+ if(ret < 0)
+ goto err;
+
+ export_wifi_eirq_enable();
+ sdio_init_complete = 1;
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_CRIT,
+ "%s <<< \n", __func__);
+ return ret;
+
+err:
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_CRIT, "rda5890_set_test_mode err!! \n" );
+ return ret;
+}
+#endif
+
+
\ No newline at end of file
--- /dev/null
+#include <linux/module.h>
+#include <linux/dcache.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/etherdevice.h>
+#include <net/iw_handler.h>
+
+#include "rda5890_defs.h"
+#include "rda5890_dev.h"
+#include "rda5890_wid.h"
+#include "rda5890_wext.h"
+
+void rda5890_data_rx(struct rda5890_private *priv,
+ char *data, unsigned short data_len)
+{
+ struct sk_buff *skb;
+ char *pkt_data;
+
+ RDA5890_DBGLAP(RDA5890_DA_TXRX, RDA5890_DL_DEBUG,
+ "%s >>>\n", __func__);
+
+ skb = dev_alloc_skb(data_len + NET_IP_ALIGN);
+ if (!skb) {
+ priv->stats.rx_dropped++;
+ return;
+ }
+ skb_reserve(skb, NET_IP_ALIGN);
+ pkt_data = skb_put(skb, data_len);
+ memcpy(pkt_data, data, data_len);
+ skb->dev = priv->dev;
+ skb->protocol = eth_type_trans(skb, priv->dev);
+ skb->ip_summed = CHECKSUM_NONE;
+
+ RDA5890_DBGLAP(RDA5890_DA_TXRX, RDA5890_DL_TRACE,
+ "netif rx, len %d\n", skb->len);
+ RDA5890_DBGLAP(RDA5890_DA_TXRX, RDA5890_DL_TRACE,
+ "%02x %02x %02x %02x ... ... %02x %02x %02x %02x\n",
+ skb->data[0], skb->data[1], skb->data[2], skb->data[3],
+ skb->data[skb->len - 4], skb->data[skb->len - 3],
+ skb->data[skb->len - 2], skb->data[skb->len - 1]);
+
+ priv->stats.rx_packets++;
+ priv->stats.rx_bytes += data_len;
+
+ if (in_interrupt())
+ netif_rx(skb);
+ else
+ netif_rx_ni(skb);
+
+ RDA5890_DBGLAP(RDA5890_DA_TXRX, RDA5890_DL_DEBUG,
+ "%s <<<\n", __func__);
+}
+
+
+int rda5890_host_to_card(struct rda5890_private *priv,
+ char *packet, unsigned short packet_len, unsigned char packet_type)
+{
+ int ret = 0;
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_DEBUG,
+ "%s <<< \n", __func__);
+
+ ret = priv->hw_host_to_card(priv, packet, packet_len, packet_type);
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_DEBUG,
+ "%s >>> \n", __func__);
+
+ return ret;
+}
+
+
+int rda5890_data_tx(struct rda5890_private *priv,
+ struct sk_buff *skb, struct net_device *dev)
+{
+ int ret;
+ char *pkt_data;
+ uint16_t pkt_len;
+ char buf[ETH_FRAME_LEN + 2];
+ uint16_t data_len;
+
+ RDA5890_DBGLAP(RDA5890_DA_TXRX, RDA5890_DL_DEBUG,
+ "%s <<< \n", __func__);
+
+ ret = NETDEV_TX_OK;
+
+ if (!skb->len || (skb->len > ETH_FRAME_LEN)) {
+ priv->stats.tx_dropped++;
+ priv->stats.tx_errors++;
+ goto free;
+ }
+
+ pkt_data = skb->data;
+ pkt_len = skb->len;
+
+ RDA5890_DBGLAP(RDA5890_DA_TXRX, RDA5890_DL_TRACE,
+ "netif tx len %d\n", pkt_len);
+ RDA5890_DBGLAP(RDA5890_DA_TXRX, RDA5890_DL_TRACE,
+ "%02x %02x %02x %02x ... ... %02x %02x %02x %02x\n",
+ skb->data[0], skb->data[1], skb->data[2], skb->data[3],
+ skb->data[skb->len - 4], skb->data[skb->len - 3],
+ skb->data[skb->len - 2], skb->data[skb->len - 1]);
+
+ /* FIXME: we can save this memcpy by adding header inside the sdio driver */
+ memcpy(buf + 2, pkt_data, pkt_len);
+ data_len = pkt_len + 2;
+ buf[0] = (char)(data_len&0xFF);
+ buf[1] = (char)((data_len>>8)&0x0F);
+ buf[1] |= 0x10; // for DataOut 0x1
+
+ //RDA5890_DBGLAP(RDA5890_DA_ETHER, RDA5890_DL_NORM,
+ // "sdio tx len %d\n", data_len);
+ //RDA5890_DBGLAP(RDA5890_DA_ETHER, RDA5890_DL_NORM,
+ // "%02x %02x %02x %02x ... ... %02x %02x %02x %02x\n",
+ // buf[0], buf[1], buf[2], buf[3],
+ // buf[data_len - 4], buf[data_len - 3],
+ // buf[data_len - 2], buf[data_len - 1]);
+
+ ret = rda5890_host_to_card(priv, buf, data_len, DATA_REQUEST_PACKET);
+ if (ret) {
+ RDA5890_ERRP("host_to_card send failed, ret = %d\n", ret);
+ goto free;
+ }
+
+ priv->stats.tx_packets++;
+ priv->stats.tx_bytes += skb->len;
+
+ dev->trans_start = jiffies;
+
+ free:
+ /* free right away, since we do copy */
+ dev_kfree_skb_any(skb);
+
+ RDA5890_DBGLAP(RDA5890_DA_TXRX, RDA5890_DL_DEBUG,
+ "%s >>> \n", __func__);
+ return ret;
+}
+
--- /dev/null
+#ifndef _RDA5890_TXRX_H_
+#define _RDA5890_TXRX_H_
+
+int rda5890_host_to_card(struct rda5890_private *priv,
+ char *packet, unsigned short packet_len, unsigned char packet_type);
+
+void rda5890_data_rx(struct rda5890_private *priv,
+ char *data, unsigned short data_len);
+int rda5890_data_tx(struct rda5890_private *priv,
+ struct sk_buff *skb, struct net_device *dev);
+
+#endif
+
--- /dev/null
+/**
+ * This file contains ioctl functions
+ */
+#include <linux/ctype.h>
+#include <linux/delay.h>
+#include <linux/if.h>
+#include <linux/if_arp.h>
+#include <linux/wireless.h>
+#include <linux/bitops.h>
+
+#include <net/iw_handler.h>
+#include <linux/etherdevice.h>
+
+#include "rda5890_defs.h"
+#include "rda5890_dev.h"
+#include "rda5890_ioctl.h"
+#include "rda5890_wid.h"
+#include "rda5890_wext.h"
+
+#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
+
+static int rda5890_get_name(struct net_device *dev, struct iw_request_info *info,
+ char *cwrq, char *extra)
+{
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s >>>\n", __func__);
+
+ /* We could add support for 802.11n here as needed. Jean II */
+ snprintf(cwrq, IFNAMSIZ, "IEEE 802.11b/g");
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s <<<\n", __func__);
+ return 0;
+}
+
+static int rda5890_get_freq(struct net_device *dev, struct iw_request_info *info,
+ struct iw_freq *fwrq, char *extra)
+{
+ //struct rda5890_private *priv = netdev_priv(dev);
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s >>>\n", __func__);
+
+ fwrq->m = (long)2437 * 100000;
+ fwrq->e = 1;
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s <<<\n", __func__);
+ return 0;
+}
+
+static int rda5890_get_wap(struct net_device *dev, struct iw_request_info *info,
+ struct sockaddr *awrq, char *extra)
+{
+ struct rda5890_private *priv = (struct rda5890_private *) netdev_priv(dev);
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_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;
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s <<<\n", __func__);
+ return 0;
+}
+
+static int rda5890_set_nick(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s >>>\n", __func__);
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s <<<\n", __func__);
+ return 0;
+}
+
+static int rda5890_get_nick(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s >>>\n", __func__);
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s <<<\n", __func__);
+ return 0;
+}
+
+static int rda5890_set_rts(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s >>>\n", __func__);
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s <<<\n", __func__);
+ return 0;
+}
+
+static int rda5890_get_rts(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ //struct rda5890_private *priv = netdev_priv(dev);
+ int ret = 0;
+ u16 val = 0;
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s >>>\n", __func__);
+
+ val = 600;
+
+ vwrq->value = val;
+ vwrq->disabled = val > RDA5890_RTS_MAX_VALUE; /* min rts value is 0 */
+ vwrq->fixed = 1;
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s <<<\n", __func__);
+ return ret;
+}
+
+static int rda5890_set_frag(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s >>>\n", __func__);
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s <<<\n", __func__);
+ return 0;
+}
+
+static int rda5890_get_frag(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ //struct rda5890_private *priv = netdev_priv(dev);
+ int ret = 0;
+ u16 val = 0;
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s >>>\n", __func__);
+
+ val = 1460;
+
+ vwrq->value = val;
+ vwrq->disabled = ((val < RDA5890_FRAG_MIN_VALUE)
+ || (val > RDA5890_FRAG_MAX_VALUE));
+ vwrq->fixed = 1;
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s <<<\n", __func__);
+ return ret;
+}
+
+static int rda5890_get_mode(struct net_device *dev,
+ struct iw_request_info *info, u32 * uwrq, char *extra)
+{
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s >>>\n", __func__);
+
+ *uwrq = IW_MODE_INFRA;
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s <<<\n", __func__);
+ return 0;
+}
+
+static int rda5890_get_txpow(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ //struct rda5890_private *priv = netdev_priv(dev);
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s >>>\n", __func__);
+
+ vwrq->value = 20; // in dbm
+ vwrq->fixed = 1;
+ vwrq->disabled = 0;
+ vwrq->flags = IW_TXPOW_DBM;
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s <<<\n", __func__);
+ return 0;
+}
+
+static int rda5890_set_retry(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s >>>\n", __func__);
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s <<<\n", __func__);
+ return 0;
+}
+
+static int rda5890_get_retry(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ //struct rda5890_private *priv = netdev_priv(dev);
+ int ret = 0;
+ u16 val = 0;
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_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;
+ }
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s <<<\n", __func__);
+ return ret;
+}
+
+/**
+ * 802.11b/g supported bitrates (in 500Kb/s units)
+ */
+u8 rda5890_bg_rates[MAX_RATES] =
+ { 0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18,
+ 0x24, 0x30, 0x48, 0x60, 0x6c,0x00, 0x00 };
+
+u16 rda5890_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 rda5890_get_range(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ //struct rda5890_private *priv = netdev_priv(dev);
+ struct iw_range *range = (struct iw_range *)extra;
+ int i;
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_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(rda5890_bg_rates);
+ for (i = 0; i < range->num_bitrates; i++)
+ range->bitrate[i] = rda5890_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 < rda5890_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 = RDA5890_RTS_MIN_VALUE;
+ range->max_rts = RDA5890_RTS_MAX_VALUE;
+ range->min_frag = RDA5890_FRAG_MIN_VALUE;
+ range->max_frag = RDA5890_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;
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s <<<\n", __func__);
+ return 0;
+}
+
+static int rda5890_set_power(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ //struct rda5890_private *priv = netdev_priv(dev);
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s >>>\n", __func__);
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s <<<\n", __func__);
+ return 0;
+}
+
+static int rda5890_get_power(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ //struct rda5890_private *priv = netdev_priv(dev);
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s >>>\n", __func__);
+
+ vwrq->value = 0;
+ vwrq->flags = 0;
+ vwrq->disabled = 0;
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s <<<\n", __func__);
+ return 0;
+}
+
+static int rda5890_update_bss_stats(struct rda5890_private *priv)
+{
+ int ret = 0;
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s >>>\n", __func__);
+
+ memcpy(priv->curbssparams.ssid,
+ priv->assoc_ssid, sizeof(priv->curbssparams.ssid));
+
+ if(priv->scan_running == 1)
+ return ret;
+
+ ret = rda5890_get_bssid(priv, priv->curbssparams.bssid);
+ if (ret) {
+ RDA5890_ERRP("rda5890_get_bssid, ret = %d\n", ret);
+ goto out;
+ }
+
+#if 0
+ ret = rda5890_get_channel(priv, &priv->curbssparams.channel);
+ if (ret) {
+ RDA5890_ERRP("rda5890_get_channel, ret = %d\n", ret);
+ goto out;
+ }
+#endif
+
+ ret = rda5890_get_rssi(priv, &priv->curbssparams.rssi);
+ if (ret) {
+ RDA5890_ERRP("rda5890_get_rssi, ret = %d\n", ret);
+ goto out;
+ }
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s <<< ch = %d rssi = %d\n", __func__, priv->curbssparams.channel, priv->curbssparams.rssi);
+
+out:
+ return ret;
+}
+
+static struct iw_statistics *rda5890_get_wireless_stats(struct net_device *dev)
+{
+ struct rda5890_private *priv = (struct rda5890_private *)netdev_priv(dev);
+ int stats_valid = 0;
+ u8 snr;
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s >>>\n", __func__);
+
+ if (priv->connect_status != MAC_CONNECTED)
+ goto out;
+
+ rda5890_update_bss_stats(priv);
+
+ priv->wstats.miss.beacon = 0;
+ priv->wstats.discard.retries = 0;
+ priv->wstats.qual.level = priv->curbssparams.rssi > 127? priv->curbssparams.rssi - 271
+ :priv->curbssparams.rssi - 15;
+
+ snr = priv->wstats.qual.level - RDA5890_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 = RDA5890_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;
+ }
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s <<<\n", __func__);
+ return &priv->wstats;
+}
+
+static int rda5890_set_freq(struct net_device *dev, struct iw_request_info *info,
+ struct iw_freq *fwrq, char *extra)
+{
+ //struct rda5890_private *priv = (struct rda5890_private *)netdev_priv(dev);
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s >>>\n", __func__);
+
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s <<<\n", __func__);
+ return 0;
+}
+
+static int rda5890_set_rate(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ //struct rda5890_private *priv = (struct rda5890_private *)netdev_priv(dev);
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s >>>\n", __func__);
+
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s <<<\n", __func__);
+ return 0;
+}
+
+static int rda5890_get_rate(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ //struct rda5890_private *priv = (struct rda5890_private *)netdev_priv(dev);
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s >>>\n", __func__);
+
+ vwrq->fixed = 0;
+ vwrq->value = 108*500000;
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s <<<\n", __func__);
+ return 0;
+}
+
+static int rda5890_set_mode(struct net_device *dev,
+ struct iw_request_info *info, u32 * uwrq, char *extra)
+{
+ //struct rda5890_private *priv = (struct rda5890_private *)netdev_priv(dev);
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s >>>\n", __func__);
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_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 rda5890_get_encode(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq, u8 * extra)
+{
+ //struct rda5890_private *priv = (struct rda5890_private *)netdev_priv(dev);
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s >>>\n", __func__);
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_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 rda5890_set_encode(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ //struct rda5890_private *priv = (struct rda5890_private *)netdev_priv(dev);
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s >>>\n", __func__);
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_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(struct rda5890_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) {
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_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) {
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_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 {
+ RDA5890_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) {
+ RDA5890_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(struct rda5890_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;
+
+ set_bit(ASSOC_FLAG_SECINFO, &priv->assoc_flags);
+ set_bit(ASSOC_FLAG_WEP_KEYS, &priv->assoc_flags);
+}
+
+static void disable_wpa(struct rda5890_private *priv)
+{
+ memset(&priv->wpa_mcast_key, 0, sizeof (struct enc_key));
+ priv->wpa_mcast_key.flags = KEY_INFO_WPA_MCAST;
+ set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &priv->assoc_flags);
+
+ memset(&priv->wpa_unicast_key, 0, sizeof (struct enc_key));
+ priv->wpa_unicast_key.flags = KEY_INFO_WPA_UNICAST;
+ set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &priv->assoc_flags);
+
+ priv->secinfo.WPAenabled = 0;
+ priv->secinfo.WPA2enabled = 0;
+ priv->secinfo.cipther_type = 0;
+ priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
+ set_bit(ASSOC_FLAG_SECINFO, &priv->assoc_flags);
+}
+
+/**
+ * @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 rda5890_get_encodeext(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq,
+ char *extra)
+{
+ struct rda5890_private *priv = (struct rda5890_private *)netdev_priv(dev);
+ int ret = -EINVAL;
+ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+ int index, max_key_len;
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_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:
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_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 rda5890_set_encodeext(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq,
+ char *extra)
+{
+ struct rda5890_private *priv = (struct rda5890_private *)netdev_priv(dev);
+ int ret = 0;
+ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+ int alg = ext->alg;
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s >>>\n", __func__);
+
+ if ((alg == IW_ENCODE_ALG_NONE) || (dwrq->flags & IW_ENCODE_DISABLED)) {
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE,
+ "NO SEC\n");
+ if(test_bit(ASSOC_FLAG_ASSOC_START ,&priv->assoc_flags))
+ {
+ 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;
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_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;
+
+ /* Set Key to Mac */
+ /* Move to assoc_helper_secinfo(), wep_key need to be set after imode */
+ //ret = rda5890_set_wepkey(priv, index, ext->key, ext->key_len);
+ //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;
+ }
+
+ /* Mark the various WEP bits as modified */
+ set_bit(ASSOC_FLAG_SECINFO, &priv->assoc_flags);
+ if (dwrq->length)
+ set_bit(ASSOC_FLAG_WEP_KEYS, &priv->assoc_flags);
+ if (set_tx_key)
+ set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &priv->assoc_flags);
+ } else if ((alg == IW_ENCODE_ALG_TKIP) || (alg == IW_ENCODE_ALG_CCMP)) {
+ struct enc_key * pkey;
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_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))) {
+ RDA5890_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;
+ set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &priv->assoc_flags);
+ } else {
+ pkey = &priv->wpa_unicast_key;
+ set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &priv->assoc_flags);
+ }
+
+ 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))) {
+ RDA5890_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))) {
+ RDA5890_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_bit(ASSOC_FLAG_SECINFO, &priv->assoc_flags);
+ }
+
+ /* Set Keys to MAC*/
+ if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
+ /* Set GTK */
+ /*
+ *Always use key_id = 1 for now
+ * need to toggle among 1, 2, 3
+ */
+ ret = rda5890_set_gtk(priv, 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 = rda5890_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_WAPI) { //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 */
+ /*
+ * Always use key_id = 1 for now
+ * need to toggle among 1, 2, 3
+ */
+ ret = rda5890_set_gtk(priv, 1, tmp, IW_ENCODE_SEQ_MAX_SIZE,
+ ext->key, ext->key_len);
+ if (ret)
+ goto out;
+ } else {
+ /* Set PTK */
+ ret = rda5890_set_ptk(priv, ext->key, ext->key_len);
+ if (ret)
+ goto out;
+ }
+ }
+
+out:
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_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 rda5890_set_pmksa(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq,
+ char *extra)
+{
+ //struct rda5890_private *priv = (struct rda5890_private *)netdev_priv(dev);
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s >>>\n", __func__);
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s <<<\n", __func__);
+ return 0;
+}
+
+static int rda5890_set_genie(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq,
+ char *extra)
+{
+ struct rda5890_private *priv = (struct rda5890_private *)netdev_priv(dev);
+ int ret = 0;
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s >>>\n", __func__);
+
+ if(extra[0] == 0x44) //wapi ie
+ {
+ unsigned char ie_len = extra[1] + 2;
+ rda5890_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:
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s <<<\n", __func__);
+ return ret;
+}
+
+static int rda5890_get_genie(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq,
+ char *extra)
+{
+ struct rda5890_private *priv = (struct rda5890_private *)netdev_priv(dev);
+ int ret = 0;
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_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:
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s <<<\n", __func__);
+ return ret;
+}
+
+static int rda5890_set_auth(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *dwrq,
+ char *extra)
+{
+ struct rda5890_private *priv = (struct rda5890_private *)netdev_priv(dev);
+ int ret = 0;
+ int updated = 0;
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s >>>\n", __func__);
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE,
+ "flags = 0x%04x, value = 0x%x\n", dwrq->flags, dwrq->value);
+
+ switch (dwrq->flags & IW_AUTH_INDEX) {
+ case IW_AUTH_CIPHER_PAIRWISE:
+#ifdef GET_SCAN_FROM_NETWORK_INFO
+ if (dwrq->value & (IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_WEP40))
+ {
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_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) {
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE,
+ "IW_AUTH_CIPHER_TKIP \n");
+ priv->secinfo.cipther_type |= IW_AUTH_CIPHER_TKIP;
+ }
+ if (dwrq->value & IW_AUTH_CIPHER_CCMP) {
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE,
+ "IW_AUTH_CIPHER_CCMP \n");
+ priv->secinfo.cipther_type |= IW_AUTH_CIPHER_CCMP;
+ }
+ if (dwrq->value & IW_AUTH_CIPHER_NONE) {
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE,
+ "OPEN System \n");
+ priv->secinfo.cipther_type = IW_AUTH_CIPHER_NONE;
+ }
+ break;
+#endif
+ case IW_AUTH_TKIP_COUNTERMEASURES:
+ case IW_AUTH_CIPHER_GROUP:
+ case IW_AUTH_DROP_UNENCRYPTED:
+ /*
+ * rda5890 does not use these parameters
+ */
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE,
+ "DO NOT USE\n");
+ break;
+
+ case IW_AUTH_KEY_MGMT:
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE,
+ "KEY_MGMT, val = %d\n", dwrq->value);
+ priv->secinfo.key_mgmt = dwrq->value;
+ updated = 1;
+ break;
+
+ case IW_AUTH_WPA_VERSION:
+ if (dwrq->value & IW_AUTH_WPA_VERSION_DISABLED) {
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_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) {
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_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) {
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE,
+ "WPA_VERSION, WPA2\n");
+ priv->secinfo.WPA2enabled = 1;
+ priv->secinfo.wep_enabled = 0;
+ priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
+ }
+ updated = 1;
+ 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 )
+ {
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_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) {
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE,
+ "80211_AUTH_ALG, OPEN\n");
+ priv->secinfo.auth_mode |= IW_AUTH_ALG_OPEN_SYSTEM;
+ }
+ }
+ else if(dwrq->value & IW_AUTH_ALG_LEAP) {
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_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{
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE,
+ "80211_AUTH_ALG, unknown\n");
+ ret = -EINVAL;
+ }
+ updated = 1;
+ break;
+
+ case IW_AUTH_WPA_ENABLED:
+ if (dwrq->value) {
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_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 {
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE,
+ "WPA_ENABLED, value = ZERO\n");
+ priv->secinfo.WPAenabled = 0;
+ priv->secinfo.WPA2enabled = 0;
+ disable_wpa (priv);
+ }
+ updated = 1;
+ break;
+
+ default:
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE,
+ "NOT SUPPORT\n");
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ if (ret == 0) {
+ if (updated) {
+ set_bit(ASSOC_FLAG_SECINFO, &priv->assoc_flags);
+ }
+ }
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s <<<\n", __func__);
+ return ret;
+}
+
+static int rda5890_get_auth(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *dwrq,
+ char *extra)
+{
+ struct rda5890_private *priv = (struct rda5890_private *)netdev_priv(dev);
+ int ret = 0;
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_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;
+ }
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s >>>\n", __func__);
+ return ret;
+}
+
+static int rda5890_set_txpow(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ //struct rda5890_private *priv = (struct rda5890_private *)netdev_priv(dev);
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s <<<\n", __func__);
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s >>>\n", __func__);
+ return 0;
+}
+
+static int rda5890_get_essid(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ struct rda5890_private *priv = (struct rda5890_private *)netdev_priv(dev);
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_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 */
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s >>> \n", __func__);
+ return 0;
+}
+
+void rda5890_indicate_disconnected(struct rda5890_private *priv)
+{
+ union iwreq_data wrqu;
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_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->dev, SIOCGIWAP, &wrqu, NULL);
+
+ /*report disconnect to upper layer*/
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_NORM, "%s >>>\n", __func__);
+}
+
+void rda5890_indicate_connected(struct rda5890_private *priv)
+{
+ union iwreq_data wrqu;
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_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->dev, SIOCGIWAP, &wrqu, NULL);
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_NORM, "%s >>>\n", __func__);
+}
+
+void rda5890_assoc_done_worker(struct work_struct *work)
+{
+ u8 bssid[6], zero_bssid[6];
+ struct rda5890_private *priv = container_of(work, struct rda5890_private,
+ assoc_done_work.work);
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s <<< \n", __func__);
+
+ memset(bssid, 0, sizeof(bssid));
+ memset(zero_bssid, 0, sizeof(zero_bssid));
+ rda5890_get_bssid(priv, bssid);
+
+ if(memcmp(bssid, zero_bssid, sizeof(zero_bssid)))
+ {
+ memcpy(priv->curbssparams.bssid, bssid, sizeof(bssid));
+ }
+
+ rda5890_get_rssi(priv, &priv->curbssparams.rssi);
+ priv->curbssparams.rssi = priv->curbssparams.rssi > 127?
+ priv->curbssparams.rssi - 271: priv->curbssparams.rssi - 15;
+
+ rda5990_assoc_power_save(priv);
+ clear_bit(ASSOC_FLAG_ASSOC_START, &priv->assoc_flags);
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s >>>\n", __func__);
+}
+
+void rda5890_wlan_connect_worker(struct work_struct *work)
+{
+ struct rda5890_private *priv = container_of(work, struct rda5890_private,
+ wlan_connect_work.work);
+
+ rda5890_set_txrate(priv, 0);
+
+ if(priv)
+ clear_bit(ASSOC_FLAG_WLAN_CONNECTING ,&priv->assoc_flags);
+}
+
+//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 -> WPA RSN 802.1x*/
+/* BIT7: 1 -> WAPI */
+static int assoc_helper_secinfo(struct rda5890_private *priv,
+ struct bss_descriptor *assoc_bss)
+{
+ int ret = 0;
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s <<<\n", __func__);
+
+ /* set imode and key */
+ if ( !priv->secinfo.wep_enabled
+ && !priv->secinfo.WPAenabled
+ && !priv->secinfo.WPA2enabled) {
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE,
+ "%s, NO SEC\n", __func__);
+ priv->imode = 0;
+ } else {
+ u16 key_len = 0;
+ u16 i;
+ if ( priv->secinfo.wep_enabled
+ && !priv->secinfo.WPAenabled
+ && !priv->secinfo.WPA2enabled) {
+ /* WEP */
+ key_len = priv->wep_keys[0].len;
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_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 {
+ RDA5890_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;
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE,
+ "%s, WPA cp:%x \n", __func__, priv->secinfo.cipther_type);
+
+ 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 = assoc_bss->data.dot11i_info;
+ 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);
+#ifdef GET_SCAN_FROM_NETWORK_INFO
+ 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
+ if (assoc_bss->data.dot11i_info & (BIT5))
+ priv->imode |= BIT5;
+ else if (assoc_bss->data.dot11i_info & (BIT6))
+ priv->imode |= BIT6;
+#endif
+ } else {
+ RDA5890_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)
+ {
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_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) {
+ /* for 802.1x, set auth type to 0x04 */
+ priv->authtype = BIT3;
+ }
+ else
+ {
+ priv->authtype = BIT0;
+ }
+ }
+ else if(priv->secinfo.auth_mode & IW_AUTH_ALG_SHARED_KEY)
+ {
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE,
+ "%s, Shared-Key Auth AUTH_ALG mode:%x \n", __func__, priv->secinfo.auth_mode);
+ priv->authtype = BIT1;
+ }
+ }
+ else if (priv->secinfo.auth_mode == IW_AUTH_ALG_WAPI) {
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE,
+ "%s, Shared-Key Auth\n", __func__);
+ priv->authtype = IW_AUTH_ALG_WAPI;
+ }
+ else if (priv->secinfo.auth_mode == IW_AUTH_ALG_LEAP) {
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE,
+ "%s, LEAP Auth, not supported\n", __func__);
+ ret = -EINVAL;
+ goto out;
+ }
+ else {
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE,
+ "%s, Unknown Auth\n", __func__);
+ ret = -EINVAL;
+ goto out;
+ }
+
+out:
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s >>> \n", __func__);
+ return ret;
+}
+
+static struct bss_descriptor *get_bss_desc_from_scanlist(
+ struct rda5890_private *priv, unsigned char *ssid)
+{
+ struct bss_descriptor *iter_bss;
+ struct bss_descriptor *ret_bss = NULL;
+ /* report all bss to upper layer */
+ list_for_each_entry (iter_bss, &priv->network_list, list) {
+#ifdef GET_SCAN_FROM_NETWORK_INFO
+ if (strcmp(iter_bss->ssid, ssid) == 0) {
+#else
+ if (strcmp(iter_bss->data.ssid, ssid) == 0) {
+#endif
+ ret_bss = iter_bss;
+ break;
+ }
+ }
+ return ret_bss;
+}
+
+void rda5890_assoc_worker(struct work_struct *work)
+{
+ static char old_imode = 0xff, old_bssid[6], assoc_count = 0;
+ struct rda5890_private *priv = container_of(work, struct rda5890_private,
+ assoc_work.work);
+ int ret = 0;
+ struct bss_descriptor *assoc_bss;
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s >>>\n", __func__);
+
+ assoc_bss = get_bss_desc_from_scanlist(priv, priv->assoc_ssid);
+ if (assoc_bss == NULL) {
+ RDA5890_ERRP("****fail to find bss in the scan list\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+#ifdef GET_SCAN_FROM_NETWORK_INFO
+ if(assoc_bss->rssi > 200)
+ {
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "assoc_bss rssi =%d > 200\n", assoc_bss->rssi);
+ rda5890_rssi_up_to_200(priv);
+ }
+#else
+ if(assoc_bss->data.rssi > 200)
+ {
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "assoc_bss rssi =%d > 200\n", assoc_bss->data.rssi);
+ rda5890_rssi_up_to_200(priv);
+ }
+#endif
+#ifdef GET_SCAN_FROM_NETWORK_INFO
+ 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);
+#else
+ priv->curbssparams.channel = assoc_bss->data.channel;
+ memcpy(priv->curbssparams.bssid, assoc_bss->data.bssid, ETH_ALEN);
+ memcpy(priv->curbssparams.ssid, assoc_bss->data.ssid,IW_ESSID_MAX_SIZE + 1);
+#endif
+ ret = assoc_helper_secinfo(priv, assoc_bss);
+ if (ret) {
+ RDA5890_ERRP("assoc_helper_secinfo fail, ret = %d\n", ret);
+ goto out;
+ }
+
+ //if the bssid is same and the association is start then break out
+ if((old_imode == priv->imode) && !memcmp(old_bssid, priv->assoc_bssid,6))
+ {
+ //WEP THE Second retry should change to shared key
+ if((old_imode == 3 || old_imode == 5) && assoc_count%2)
+ {
+ priv->authtype = BIT1;
+ }
+ assoc_count ++;
+ }
+ else
+ {
+ //save old bssid para
+ old_imode = priv->imode;
+ memcpy(old_bssid, priv->assoc_bssid, 6);
+ assoc_count = 0;
+ }
+
+ set_bit(ASSOC_FLAG_ASSOC_START ,&priv->assoc_flags);
+ set_bit(ASSOC_FLAG_ASSOC_RETRY, &priv->assoc_flags);
+
+ if((priv->imode == 3) || (priv->imode ==5))
+ {
+ if(assoc_count > 5)
+ {
+ clear_bit(ASSOC_FLAG_ASSOC_RETRY, &priv->assoc_flags);
+ clear_bit(ASSOC_FLAG_ASSOC_START ,&priv->assoc_flags);
+ old_imode = 0xff;
+ }
+ }
+ else
+ {
+ if(assoc_count)
+ {
+ clear_bit(ASSOC_FLAG_ASSOC_RETRY, &priv->assoc_flags);
+ clear_bit(ASSOC_FLAG_ASSOC_START ,&priv->assoc_flags);
+ old_imode = 0xff;
+ }
+ }
+
+ ret = rda5890_start_join(priv);
+ if (ret) {
+ RDA5890_ERRP("rda5890_set_ssid fail, ret = %d\n", ret);
+ goto out;
+ }
+
+ if(test_bit(ASSOC_FLAG_ASSOC_RETRY, &priv->assoc_flags))
+ {
+ queue_delayed_work(priv->work_thread, &priv->assoc_work, 3*HZ);
+ }
+
+out:
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s <<< \n", __func__);
+}
+
+static int rda5890_set_essid(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ struct rda5890_private *priv = (struct rda5890_private *)netdev_priv(dev);
+ int ret = 0;
+ u8 ssid[IW_ESSID_MAX_SIZE + 1];
+ u8 ssid_len = 0;
+ int in_ssid_len = dwrq->length;
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_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) {
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE,
+ "requested any SSID\n");
+ } else {
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_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(!test_bit(ASSOC_FLAG_SSID, &priv->assoc_flags))
+ goto out;
+
+ if(!test_bit(ASSOC_FLAG_ASSOC_RETRY, &priv->assoc_flags))
+ {
+ if(ssid_len)
+ {
+ cancel_delayed_work(&priv->assoc_work);
+ queue_delayed_work(priv->work_thread, &priv->assoc_work, HZ/2);
+ }
+ }
+
+out:
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_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 rda5890_set_wap(struct net_device *dev, struct iw_request_info *info,
+ struct sockaddr *awrq, char *extra)
+{
+ unsigned char * ap_addr = NULL;
+ struct rda5890_private *priv = (struct rda5890_private *)netdev_priv(dev);
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s >>>\n", __func__);
+
+ ap_addr = awrq->sa_data;
+ if(!test_bit(ASSOC_FLAG_ASSOC_RETRY, &priv->assoc_flags)
+ && !is_zero_eth_addr(ap_addr))
+ {
+ cancel_delayed_work(&priv->assoc_work);
+ queue_delayed_work(priv->work_thread, &priv->assoc_work, HZ/2);
+ set_bit(ASSOC_FLAG_SSID, &priv->assoc_flags);
+ memcpy(priv->assoc_bssid, ap_addr, 6);
+ printk("rda5890_set_wap addr is not null \n");
+ }
+
+ if(is_zero_eth_addr(ap_addr))
+ {
+ clear_bit(ASSOC_FLAG_SSID, &priv->assoc_flags);
+ disable_wep( priv);
+ disable_wpa(priv);
+ }
+
+
+ RDA5890_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;
+}
+
+static inline char *translate_scan(struct rda5890_private *priv,
+ struct iw_request_info *info,
+ char *start, char *stop,
+ struct bss_descriptor *bss_desc)
+{
+#ifndef GET_SCAN_FROM_NETWORK_INFO
+ struct iw_event iwe; /* Temporary buffer */
+ u8 snr;
+ struct rda5890_bss_descriptor *bss = &bss_desc->data;
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE,
+ "translate_scan, ssid = %s\n", bss->ssid);
+
+ /* 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 = strlen(bss->ssid);
+ start = iwe_stream_add_point(info, start, stop, &iwe, bss->ssid);
+
+ /* Mode */
+ iwe.cmd = SIOCGIWMODE;
+ //iwe.u.mode = bss->mode;
+ iwe.u.mode = IW_MODE_INFRA;
+ 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 = bss->rssi > 127? bss->rssi - 271: bss->rssi - 15;
+
+ snr = iwe.u.qual.level - RDA5890_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 = RDA5890_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->dot11i_info & BIT0) {
+ 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);
+
+#if 0
+ current_val = start + iwe_stream_lcp_len(info);
+
+ iwe.cmd = SIOCGIWRATE;
+ iwe.u.bitrate.fixed = 0;
+ iwe.u.bitrate.disabled = 0;
+ iwe.u.bitrate.value = 0;
+
+ for (j = 0; bss->rates[j] && (j < sizeof(bss->rates)); j++) {
+ /* Bit rate given in 500 kb/s units */
+ iwe.u.bitrate.value = bss->rates[j] * 500000;
+ current_val = iwe_stream_add_value(info, start, current_val,
+ stop, &iwe, IW_EV_PARAM_LEN);
+ }
+ if ((bss->mode == IW_MODE_ADHOC) && priv->adhoccreate
+ && !lbs_ssid_cmp(priv->curbssparams.ssid,
+ priv->curbssparams.ssid_len,
+ bss->ssid, bss->ssid_len)) {
+ iwe.u.bitrate.value = 22 * 500000;
+ current_val = iwe_stream_add_value(info, start, current_val,
+ stop, &iwe, IW_EV_PARAM_LEN);
+ }
+ /* Check if we added any event */
+ if ((current_val - start) > iwe_stream_lcp_len(info))
+ start = current_val;
+#endif
+
+ memset(&iwe, 0, sizeof(iwe));
+ if (bss_desc->wpa_ie_len) {
+ char buf[MAX_WPA_IE_LEN];
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE,
+ "translate_scan, wpa_ie, len %d\n", bss_desc->wpa_ie_len);
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_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_desc->wpa_ie, bss_desc->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];
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE,
+ "translate_scan, rsn_ie, len %d\n", bss_desc->rsn_ie_len);
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_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_desc->rsn_ie, bss_desc->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);
+ }
+
+ return start;
+#else
+ struct iw_event iwe; /* Temporary buffer */
+ u8 snr;
+ struct bss_descriptor *bss = bss_desc;
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_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 = bss->rssi > 127? bss->rssi - 271: bss->rssi - 15;
+
+ snr = iwe.u.qual.level - RDA5890_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 = RDA5890_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];
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE,
+ "translate_scan, wpa_ie, len %d\n", bss_desc->wpa_ie_len);
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_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 && !bss_desc->wapi_ie_len) {
+ char buf[MAX_WPA_IE_LEN];
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE,
+ "translate_scan, rsn_ie, len %d\n", bss_desc->rsn_ie_len);
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_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);
+ }
+
+ memset(&iwe, 0, sizeof(iwe));
+ if (bss_desc->wapi_ie_len) {
+ char buf[100];
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE,
+ "translate_scan, wapi_len %d\n", bss_desc->wapi_ie_len);
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_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, bss->wapi_ie, bss->wapi_ie_len);
+ iwe.cmd = IWEVGENIE;
+ iwe.u.data.length = bss_desc->wapi_ie_len;
+ start = iwe_stream_add_point(info, start, stop, &iwe, buf);
+ }
+
+ return start;
+#endif
+}
+
+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 <hidden> with the same BSSID and channel
+ * as one network */
+#ifndef GET_SCAN_FROM_NETWORK_INFO
+ return ((src->data.channel == dst->data.channel) &&
+ !compare_ether_addr(src->data.bssid, dst->data.bssid) &&
+ !memcmp(src->data.ssid, dst->data.ssid, IW_ESSID_MAX_SIZE));
+#else
+ return ((src->channel == dst->channel) &&
+ !compare_ether_addr(src->bssid, dst->bssid) &&
+ !memcmp(src->ssid, dst->ssid, IW_ESSID_MAX_SIZE));
+#endif
+}
+
+void clear_bss_descriptor(struct bss_descriptor *bss)
+{
+ /* Don't blow away ->list, just BSS data */
+ memset(bss, 0, offsetof(struct bss_descriptor, list));
+}
+
+static void dump_bss_desc(struct rda5890_bss_descriptor *bss_desc)
+{
+ RDA5890_DBGP("########## dump bss ##########\n");
+ RDA5890_DBGP("ssid = %s\n", bss_desc->ssid);
+ RDA5890_DBGP("bss_type = %d\n", bss_desc->bss_type);
+ RDA5890_DBGP("channel = %d\n", bss_desc->channel);
+ RDA5890_DBGP("dot11i_info = 0x%02x\n", bss_desc->dot11i_info);
+ RDA5890_DBGP("bssid = %02x:%02x:%02x:%02x:%02x:%02x\n",
+ bss_desc->bssid[0], bss_desc->bssid[1], bss_desc->bssid[2],
+ bss_desc->bssid[3], bss_desc->bssid[4], bss_desc->bssid[5]);
+ RDA5890_DBGP("rssi = %d\n", (char)bss_desc->rssi);
+ RDA5890_DBGP("auth_info = 0x%02x\n", bss_desc->auth_info);
+ RDA5890_DBGP("rsn_cap = 0x%04x\n",
+ (bss_desc->rsn_cap[1] << 8) | bss_desc->rsn_cap[0]);
+ RDA5890_DBGP("########## dump bss ##########\n");
+}
+
+/* Element Ids used in Management frames in 802.11i mode */
+typedef enum{ IRSNELEMENT = 48, /* RSN Information Element */
+ IWPAELEMENT = 221 /* WPA Information Element */
+}ELEMENTID_11I_T;
+
+/* CIPHER set for RSN or WPA element */
+typedef enum { CIPHER_TYPE_USE_GROUP_SET = 0,
+ CIPHER_TYPE_WEP40 = 1,
+ CIPHER_TYPE_TKIP = 2,
+ CIPHER_TYPE_CCMP = 4,
+ CIPHER_TYPE_WEP104 = 5
+} CIPHER_TYPE_T;
+
+unsigned char oui_rsn[3] = {0x00, 0x0F, 0xAC};
+unsigned char oui_wpa[3] = {0x00, 0x50, 0xf2};
+
+static void fill_rsn_wpa_ie(unsigned char *data, unsigned char ie_type,
+ struct rda5890_bss_descriptor *bss, size_t *len)
+{
+ unsigned char index = 0;
+ unsigned char *oui;
+
+ if (ie_type == IRSNELEMENT) {
+ oui = &oui_rsn[0];
+
+ /* Set RSN Information Element element ID */
+ data[index] = IRSNELEMENT;
+ index += 2;
+ }
+ else {
+ oui = &oui_wpa[0];
+
+ /* Set WPA Information Element element ID */
+ data[index] = IWPAELEMENT;
+ index += 2;
+
+ /* Copy OUI */
+ memcpy(&data[index], oui, 3);
+ index += 3;
+ data[index++] = 0x01;
+ }
+
+ /* Set the version of RSN Element to 1 */
+ data[index++] = 1;
+ data[index++] = 0;
+
+ /* Set Group Cipher Suite */
+ memcpy(&data[index], oui, 3);
+ index += 3;
+ if ((bss->dot11i_info & BIT5) && !(bss->dot11i_info & BIT6)) {
+ /* only CCMP and !TKIP, use CCMP, otherwise, always TKIP */
+ data[index++] = CIPHER_TYPE_CCMP;
+ }
+ else {
+ data[index++] = CIPHER_TYPE_TKIP;
+ }
+
+ /* Set Pairwise cipher Suite */
+ if ((bss->dot11i_info & BIT5) && (bss->dot11i_info & BIT6)) {
+ /* both CCMP and TKIP */
+ data[index++] = 2;
+ data[index++] = 0;
+
+ /* Check BIT7 to determine who goes first */
+ if (bss->dot11i_info & BIT7) {
+ /* BIT7 is 1 => CCMP goes first */
+ memcpy(&data[index], oui, 3);
+ index += 3;
+ data[index++] = CIPHER_TYPE_CCMP;
+
+ memcpy(&data[index], oui, 3);
+ index += 3;
+ data[index++] = CIPHER_TYPE_TKIP;
+ }
+ else {
+ /* BIT7 is 0 => TKIP goes first */
+ memcpy(&data[index], oui, 3);
+ index += 3;
+ data[index++] = CIPHER_TYPE_TKIP;
+
+ memcpy(&data[index], oui, 3);
+ index += 3;
+ data[index++] = CIPHER_TYPE_CCMP;
+ }
+ }
+ else if ((bss->dot11i_info & BIT5) && !(bss->dot11i_info & BIT6)) {
+ /* CCMP and !TKIP */
+ data[index++] = 1;
+ data[index++] = 0;
+
+ memcpy(&data[index], oui, 3);
+ index += 3;
+ data[index++] = CIPHER_TYPE_CCMP;
+ }
+ else if (!(bss->dot11i_info & BIT5) && (bss->dot11i_info & BIT6)) {
+ /* !CCMP and TKIP */
+ data[index++] = 1;
+ data[index++] = 0;
+
+ memcpy(&data[index], oui, 3);
+ index += 3;
+ data[index++] = CIPHER_TYPE_TKIP;
+ }
+ else {
+ /* neither CCMP nor TKIP, use TKIP for WPA, and CCMP for RSN */
+ data[index++] = 1;
+ data[index++] = 0;
+
+ memcpy(&data[index], oui, 3);
+ index += 3;
+ if (ie_type == IRSNELEMENT) {
+ data[index++] = CIPHER_TYPE_CCMP;
+ }
+ else {
+ data[index++] = CIPHER_TYPE_TKIP;
+ }
+ }
+
+ /* Set Authentication Suite */
+ if ((bss->auth_info & 0x01) && (bss->auth_info & 0x02)) {
+ /* both 802.1X and PSK */
+ data[index++] = 2;
+ data[index++] = 0;
+
+ memcpy(&data[index], oui, 3);
+ index += 3;
+ data[index++] = 0x01;
+
+ memcpy(&data[index], oui, 3);
+ index += 3;
+ data[index++] = 0x02;
+ }
+ else if ((bss->auth_info & 0x01) && !(bss->auth_info & 0x02)) {
+ /* 802.1X and !PSK */
+ data[index++] = 1;
+ data[index++] = 0;
+
+ memcpy(&data[index], oui, 3);
+ index += 3;
+ data[index++] = 0x01;
+ }
+ else if (!(bss->auth_info & 0x01) && (bss->auth_info & 0x02)) {
+ /* !802.1X and PSK */
+ data[index++] = 1;
+ data[index++] = 0;
+
+ memcpy(&data[index], oui, 3);
+ index += 3;
+ data[index++] = 0x02;
+ }
+ else {
+ /* neither 802.1X nor PSK, use 802.1X */
+ data[index++] = 1;
+ data[index++] = 0;
+
+ memcpy(&data[index], oui, 3);
+ index += 3;
+ data[index++] = 0x01;
+ }
+
+ /* The RSN Capabilities, for RSN IE only */
+ if (ie_type == IRSNELEMENT) {
+ data[index++] = bss->rsn_cap[0];
+ data[index++] = bss->rsn_cap[1];
+ }
+
+ /* Set the length of the RSN Information Element */
+ data[1] = (index - 2);
+
+ /* Return the Extended Supported Rates element length */
+ *len = (size_t)index;
+}
+
+/* reconstruct wpa/rsn ie from the dot11i_info and auth_info fields */
+/* TODO:
+ * assuming RSN and WPA are using same cipher suite, no space to store each
+ * assuming grp and unicast are using same cipher suite
+ */
+static void reconstruct_rsn_wpa_ie(struct bss_descriptor *bss_desc)
+{
+ bss_desc->wpa_ie_len = 0;
+ bss_desc->rsn_ie_len = 0;
+
+ if (bss_desc->data.dot11i_info & BIT0) {
+ if (bss_desc->data.dot11i_info & BIT3) {
+ /* WPA IE present */
+ fill_rsn_wpa_ie(&bss_desc->wpa_ie[0], IWPAELEMENT,
+ &bss_desc->data, &bss_desc->wpa_ie_len);
+ }
+
+ if (bss_desc->data.dot11i_info & BIT4) {
+ /* RSN IE present */
+ fill_rsn_wpa_ie(&bss_desc->rsn_ie[0], IRSNELEMENT,
+ &bss_desc->data, &bss_desc->rsn_ie_len);
+ }
+ }
+ else {
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE,
+ "form_rsn_ie, NO SEC\n");
+ }
+}
+
+void rda5890_scan_worker(struct work_struct *work)
+{
+ struct rda5890_private *priv = container_of(work, struct rda5890_private,
+ scan_work.work);
+ int ret = 0;
+ struct rda5890_bss_descriptor bss_desc[RDA5890_MAX_NETWORK_NUM];
+ int bss_index, bss_count;
+ struct bss_descriptor *iter_bss;
+ union iwreq_data wrqu;
+ unsigned char fist_send = 0;
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s >>>\n", __func__);
+
+ if(test_bit(ASSOC_FLAG_ASSOC_START, &priv->assoc_flags)
+ || test_bit(ASSOC_FLAG_WLAN_CONNECTING, &priv->assoc_flags))
+ {
+ cancel_delayed_work(&priv->scan_work);
+ queue_delayed_work(priv->work_thread, &priv->scan_work, HZ/2);
+ return;
+ }
+
+ priv->scan_running = 1;
+
+#ifdef WIFI_UNLOCK_SYSTEM
+ rda5990_wakeLock();
+#endif
+
+#ifdef GET_SCAN_FROM_NETWORK_INFO
+ ret = rda5890_start_scan_enable_network_info(priv);
+#else
+ ret = rda5890_start_scan(priv);
+#endif
+ if (ret) {
+ RDA5890_ERRP("rda5890_start_scan fail, ret = %d\n", ret);
+ goto out;
+ }
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "SCANNING ...\n");
+ /* TODO: delay 2 sec for now, need to be put into a worker */
+ rda5890_shedule_timeout(1500);
+
+#ifndef GET_SCAN_FROM_NETWORK_INFO
+retry:
+ bss_count = rda5890_get_scan_results(priv, bss_desc);
+
+ fist_send = (bss_count >> 8) & 0xff;
+ bss_count &= 0xff;
+ if (bss_count < 0 || bss_count >= RDA5890_MAX_NETWORK_NUM) {
+ RDA5890_ERRP("rda5890_get_scan_results fail, ret = %d\n", bss_count);
+ goto out;
+ }
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_TRACE,
+ "Get Scan Result, count = %d, fist_send= %d \n", bss_count, fist_send);
+
+ /* add scaned bss into list */
+ for(bss_index = 0; bss_index < bss_count; bss_index++) {
+ struct bss_descriptor new;
+ struct bss_descriptor *found = NULL;
+ struct bss_descriptor *oldest = NULL;
+
+ if (RDA5890_DBGLA(RDA5890_DA_WEXT, RDA5890_DL_TRACE))
+ dump_bss_desc(&bss_desc[bss_index]);
+
+ memcpy(&new.data, &bss_desc[bss_index], sizeof(struct rda5890_bss_descriptor));
+ reconstruct_rsn_wpa_ie(&new);
+ new.last_scanned = jiffies;
+
+ /* 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, &new)) {
+ found = iter_bss;
+ break;
+ }
+
+ if ((oldest == NULL) ||
+ (iter_bss->last_scanned < oldest->last_scanned))
+ oldest = iter_bss;
+ }
+
+ if (found) {
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE,
+ "FOUND SAME %s, update\n", found->data.ssid);
+ /* found, clear it */
+ clear_bss_descriptor(found);
+ } else if (!list_empty(&priv->network_free_list)) {
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE,
+ "FOUND NEW %s, add\n", new.data.ssid);
+ /* Pull one from the free list */
+ found = list_entry(priv->network_free_list.next,
+ struct bss_descriptor, list);
+ list_move_tail(&found->list, &priv->network_list);
+ } else if (oldest) {
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE,
+ "FOUND NEW %s, no space, replace oldest %s\n",
+ new.data.ssid, oldest->data.ssid);
+ /* If there are no more slots, expire the oldest */
+ found = oldest;
+ clear_bss_descriptor(found);
+ list_move_tail(&found->list, &priv->network_list);
+ } else {
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE,
+ "FOUND NEW but no space to store\n");
+ }
+
+ /* Copy the locally created newbssentry to the scan table */
+ memcpy(found, &new, offsetof(struct bss_descriptor, list));
+ }
+
+ if(bss_count >= 5 && !fist_send)
+ goto retry;
+
+#else
+ //do noting in get network info modle
+
+#endif
+
+out:
+ priv->scan_running = 0;
+ memset(&wrqu, 0, sizeof(union iwreq_data));
+ wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s <<<\n", __func__);
+
+#ifdef WIFI_UNLOCK_SYSTEM
+ rda5990_wakeUnlock();
+#endif
+}
+
+/**
+ * @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 rda5890_set_scan(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct rda5890_private *priv = (struct rda5890_private *)netdev_priv(dev);
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s >>>\n", __func__);
+
+ if (priv->scan_running)
+ goto out;
+
+
+ cancel_delayed_work(&priv->scan_work);
+ queue_delayed_work(priv->work_thread, &priv->scan_work, HZ/50);
+
+out:
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s <<<\n", __func__);
+ return 0;
+}
+
+/**
+ * @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 rda5890_get_scan(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+#define SCAN_ITEM_SIZE 128
+ struct rda5890_private *priv = (struct rda5890_private *)netdev_priv(dev);
+ int ret = 0;
+ struct bss_descriptor *iter_bss;
+ struct bss_descriptor *safe;
+ char *ev = extra;
+ char *stop = ev + dwrq->length;
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s >>>\n", __func__);
+
+ /* iwlist should wait until the current scan is finished */
+ if (priv->scan_running) {
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE,
+ "Scan is Running, return AGAIN\n");
+ return -EAGAIN;
+ }
+
+ /* 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;
+ }
+
+ /* Prune old an old scan result */
+ stale_time = iter_bss->last_scanned + DEFAULT_MAX_SCAN_AGE;
+ if (time_after(jiffies, stale_time)) {
+ list_move_tail(&iter_bss->list, &priv->network_free_list);
+#ifdef GET_SCAN_FROM_NETWORK_INFO
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE,
+ "Prune Old Bss %s\n", iter_bss->ssid);
+#else
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE,
+ "Prune Old Bss %s\n", iter_bss->ssid);
+#endif
+ clear_bss_descriptor(iter_bss);
+ continue;
+ }
+
+ /* Translate to WE format this entry */
+ next_ev = translate_scan(priv, info, ev, stop, iter_bss);
+#ifdef GET_SCAN_FROM_NETWORK_INFO
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE,
+ "Report BSS %s\n", iter_bss->ssid);
+#else
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE,
+ "Report BSS %s\n", iter_bss->data.ssid);
+#endif
+ if (next_ev == NULL)
+ continue;
+ ev = next_ev;
+ }
+ dwrq->length = (ev - extra);
+ dwrq->flags = 0;
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s <<<\n", __func__);
+ return ret;
+}
+
+int rda5890_set_mlme(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ //struct rda5890_private *priv = (struct rda5890_private *)netdev_priv(dev);
+ struct iw_mlme *mlme = (struct iw_mlme *)extra;
+ int ret = 0;
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s >>>\n", __func__);
+
+ switch (mlme->cmd) {
+ case IW_MLME_DEAUTH:
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE,
+ "DEAUTH\n");
+ /* silently ignore */
+ break;
+
+ case IW_MLME_DISASSOC:
+ {
+ unsigned char ssid[6];
+ memset(ssid, 0, 6);
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE,
+ "DISASSOC\n");
+ /* silently ignore */
+ rda5890_set_ssid((struct rda5890_private *)netdev_priv(dev) , ssid, 6);
+ }
+ break;
+ default:
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE,
+ "Not supported cmd %d\n", mlme->cmd);
+ ret = -EOPNOTSUPP;
+ }
+
+ RDA5890_DBGLAP(RDA5890_DA_WEXT, RDA5890_DL_TRACE, "%s <<<\n", __func__);
+ return ret;
+}
+
+/*
+ * iwconfig settable callbacks
+ */
+static const iw_handler rda5890_wext_handler[] = {
+ (iw_handler) NULL, /* SIOCSIWCOMMIT */
+ (iw_handler) rda5890_get_name, /* SIOCGIWNAME */
+ (iw_handler) NULL, /* SIOCSIWNWID */
+ (iw_handler) NULL, /* SIOCGIWNWID */
+ (iw_handler) rda5890_set_freq, /* SIOCSIWFREQ */
+ (iw_handler) rda5890_get_freq, /* SIOCGIWFREQ */
+ (iw_handler) rda5890_set_mode, /* SIOCSIWMODE */
+ (iw_handler) rda5890_get_mode, /* SIOCGIWMODE */
+ (iw_handler) NULL, /* SIOCSIWSENS */
+ (iw_handler) NULL, /* SIOCGIWSENS */
+ (iw_handler) NULL, /* SIOCSIWRANGE */
+ (iw_handler) rda5890_get_range, /* SIOCGIWRANGE */
+ (iw_handler) NULL, /* SIOCSIWPRIV */
+ (iw_handler) NULL, /* SIOCGIWPRIV */
+ (iw_handler) NULL, /* SIOCSIWSTATS */
+ (iw_handler) NULL, /* SIOCGIWSTATS */
+ (iw_handler) NULL, /* SIOCSIWSPY */
+ (iw_handler) NULL, /* SIOCGIWSPY */
+ (iw_handler) NULL, /* SIOCSIWTHRSPY */
+ (iw_handler) NULL, /* SIOCGIWTHRSPY */
+ (iw_handler) rda5890_set_wap, /* SIOCSIWAP */
+ (iw_handler) rda5890_get_wap, /* SIOCGIWAP */
+ (iw_handler) rda5890_set_mlme, /* SIOCSIWMLME */
+ (iw_handler) NULL, /* SIOCGIWAPLIST - deprecated */
+ (iw_handler) rda5890_set_scan, /* SIOCSIWSCAN */
+ (iw_handler) rda5890_get_scan, /* SIOCGIWSCAN */
+ (iw_handler) rda5890_set_essid, /* SIOCSIWESSID */
+ (iw_handler) rda5890_get_essid, /* SIOCGIWESSID */
+ (iw_handler) rda5890_set_nick, /* SIOCSIWNICKN */
+ (iw_handler) rda5890_get_nick, /* SIOCGIWNICKN */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) rda5890_set_rate, /* SIOCSIWRATE */
+ (iw_handler) rda5890_get_rate, /* SIOCGIWRATE */
+ (iw_handler) rda5890_set_rts, /* SIOCSIWRTS */
+ (iw_handler) rda5890_get_rts, /* SIOCGIWRTS */
+ (iw_handler) rda5890_set_frag, /* SIOCSIWFRAG */
+ (iw_handler) rda5890_get_frag, /* SIOCGIWFRAG */
+ (iw_handler) rda5890_set_txpow, /* SIOCSIWTXPOW */
+ (iw_handler) rda5890_get_txpow, /* SIOCGIWTXPOW */
+ (iw_handler) rda5890_set_retry, /* SIOCSIWRETRY */
+ (iw_handler) rda5890_get_retry, /* SIOCGIWRETRY */
+ (iw_handler) rda5890_set_encode, /* SIOCSIWENCODE */
+ (iw_handler) rda5890_get_encode, /* SIOCGIWENCODE */
+ (iw_handler) rda5890_set_power, /* SIOCSIWPOWER */
+ (iw_handler) rda5890_get_power, /* SIOCGIWPOWER */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) rda5890_set_genie, /* SIOCSIWGENIE */
+ (iw_handler) rda5890_get_genie, /* SIOCGIWGENIE */
+ (iw_handler) rda5890_set_auth, /* SIOCSIWAUTH */
+ (iw_handler) rda5890_get_auth, /* SIOCGIWAUTH */
+ (iw_handler) rda5890_set_encodeext,/* SIOCSIWENCODEEXT */
+ (iw_handler) rda5890_get_encodeext,/* SIOCGIWENCODEEXT */
+ (iw_handler) rda5890_set_pmksa, /* SIOCSIWPMKSA */
+};
+
+struct iw_handler_def rda5890_wext_handler_def = {
+ .num_standard = ARRAY_SIZE(rda5890_wext_handler),
+ .standard = (iw_handler *) rda5890_wext_handler,
+ .get_wireless_stats = rda5890_get_wireless_stats,
+};
+
--- /dev/null
+/**
+ * This file contains definition for IOCTL call.
+ */
+#include "rda5890_defs.h"
+#ifndef _RDA5890_WEXT_H_
+#define _RDA5890_WEXT_H_
+
+#ifndef DEFAULT_MAX_SCAN_AGE
+#define DEFAULT_MAX_SCAN_AGE (15*HZ)
+#ifdef GET_SCAN_FROM_NETWORK_INFO
+#else
+#define DEFAULT_MAX_SCAN_AGE (15*HZ)
+#endif
+#else
+#undef DEFAULT_MAX_SCAN_AGE
+#ifdef GET_SCAN_FROM_NETWORK_INFO
+#define DEFAULT_MAX_SCAN_AGE (15*HZ)
+#else
+#define DEFAULT_MAX_SCAN_AGE (15*HZ)
+#endif
+#endif
+
+extern struct iw_handler_def rda5890_wext_handler_def;
+
+void rda5890_indicate_disconnected(struct rda5890_private *priv);
+void rda5890_indicate_connected(struct rda5890_private *priv);
+void rda5890_assoc_done_worker(struct work_struct *work);
+void rda5890_assoc_worker(struct work_struct *work);
+void rda5890_scan_worker(struct work_struct *work);
+void rda5890_wlan_connect_worker(struct work_struct *work);
+
+static inline unsigned char is_zero_eth_addr(unsigned char * addr)
+{
+ return !(addr[0] | addr[1] |addr[2] |addr[3] |addr[4] |addr[5]);
+}
+
+#endif
--- /dev/null
+#include <linux/module.h>
+#include <linux/dcache.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/etherdevice.h>
+#include <net/iw_handler.h>
+#include <linux/mmc/sdio_func.h>
+
+#include "rda5890_defs.h"
+#include "rda5890_dev.h"
+#include "rda5890_wid.h"
+#include "rda5890_wext.h"
+#include "rda5890_txrx.h"
+#include "rda5890_if_sdio.h"
+
+static unsigned char is_need_set_notch = 0;
+
+/* for both Query and Write */
+int rda5890_wid_request(struct rda5890_private *priv,
+ char *wid_req, unsigned short wid_req_len,
+ char *wid_rsp, unsigned short *wid_rsp_len)
+{
+ int ret = 0;
+ int timeleft = 0;
+ char data_buf[RDA5890_MAX_WID_LEN + 2];
+ unsigned short data_len;
+ struct if_sdio_card * card = (struct if_sdio_card *)priv->card;
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_DEBUG,
+ "%s <<<\n", __func__);
+
+#ifdef WIFI_TEST_MODE
+ if(rda_5990_wifi_in_test_mode())
+ return 0;
+#endif //end WIFI_TEST_MODE
+
+ mutex_lock(&priv->wid_lock);
+ priv->wid_rsp = wid_rsp;
+ priv->wid_rsp_len = *wid_rsp_len;
+ priv->wid_pending = 1;
+
+ data_len = wid_req_len + 2;
+ data_buf[0] = (char)(data_len&0xFF);
+ data_buf[1] = (char)((data_len>>8)&0x0F);
+ data_buf[1] |= 0x40; // for Request(Q/W) 0x4
+ memcpy(data_buf + 2, wid_req, wid_req_len);
+
+ init_completion(&priv->wid_done);
+#ifdef WIFI_UNLOCK_SYSTEM
+ rda5990_wakeLock();
+#endif
+ ret = rda5890_host_to_card(priv, data_buf, data_len, WID_REQUEST_PACKET);
+ if (ret) {
+ RDA5890_ERRP("host_to_card send failed, ret = %d\n", ret);
+ priv->wid_pending = 0;
+ goto out;
+ }
+
+ atomic_inc(&card->wid_complete_flag);
+ timeleft = wait_for_completion_timeout(&priv->wid_done, msecs_to_jiffies(450));
+ if (timeleft == 0) {
+ RDA5890_ERRP("respose timeout wid :%x %x \n", wid_req[4], wid_req[5]);
+ priv->wid_pending = 0;
+ ret = -EFAULT;
+ goto out;
+ }
+
+ *wid_rsp_len = priv->wid_rsp_len;
+
+out:
+ mutex_unlock(&priv->wid_lock);
+ atomic_set(&card->wid_complete_flag, 0);
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_DEBUG,
+ "%s >>> wid: %x %x \n", __func__, wid_req[4],wid_req[5]);
+#ifdef WIFI_UNLOCK_SYSTEM
+ rda5990_wakeUnlock();
+#endif
+ return ret;
+}
+
+int rda5890_wid_request_polling(struct rda5890_private *priv,
+ char *wid_req, unsigned short wid_req_len,
+ char *wid_rsp, unsigned short *wid_rsp_len)
+{
+ int ret = -1;
+ int timeleft = 0;
+ char data_buf[RDA5890_MAX_WID_LEN + 2];
+ unsigned short data_len;
+ unsigned char status;
+ unsigned int retry = 0, count = 0;
+ struct if_sdio_card * card = (struct if_sdio_card*)priv->card;
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_DEBUG,
+ "%s >>>\n", __func__);
+
+ priv->wid_rsp = wid_rsp;
+ priv->wid_rsp_len = *wid_rsp_len;
+
+ data_len = wid_req_len + 2;
+ data_buf[0] = (char)(data_len&0xFF);
+ data_buf[1] = (char)((data_len>>8)&0x0F);
+ data_buf[1] |= 0x40; // for Request(Q/W) 0x4
+ memcpy(data_buf + 2, wid_req, wid_req_len);
+
+re_send:
+
+ count += 1;
+ ret = rda5890_host_to_card(priv, data_buf, data_len, WID_REQUEST_POLLING_PACKET);
+ if (ret) {
+ RDA5890_ERRP("host_to_card send failed, ret = %d\n", ret);
+ goto out;
+ }
+
+ rda5890_shedule_timeout(3); //3ms delay
+ while(retry < 20)
+ {
+ sdio_claim_host(card->func);
+ status = sdio_readb(card->func, IF_SDIO_FUN1_INT_STAT, &ret);
+ sdio_release_host(card->func);
+ if (ret)
+ goto out;
+
+ if (status & IF_SDIO_INT_AHB2SDIO)
+ {
+ int ret = 0;
+ u8 size_l = 0, size_h = 0;
+ u16 size, chunk;
+
+ sdio_claim_host(card->func);
+ size_l = sdio_readb(card->func, IF_SDIO_AHB2SDIO_PKTLEN_L, &ret);
+ sdio_release_host(card->func);
+ if (ret) {
+ RDA5890_ERRP("read PKTLEN_L reg fail\n");
+ goto out;
+ }
+ else
+ RDA5890_ERRP("read PKTLEN_L reg size_l:%d \n", size_l);
+
+ sdio_claim_host(card->func);
+ size_h = sdio_readb(card->func, IF_SDIO_AHB2SDIO_PKTLEN_H, &ret);
+ sdio_release_host(card->func);
+ if (ret) {
+ RDA5890_ERRP("read PKTLEN_H reg fail\n");
+ goto out;
+ }
+ else
+ RDA5890_ERRP("read PKTLEN_H reg size_h:%d\n",size_h);
+
+ size = (size_l | ((size_h & 0x7f) << 8)) * 4;
+ if (size < 4) {
+ RDA5890_ERRP("invalid packet size (%d bytes) from firmware\n", size);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* alignment is handled on firmside */
+ //chunk = sdio_align_size(card->func, size);
+ chunk = size;
+
+ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_NORM,
+ "if_sdio_card_to_host, size = %d, aligned size = %d\n", size, chunk);
+
+ /* TODO: handle multiple packets here */
+ sdio_claim_host(card->func);
+ ret = sdio_readsb(card->func, card->buffer, IF_SDIO_FUN1_FIFO_RD, chunk);
+ sdio_release_host(card->func);
+ if (ret) {
+ RDA5890_ERRP("sdio_readsb fail, ret = %d\n", ret);
+ goto out;
+ }
+#if 1
+ if(priv->version == 7)
+ sdio_writeb(card->func, 0x20 ,IF_SDIO_FUN1_INT_PEND, &ret);
+#endif
+
+ /* TODO: this chunk size need to be handled here */
+ {
+ unsigned char rx_type;
+ unsigned short rx_length;
+ unsigned char msg_type;
+ unsigned char *packet = (unsigned char *)card->buffer;
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_DEBUG,
+ "%s >>>\n", __func__);
+
+ rx_type = (unsigned char)packet[1]&0xF0;
+ rx_length = (unsigned short)(packet[0] + ((packet[1]&0x0f) << 8));
+
+ if (rx_length > chunk) {
+ RDA5890_ERRP("packet_len %d less than header specified length %d\n",
+ chunk, rx_length);
+ goto out;
+ }
+
+ if( rx_type == 0x30 )
+ {
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_NORM,
+ "Message Packet type =%x \n", msg_type);
+ msg_type = packet[2];
+
+ if (msg_type == 'R')
+ {
+ packet += 2;
+ if(priv->wid_msg_id - 1 == packet[1])
+ {
+ ret = 0;
+ if(priv->wid_rsp_len > rx_length - 2)
+ {
+ priv->wid_rsp_len = rx_length - 2;
+ memcpy(priv->wid_rsp, packet, rx_length -2);
+ }
+ break;
+ }
+ else
+ RDA5890_ERRP("rda5890_wid_request_polling wid_msg_id is wrong %d %d wid=%x \n", priv->wid_msg_id -1, packet[1], (packet[4] | (packet[5] << 8)));
+ }
+ }
+ }
+ }
+
+ rda5890_shedule_timeout(3); //3ms delay
+ ret = -1;
+ retry ++;
+ }
+
+ if(ret < 0 && count <= 3)
+ goto re_send;
+out:
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_DEBUG,
+ "%s <<< wid: %x %x retry: %d count = %d \n", __func__, wid_req[4],wid_req[5], retry, count);
+
+ return ret;
+}
+void rda5890_wid_response(struct rda5890_private *priv,
+ char *wid_rsp, unsigned short wid_rsp_len)
+{
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_DEBUG,
+ "%s >>>\n", __func__);
+
+ if (!priv->wid_pending) {
+ RDA5890_ERRP("no wid pending\n");
+ return;
+ }
+
+ if (wid_rsp_len > priv->wid_rsp_len) {
+ RDA5890_ERRP("not enough space for wid response, size = %d, buf = %d\n",
+ wid_rsp_len, priv->wid_rsp_len);
+ complete(&priv->wid_done);
+ return;
+ }
+
+ memcpy(priv->wid_rsp, wid_rsp, wid_rsp_len);
+ priv->wid_rsp_len = wid_rsp_len;
+ priv->wid_pending = 0;
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_DEBUG,
+ "%s <<<\n", __func__);
+
+ complete(&priv->wid_done);
+}
+
+void rda5890_wid_status(struct rda5890_private *priv,
+ char *wid_status, unsigned short wid_status_len)
+{
+ char mac_status;
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_DEBUG,
+ "%s >>>\n", __func__);
+
+#ifdef WIFI_UNLOCK_SYSTEM
+ rda5990_wakeLock();
+#endif
+
+ mac_status = wid_status[7];
+ if (mac_status == MAC_CONNECTED) {
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_CRIT,
+ "MAC CONNECTED\n");
+
+ priv->connect_status = MAC_CONNECTED;
+ netif_carrier_on(priv->dev);
+ netif_wake_queue(priv->dev);
+ rda5890_indicate_connected(priv);
+
+ priv->first_init = 0;
+ cancel_delayed_work(&priv->assoc_done_work);
+ queue_delayed_work(priv->work_thread, &priv->assoc_done_work, 0);
+
+ if(test_and_clear_bit(ASSOC_FLAG_ASSOC_RETRY, &priv->assoc_flags))
+ {
+ cancel_delayed_work_sync(&priv->assoc_work);
+ }
+
+ if(test_bit(ASSOC_FLAG_WLAN_CONNECTING, &priv->assoc_flags))
+ cancel_delayed_work(&priv->wlan_connect_work);
+
+ set_bit(ASSOC_FLAG_WLAN_CONNECTING, &priv->assoc_flags);
+ queue_delayed_work(priv->work_thread, &priv->wlan_connect_work, HZ*20);
+
+ }
+ else if (mac_status == MAC_DISCONNECTED) {
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_CRIT,
+ "MAC DISCONNECTED\n");
+
+ if(priv->connect_status == MAC_CONNECTED)
+ is_need_set_notch = 1;
+ else
+ is_need_set_notch = 0;
+
+ if(!test_bit(ASSOC_FLAG_ASSOC_RETRY, &priv->assoc_flags))
+ {
+ priv->connect_status = MAC_DISCONNECTED;
+ netif_stop_queue(priv->dev);
+ netif_carrier_off(priv->dev);
+ if(!priv->first_init) // the first disconnect should not send to upper
+ rda5890_indicate_disconnected(priv);
+ else
+ priv->first_init = 0;
+
+ if(test_bit(ASSOC_FLAG_ASSOC_START, &priv->assoc_flags))
+ {
+ cancel_delayed_work(&priv->wlan_connect_work);
+ queue_delayed_work(priv->work_thread, &priv->wlan_connect_work, HZ*4);
+ }
+
+ clear_bit(ASSOC_FLAG_ASSOC_START, &priv->assoc_flags);
+ clear_bit(ASSOC_FLAG_WLAN_CONNECTING, &priv->assoc_flags);
+ }
+ else
+ {
+ RDA5890_ERRP("********wep assoc will be retry ---------- 0x%02x\n", mac_status);
+ }
+ }
+ else {
+ RDA5890_ERRP("Invalid MAC Status 0x%02x\n", mac_status);
+ }
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_DEBUG,
+ "%s <<<\n", __func__);
+
+#ifdef WIFI_UNLOCK_SYSTEM
+ rda5990_wakeUnlock();
+#endif
+}
+
+void rda5890_card_to_host(struct rda5890_private *priv,
+ char *packet, unsigned short packet_len)
+{
+ unsigned char rx_type;
+ unsigned short rx_length;
+ unsigned char msg_type;
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_DEBUG,
+ "%s >>>\n", __func__);
+
+ rx_type = (unsigned char)packet[1]&0xF0;
+ rx_length = (unsigned short)(packet[0] + ((packet[1]&0x0f) << 8));
+
+ if (rx_length > packet_len) {
+ RDA5890_ERRP("packet_len %d less than header specified length %d\n",
+ packet_len, rx_length);
+ goto out;
+ }
+
+ if( rx_type == 0x30 )
+ {
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_NORM,
+ "Message Packet\n");
+ msg_type = packet[2];
+ if(msg_type == 'I')
+ {
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_NORM,
+ "Indication Message\n");
+ rda5890_wid_status(priv, packet + 2, rx_length - 2);
+ }
+ else if (msg_type == 'R')
+ {
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_NORM,
+ "WID Message\n");
+ rda5890_wid_response(priv, packet + 2, rx_length - 2);
+ }
+#ifdef GET_SCAN_FROM_NETWORK_INFO
+ else if(msg_type == 'N')
+ {
+ extern void rda5890_network_information(struct rda5890_private *priv,
+ char *info, unsigned short info_len);
+ rda5890_network_information(priv, packet + 2, rx_length - 2);
+ }
+#endif
+ else {
+ //RDA5890_ERRP("Invalid Message Type '%c'\n", msg_type);
+ }
+ }
+ else if(rx_type == 0x20)
+ {
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_NORM,
+ "Data Packet\n");
+ rda5890_data_rx(priv, packet + 2, rx_length - 2);
+ }
+ else {
+ RDA5890_ERRP("Invalid Packet Type 0x%02x\n", rx_type);
+ }
+
+out:
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_DEBUG,
+ "%s <<<\n", __func__);
+}
+
+/*
+ * check wid response header
+ * if no error, return the pointer to the payload
+ * support only 1 wid per packet
+ */
+int rda5890_check_wid_response(char *wid_rsp, unsigned short wid_rsp_len,
+ unsigned short wid, char wid_msg_id,
+ char payload_len, char **ptr_payload)
+{
+ unsigned short rsp_len;
+ unsigned short rsp_wid;
+ unsigned char msg_len;
+
+ if (wid_rsp[0] != 'R') {
+ RDA5890_ERRP("wid_rsp[0] != 'R'\n");
+ goto err;
+ }
+
+ if (wid_rsp[1] != wid_msg_id) {
+ RDA5890_ERRP("wid_msg_id not match msg_id: %d \n", wid_rsp[1]);
+ goto err;
+ }
+
+ if (wid_rsp_len < 4) {
+ RDA5890_ERRP("wid_rsp_len < 4\n");
+ goto err;
+ }
+
+ rsp_len = wid_rsp[2] | (wid_rsp[3] << 8);
+ if (wid_rsp_len != rsp_len) {
+ RDA5890_ERRP("wid_rsp_len not match, %d != %d\n", wid_rsp_len, rsp_len);
+ goto err;
+ }
+
+ if (wid_rsp_len < 7) {
+ RDA5890_ERRP("wid_rsp_len < 7\n");
+ goto err;
+ }
+#if 0
+ rsp_wid = wid_rsp[4] | (wid_rsp[5] << 8);
+ if (wid != rsp_wid) {
+ RDA5890_ERRP("wid not match, 0x%04x != 0x%04x\n", wid, rsp_wid);
+ goto err;
+ }
+#endif
+ msg_len = wid_rsp[6];
+ if (wid_rsp_len != msg_len + 7) {
+ RDA5890_ERRP("msg_len not match, %d + 7 != %d\n", msg_len, wid_rsp_len);
+ goto err;
+ }
+
+ if (payload_len != msg_len) {
+ RDA5890_ERRP("payload_len not match, %d != %d\n", msg_len, payload_len);
+ goto err;
+ }
+
+ *ptr_payload = wid_rsp + 7;
+
+ return 0;
+
+err:
+ RDA5890_ERRP("rda5890_check_wid_response failed wid=0x%04x wid_msg_id:%d \n" ,wid_rsp[4] | (wid_rsp[5] << 8), wid_msg_id);
+ return -EINVAL;
+}
+
+/*
+ * check wid status response
+ */
+int rda5890_check_wid_status(char *wid_rsp, unsigned short wid_rsp_len,
+ char wid_msg_id)
+{
+ int ret;
+ unsigned short wid = WID_STATUS;
+ char *ptr_payload;
+ char status_val;
+
+ ret = rda5890_check_wid_response(wid_rsp, wid_rsp_len, wid, wid_msg_id,
+ 1, &ptr_payload);
+ if (ret) {
+ RDA5890_ERRP("rda5890_check_wid_status, check_wid_response fail\n");
+ return ret;
+ }
+
+ status_val = ptr_payload[0];
+ if (status_val != WID_STATUS_SUCCESS) {
+ RDA5890_ERRP("check_wid_status NOT success, status = %d\n", status_val);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int rda5890_generic_get_uchar(struct rda5890_private *priv,
+ unsigned short wid, unsigned char *val)
+{
+ int ret;
+ char wid_req[6];
+ unsigned short wid_req_len = 6;
+ char wid_rsp[32];
+ unsigned short wid_rsp_len = 32;
+ char wid_msg_id = priv->wid_msg_id++;
+ char *ptr_payload;
+
+ 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 = rda5890_wid_request(priv, wid_req, wid_req_len, wid_rsp, &wid_rsp_len);
+ if (ret) {
+ RDA5890_ERRP("rda5890_wid_request fail, ret = %d\n", ret);
+ goto out;
+ }
+
+ ret = rda5890_check_wid_response(wid_rsp, wid_rsp_len, wid, wid_msg_id,
+ sizeof(unsigned char), &ptr_payload);
+ if (ret) {
+ RDA5890_ERRP("check_wid_response fail, ret = %d\n", ret);
+ goto out;
+ }
+
+ *val = *ptr_payload;
+out:
+ return ret;
+}
+
+int rda5890_generic_set_uchar(struct rda5890_private *priv,
+ unsigned short wid, unsigned char val)
+{
+ int ret;
+ char wid_req[7 + sizeof(unsigned char)];
+ unsigned short wid_req_len = 7 + 1;
+ char wid_rsp[32];
+ unsigned short wid_rsp_len = 32;
+ char 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_req[4] = (char)(wid&0x00FF);
+ wid_req[5] = (char)((wid&0xFF00) >> 8);
+
+ wid_req[6] = 1;
+ wid_req[7] = val;
+ ret = rda5890_wid_request(priv, wid_req, wid_req_len, wid_rsp, &wid_rsp_len);
+ if (ret) {
+ RDA5890_ERRP("rda5890_wid_request fail, ret = %d\n", ret);
+ goto out;
+ }
+
+ ret = rda5890_check_wid_status(wid_rsp, wid_rsp_len, wid_msg_id);
+ if (ret) {
+ RDA5890_ERRP("check_wid_status fail, ret = %d\n", ret);
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+#if 1
+int rda5890_generic_get_ushort(struct rda5890_private *priv,
+ unsigned short wid, unsigned short *val)
+{
+ int ret;
+ char wid_req[6];
+ unsigned short wid_req_len = 6;
+ char wid_rsp[32];
+ unsigned short wid_rsp_len = 32;
+ char wid_msg_id = priv->wid_msg_id++;
+ char *ptr_payload;
+
+ 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 = rda5890_wid_request(priv, wid_req, wid_req_len, wid_rsp, &wid_rsp_len);
+ if (ret) {
+ RDA5890_ERRP("rda5890_wid_request fail, ret = %d\n", ret);
+ goto out;
+ }
+
+ ret = rda5890_check_wid_response(wid_rsp, wid_rsp_len, wid, wid_msg_id,
+ sizeof(unsigned short), &ptr_payload);
+ if (ret) {
+ RDA5890_ERRP("check_wid_response fail, ret = %d\n", ret);
+ goto out;
+ }
+
+ memcpy(val, ptr_payload, sizeof(unsigned short));
+
+out:
+ return ret;
+}
+
+int rda5890_generic_set_ushort(struct rda5890_private *priv,
+ unsigned short wid, unsigned short val)
+{
+ int ret;
+ char wid_req[7 + sizeof(unsigned short)];
+ unsigned short wid_req_len = 7 + sizeof(unsigned short);
+ char wid_rsp[32];
+ unsigned short wid_rsp_len = 32;
+ char 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_req[4] = (char)(wid&0x00FF);
+ wid_req[5] = (char)((wid&0xFF00) >> 8);
+
+ wid_req[6] = (char)(sizeof(unsigned short));
+ memcpy(wid_req + 7, &val, sizeof(unsigned short));
+
+ ret = rda5890_wid_request(priv, wid_req, wid_req_len, wid_rsp, &wid_rsp_len);
+ if (ret) {
+ RDA5890_ERRP("rda5890_wid_request fail, ret = %d\n", ret);
+ goto out;
+ }
+
+ ret = rda5890_check_wid_status(wid_rsp, wid_rsp_len, wid_msg_id);
+ if (ret) {
+ RDA5890_ERRP("check_wid_status fail, ret = %d\n", ret);
+ goto out;
+ }
+
+out:
+ return ret;
+}
+#endif
+
+int rda5890_generic_get_ulong(struct rda5890_private *priv,
+ unsigned short wid, unsigned long *val)
+{
+ int ret;
+ char wid_req[6];
+ unsigned short wid_req_len = 6;
+ char wid_rsp[32];
+ unsigned short wid_rsp_len = 32;
+ char wid_msg_id = priv->wid_msg_id++;
+ char *ptr_payload;
+
+ 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 = rda5890_wid_request(priv, wid_req, wid_req_len, wid_rsp, &wid_rsp_len);
+ if (ret) {
+ RDA5890_ERRP("rda5890_wid_request fail, ret = %d\n", ret);
+ goto out;
+ }
+
+ ret = rda5890_check_wid_response(wid_rsp, wid_rsp_len, wid, wid_msg_id,
+ sizeof(unsigned long), &ptr_payload);
+ if (ret) {
+ RDA5890_ERRP("check_wid_response fail, ret = %d\n", ret);
+ goto out;
+ }
+
+ memcpy(val, ptr_payload, sizeof(unsigned long));
+
+out:
+ return ret;
+}
+
+int rda5890_generic_set_ulong(struct rda5890_private *priv,
+ unsigned short wid, unsigned long val)
+{
+ int ret;
+ char wid_req[7 + sizeof(unsigned long)];
+ unsigned short wid_req_len = 7 + sizeof(unsigned long);
+ char wid_rsp[32];
+ unsigned short wid_rsp_len = 32;
+ char 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_req[4] = (char)(wid&0x00FF);
+ wid_req[5] = (char)((wid&0xFF00) >> 8);
+
+ wid_req[6] = (char)(sizeof(unsigned long));
+ memcpy(wid_req + 7, &val, sizeof(unsigned long));
+
+ ret = rda5890_wid_request(priv, wid_req, wid_req_len, wid_rsp, &wid_rsp_len);
+ if (ret) {
+ RDA5890_ERRP("rda5890_wid_request fail, ret = %d\n", ret);
+ goto out;
+ }
+
+ ret = rda5890_check_wid_status(wid_rsp, wid_rsp_len, wid_msg_id);
+ if (ret) {
+ RDA5890_ERRP("check_wid_status fail, ret = %d\n", ret);
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+int rda5890_generic_get_str(struct rda5890_private *priv,
+ unsigned short wid, unsigned char *val, unsigned char len)
+{
+ int ret;
+ char wid_req[6];
+ unsigned short wid_req_len = 6;
+ char wid_rsp[RDA5890_MAX_WID_LEN];
+ unsigned short wid_rsp_len = RDA5890_MAX_WID_LEN;
+ char wid_msg_id = priv->wid_msg_id++;
+ char *ptr_payload;
+
+ 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 = rda5890_wid_request(priv, wid_req, wid_req_len, wid_rsp, &wid_rsp_len);
+ if (ret) {
+ RDA5890_ERRP("rda5890_wid_request fail, ret = %d\n", ret);
+ goto out;
+ }
+
+ ret = rda5890_check_wid_response(wid_rsp, wid_rsp_len, wid, wid_msg_id,
+ (char)len, &ptr_payload);
+ if (ret) {
+ RDA5890_ERRP("check_wid_response fail, ret = %d\n", ret);
+ goto out;
+ }
+
+ memcpy(val, ptr_payload, len);
+
+out:
+ return ret;
+}
+
+int rda5890_generic_set_str(struct rda5890_private *priv,
+ unsigned short wid, unsigned char *val, unsigned char len)
+{
+ int ret;
+ char wid_req[RDA5890_MAX_WID_LEN];
+ unsigned short wid_req_len = 7 + len;
+ char wid_rsp[RDA5890_MAX_WID_LEN];
+ unsigned short wid_rsp_len = RDA5890_MAX_WID_LEN;
+ char 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_req[4] = (char)(wid&0x00FF);
+ wid_req[5] = (char)((wid&0xFF00) >> 8);
+
+ wid_req[6] = (char)(len);
+ memcpy(wid_req + 7, val, len);
+
+ ret = rda5890_wid_request(priv, wid_req, wid_req_len, wid_rsp, &wid_rsp_len);
+ if (ret) {
+ RDA5890_ERRP("rda5890_wid_request fail, ret = %d\n", ret);
+ goto out;
+ }
+
+ ret = rda5890_check_wid_status(wid_rsp, wid_rsp_len, wid_msg_id);
+ if (ret) {
+ RDA5890_ERRP("check_wid_status fail, ret = %d\n", ret);
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+int rda5890_check_wid_response_unknown_len(
+ char *wid_rsp, unsigned short wid_rsp_len,
+ unsigned short wid, char wid_msg_id,
+ char *payload_len, char **ptr_payload)
+{
+ unsigned short rsp_len;
+ unsigned short rsp_wid;
+ unsigned char msg_len;
+
+ if (wid_rsp[0] != 'R') {
+ RDA5890_ERRP("wid_rsp[0] != 'R'\n");
+ return -EINVAL;
+ }
+
+ if (wid_rsp[1] != wid_msg_id) {
+ RDA5890_ERRP("wid_msg_id not match\n");
+ return -EINVAL;
+ }
+
+ if (wid_rsp_len < 4) {
+ RDA5890_ERRP("wid_rsp_len < 4\n");
+ return -EINVAL;
+ }
+
+ rsp_len = wid_rsp[2] | (wid_rsp[3] << 8);
+ if (wid_rsp_len != rsp_len) {
+ RDA5890_ERRP("wid_rsp_len not match, %d != %d\n", wid_rsp_len, rsp_len);
+ return -EINVAL;
+ }
+
+ if (wid_rsp_len < 7) {
+ RDA5890_ERRP("wid_rsp_len < 7\n");
+ return -EINVAL;
+ }
+#if 0
+ rsp_wid = wid_rsp[4] | (wid_rsp[5] << 8);
+ if (wid != rsp_wid) {
+ RDA5890_ERRP("wid not match, 0x%04x != 0x%04x\n", wid, rsp_wid);
+ return -EINVAL;
+ }
+#endif
+ msg_len = wid_rsp[6];
+ if (wid_rsp_len != msg_len + 7) {
+ RDA5890_ERRP("msg_len not match, %d + 7 != %d\n", msg_len, wid_rsp_len);
+ return -EINVAL;
+ }
+
+ *payload_len = msg_len;
+
+ *ptr_payload = wid_rsp + 7;
+
+ return 0;
+err:
+
+ RDA5890_ERRP("wid is %x wid_msg %d \n", wid_rsp[4] | (wid_rsp[5] << 8), wid_rsp[1]);
+ return -EINVAL;
+}
+
+int rda5890_get_str_unknown_len(struct rda5890_private *priv,
+ unsigned short wid, unsigned char *val, unsigned char *len)
+{
+ int ret;
+ char wid_req[6];
+ unsigned short wid_req_len = 6;
+ char wid_rsp[RDA5890_MAX_WID_LEN];
+ unsigned short wid_rsp_len = RDA5890_MAX_WID_LEN;
+ char wid_msg_id = priv->wid_msg_id++;
+ char *ptr_payload;
+
+ 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 = rda5890_wid_request(priv, wid_req, wid_req_len, wid_rsp, &wid_rsp_len);
+ if (ret) {
+ RDA5890_ERRP("rda5890_wid_request fail, ret = %d\n", ret);
+ goto out;
+ }
+
+ ret = rda5890_check_wid_response_unknown_len(
+ wid_rsp, wid_rsp_len, wid, wid_msg_id, (char*)len, &ptr_payload);
+ if (ret) {
+ RDA5890_ERRP("check_wid_response fail, ret = %d\n", ret);
+ goto out;
+ }
+
+ memcpy(val, ptr_payload, *len);
+
+out:
+ return ret;
+}
+
+extern int rda5890_sdio_set_default_notch(struct rda5890_private *priv);
+int rda5890_start_scan(struct rda5890_private *priv)
+{
+ int ret;
+ char wid_req[12];
+ unsigned short wid_req_len = 12;
+ char wid_rsp[32];
+ unsigned short wid_rsp_len = 32;
+ unsigned short wid;
+ char wid_msg_id = 0;
+
+ if(priv->connect_status != MAC_CONNECTED)
+ {
+ rda5890_sdio_set_default_notch(priv);
+ }
+
+ 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_req_len = 12;
+ wid_req[2] = (char)(wid_req_len&0x00FF);
+ wid_req[3] = (char)((wid_req_len&0xFF00) >> 8);
+
+ ret = rda5890_wid_request(priv, wid_req, wid_req_len, wid_rsp, &wid_rsp_len);
+ if (ret) {
+ RDA5890_ERRP("rda5890_wid_request fail, ret = %d\n", ret);
+ goto out;
+ }
+
+ ret = rda5890_check_wid_status(wid_rsp, wid_rsp_len, wid_msg_id);
+ if (ret) {
+ RDA5890_ERRP("check_wid_status fail, ret = %d\n", ret);
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+
+int rda5890_start_scan_enable_network_info(struct rda5890_private *priv)
+{
+ int ret;
+ char wid_req[12];
+ unsigned short wid_req_len = 12;
+ char wid_rsp[32];
+ unsigned short wid_rsp_len = 32;
+ unsigned short wid;
+ char wid_msg_id = 0;
+
+ if(priv->connect_status != MAC_CONNECTED)
+ {
+ rda5890_sdio_set_default_notch(priv);
+ }
+
+ 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;
+ wid_req[2] = (char)(wid_req_len&0x00FF);
+ wid_req[3] = (char)((wid_req_len&0xFF00) >> 8);
+
+ ret = rda5890_wid_request(priv, wid_req, wid_req_len, wid_rsp, &wid_rsp_len);
+ if (ret) {
+ RDA5890_ERRP("rda5890_wid_request fail, ret = %d\n", ret);
+ goto out;
+ }
+
+ ret = rda5890_check_wid_status(wid_rsp, wid_rsp_len, wid_msg_id);
+ if (ret) {
+ RDA5890_ERRP("check_wid_status fail, ret = %d\n", ret);
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+int rda5890_start_join(struct rda5890_private *priv)
+{
+ int ret;
+ char wid_req[255];
+ unsigned short wid_req_len = 0;
+ char wid_rsp[32];
+ unsigned short wid_rsp_len = 32;
+ unsigned short wid;
+ char wid_msg_id = priv->wid_msg_id++;
+ unsigned short i = 0;
+ unsigned char * wep_key = 0, key_str_len = 0;
+ unsigned char key_str[26 + 1] , * key, *pWid_req;
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_DEBUG,
+ "%s <<< mode:%d authtype:%d ssid:%s\n", __func__, priv->imode, priv->authtype,
+ priv->assoc_ssid);
+
+ wid_req[0] = 'W';
+ wid_req[1] = wid_msg_id;
+
+
+ wid = WID_802_11I_MODE;
+ wid_req[4] = (char)(wid&0x00FF);
+ wid_req[5] = (char)((wid&0xFF00) >> 8);
+
+ wid_req[6] = 1;
+ wid_req[7] = priv->imode;
+
+ wid = WID_AUTH_TYPE;
+ wid_req[8] = (char)(wid&0x00FF);
+ wid_req[9] = (char)((wid&0xFF00) >> 8);
+
+ wid_req[10] = 1;
+ wid_req[11] = priv->authtype;
+
+#ifdef GET_SCAN_FROM_NETWORK_INFO
+ wid = WID_NETWORK_INFO_EN;
+ wid_req[12] = (char)(wid&0x00FF);
+ wid_req[13] = (char)((wid&0xFF00) >> 8);
+
+ wid_req[14] = 1;
+ wid_req[15] = 0;
+
+ wid = WID_CURRENT_TX_RATE;
+ wid_req[16] = (char)(wid&0x00FF);
+ wid_req[17] = (char)((wid&0xFF00) >> 8);
+
+ wid_req[18] = 1;
+ wid_req[19] = 1;
+
+ wid_req_len = 20;
+ pWid_req = wid_req + 20;
+#else
+ wid_req_len = 12;
+ pWid_req = wid_req + 12;
+#endif
+ wid = WID_WEP_KEY_VALUE0;
+ if(priv->imode == 3 || priv->imode == 7) //write wep key
+ {
+ 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;
+ }
+ }
+
+// 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;
+
+
+ wid_req[2] = (char)(wid_req_len&0x00FF);
+ wid_req[3] = (char)((wid_req_len&0xFF00) >> 8);
+
+ ret = rda5890_wid_request(priv, wid_req, wid_req_len, wid_rsp, &wid_rsp_len);
+ if (ret) {
+ RDA5890_ERRP("rda5890_start_join fail, ret = %d\n", ret);
+ goto out;
+ }
+
+ ret = rda5890_check_wid_status(wid_rsp, wid_rsp_len, wid_msg_id);
+ if (ret) {
+ RDA5890_ERRP("rda5890_start_join check status fail, ret = %d\n", ret);
+ goto out;
+ }
+
+out:
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_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 rda5890_set_txrate(struct rda5890_private *priv, unsigned char mbps)
+{
+ int ret;
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_TRACE,
+ "rda5890_set_txrate <<< \n");
+
+ ret = rda5890_generic_set_uchar(priv, WID_CURRENT_TX_RATE, mbps); //O FOR AUTO 1FOR 1MBPS
+ if (ret) {
+ goto out;
+ }
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_TRACE,
+ "rda5890_set_txrate success >>> \n");
+
+out:
+ return ret;
+}
+
+int rda5890_set_core_init_polling(struct rda5890_private *priv, const unsigned int (*data)[2], unsigned char num)
+{
+ int ret = -1;
+ char wid_req[255];
+ unsigned short wid_req_len = 4 + 14*num;
+ char wid_rsp[32];
+ unsigned short wid_rsp_len = 32;
+ unsigned short wid;
+ char wid_msg_id = priv->wid_msg_id++;
+ char count = 0, *p_wid_req = NULL;
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_DEBUG,
+ "%s <<< \n", __func__);
+
+ 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(p_wid_req + 3, (char*)&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(p_wid_req + 10, (char*)&data[count][1], 4);
+ p_wid_req += 14;
+ }
+ ret = rda5890_wid_request_polling(priv, wid_req, wid_req_len, wid_rsp, &wid_rsp_len);
+ if (ret) {
+ RDA5890_ERRP("rda5890_set_sdio_core_init fail, ret = %d\n", ret);
+ goto out;
+ }
+
+out:
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_DEBUG,
+ "%s >>> \n", __func__);
+ return ret;
+}
+
+int rda5890_set_core_init(struct rda5890_private *priv, const unsigned int (*data)[2], unsigned char num)
+{
+ int ret = -1;
+ char wid_req[255];
+ unsigned short wid_req_len = 4 + 14*num;
+ char wid_rsp[32];
+ unsigned short wid_rsp_len = 32;
+ unsigned short wid;
+ char wid_msg_id = priv->wid_msg_id++;
+ char count = 0, *p_wid_req = NULL;
+
+ 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(p_wid_req + 3, (char*)&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(p_wid_req + 10, (char*)&data[count][1], 4);
+ p_wid_req += 14;
+ }
+ ret = rda5890_wid_request(priv, wid_req, wid_req_len, wid_rsp, &wid_rsp_len);
+ if (ret) {
+ RDA5890_ERRP("rda5890_set_sdio_core_init fail, ret = %d\n", ret);
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+int rda5890_set_core_patch_polling(struct rda5890_private *priv, const unsigned char (*patch)[2], unsigned char num)
+{
+ int ret;
+ char wid_req[255];
+ unsigned short wid_req_len = 4 + 8*num;
+ char wid_rsp[32];
+ unsigned short wid_rsp_len = 32;
+ unsigned short wid;
+ char wid_msg_id = priv->wid_msg_id++;
+ char count = 0 , *p_wid_req = NULL;
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_DEBUG,
+ "%s <<< \n", __func__);
+
+ 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] = 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] = patch[count][1];
+ p_wid_req += 8;
+ }
+ ret = rda5890_wid_request_polling(priv, wid_req, wid_req_len, wid_rsp, &wid_rsp_len);
+ if (ret) {
+ RDA5890_ERRP("rda5890_set_core_patch fail, ret = %d \n", ret);
+ goto out;
+ }
+
+out:
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_DEBUG,
+ "%s >>> \n", __func__);
+ return ret;
+}
+
+int rda5890_set_core_patch(struct rda5890_private *priv, const unsigned char (*patch)[2], unsigned char num)
+{
+ int ret;
+ char wid_req[255];
+ unsigned short wid_req_len = 4 + 8*num;
+ char wid_rsp[32];
+ unsigned short wid_rsp_len = 32;
+ unsigned short wid;
+ char wid_msg_id = priv->wid_msg_id++;
+ char count = 0 , *p_wid_req = NULL;
+
+ 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] = 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] = patch[count][1];
+ p_wid_req += 8;
+ }
+ ret = rda5890_wid_request(priv, wid_req, wid_req_len, wid_rsp, &wid_rsp_len);
+ if (ret) {
+ RDA5890_ERRP("rda5890_set_core_patch fail, ret = %d \n", ret);
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+
+int rda5890_get_fw_ver(struct rda5890_private *priv, unsigned long *fw_ver)
+{
+ int ret;
+
+ ret = rda5890_generic_get_ulong(priv, WID_SYS_FW_VER, fw_ver);
+ if (ret) {
+ goto out;
+ }
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_TRACE,
+ "Get FW_VER 0x%08lx\n", *fw_ver);
+
+out:
+ return ret;
+}
+
+int rda5890_get_mac_addr(struct rda5890_private *priv, unsigned char *mac_addr)
+{
+ int ret;
+
+ ret = rda5890_generic_get_str(priv, WID_MAC_ADDR, mac_addr, ETH_ALEN);
+ if (ret) {
+ goto out;
+ }
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_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;
+}
+
+/* support only one bss per packet for now */
+int rda5890_get_scan_results(struct rda5890_private *priv,
+ struct rda5890_bss_descriptor *bss_desc)
+{
+ int ret;
+ int count = 0;
+ unsigned char len;
+ unsigned char buf[sizeof(struct rda5890_bss_descriptor)*RDA5890_MAX_NETWORK_NUM + 2];
+ unsigned char first_send = 0;
+
+ ret = rda5890_get_str_unknown_len(priv, WID_SITE_SURVEY_RESULTS,
+ buf, &len);
+ if (ret) {
+ return ret;
+ }
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_TRACE,
+ "Get Scan Result, len = %d\n", len);
+
+ if ((len - 2) % sizeof(struct rda5890_bss_descriptor)) {
+ RDA5890_ERRP("Scan Result len not correct, %d\n", len);
+ return -EINVAL;
+ }
+
+ count = (len - 2) / sizeof(struct rda5890_bss_descriptor);
+
+ first_send = *(buf + 1);
+ memcpy(bss_desc, buf + 2, (len - 2));
+
+ return (count | first_send << 8);
+}
+
+int rda5890_get_bssid(struct rda5890_private *priv, unsigned char *bssid)
+{
+ int ret;
+
+ ret = rda5890_generic_get_str(priv, WID_BSSID, bssid, ETH_ALEN);
+ if (ret) {
+ goto out;
+ }
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_TRACE,
+ "Get BSSID [%02x:%02x:%02x:%02x:%02x:%02x]\n",
+ bssid[0], bssid[1], bssid[2],
+ bssid[3], bssid[4], bssid[5]);
+out:
+ return ret;
+}
+
+int rda5890_get_channel(struct rda5890_private *priv, unsigned char *channel)
+{
+ int ret;
+
+ ret = rda5890_generic_get_uchar(priv, WID_CURRENT_CHANNEL, channel);
+ if (ret) {
+ goto out;
+ }
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_TRACE,
+ "Get Channel %d\n", *channel);
+
+out:
+ return ret;
+}
+
+int rda5890_get_rssi(struct rda5890_private *priv, unsigned char *rssi)
+{
+ int ret;
+
+ *rssi = 0;
+ ret = rda5890_generic_get_uchar(priv, WID_RSSI, rssi);
+ if (ret) {
+ goto out;
+ }
+
+
+ if(priv->connect_status == MAC_CONNECTED)
+ {
+ if(*rssi > 215)
+ {
+ rda5890_rssi_up_to_200(priv);
+ }
+ else
+ {
+ rda5890_sdio_set_notch_by_channel(priv, priv->curbssparams.channel);
+ }
+ }
+ else
+ *rssi = 0;
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_TRACE,
+ "Get RSSI <<< %d\n", *(char*)rssi);
+
+out:
+ return ret;
+}
+
+int rda5890_set_mac_addr(struct rda5890_private *priv, unsigned char *mac_addr)
+{
+ int ret;
+
+ ret = rda5890_generic_set_str(priv, WID_MAC_ADDR, mac_addr, ETH_ALEN);
+ if (ret) {
+ goto out;
+ }
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_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 rda5890_set_preamble(struct rda5890_private *priv, unsigned char preamble)
+{
+ int ret;
+
+ ret = rda5890_generic_set_uchar(priv, WID_PREAMBLE, preamble);
+ if (ret) {
+ goto out;
+ }
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_TRACE, "rda5890_set_preamble \n");
+out:
+ return ret;
+}
+
+#ifdef GET_SCAN_FROM_NETWORK_INFO
+
+int rda5890_set_scan_complete(struct rda5890_private *priv)
+{
+ int ret;
+
+ ret = rda5890_generic_set_uchar(priv, WID_NETWORK_INFO_EN, 0);
+ if (ret) {
+ goto out;
+ }
+
+out:
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_TRACE, "rda5890_set_scan_complete ret=%d \n", ret);
+ return ret;
+}
+#endif
+
+int rda5890_set_ssid(struct rda5890_private *priv,
+ unsigned char *ssid, unsigned char ssid_len)
+{
+ int ret;
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_TRACE,
+ "Set SSID: %s, len = %d\n", ssid, ssid_len);
+
+ ret = rda5890_generic_set_str(priv, WID_SSID, ssid, ssid_len);
+ if (ret) {
+ goto out;
+ }
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_TRACE,
+ "Set SSID Done\n");
+
+out:
+ return ret;
+}
+
+int rda5890_get_ssid(struct rda5890_private *priv,
+ unsigned char *ssid, unsigned char *ssid_len)
+{
+ int ret;
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_TRACE,
+ "Get SSID \n");
+
+ ret = rda5890_get_str_unknown_len(priv, WID_SSID, ssid, ssid_len);
+ if(*ssid_len > 0)
+ ssid[*ssid_len] = '\0';
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_TRACE,
+ "Get SSID Done len:%d %s\n", *ssid_len, *ssid_len > 0? ssid:"NULL");
+out:
+ return ret;
+}
+int rda5890_set_bssid(struct rda5890_private *priv, unsigned char *bssid)
+{
+ int ret;
+
+ ret = rda5890_generic_set_str(priv, WID_BSSID, bssid, ETH_ALEN);
+ if (ret) {
+ goto out;
+ }
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_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 rda5890_set_imode(struct rda5890_private *priv, unsigned char imode)
+{
+ int ret;
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_TRACE,
+ "Set IMode 0x%02x\n", imode);
+
+ ret = rda5890_generic_set_uchar(priv, WID_802_11I_MODE, imode);
+ if (ret) {
+ goto out;
+ }
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_TRACE,
+ "Set IMode Done\n");
+
+out:
+ return ret;
+}
+
+int rda5890_set_authtype(struct rda5890_private *priv, unsigned char authtype)
+{
+ int ret;
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_TRACE,
+ "Set AuthType 0x%02x\n", authtype);
+
+ ret = rda5890_generic_set_uchar(priv, WID_AUTH_TYPE, authtype);
+ if (ret) {
+ goto out;
+ }
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_TRACE,
+ "Set AuthType Done\n");
+
+out:
+ return ret;
+}
+
+int rda5890_set_listen_interval(struct rda5890_private *priv, unsigned char interval)
+{
+ int ret;
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_TRACE,
+ "Set rda5890_set_listen_interval 0x%02x\n", interval);
+
+ ret = rda5890_generic_set_uchar(priv, WID_LISTEN_INTERVAL, interval);
+ if (ret) {
+ goto out;
+ }
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_TRACE,
+ "Set rda5890_set_listen_interval Done\n");
+
+out:
+ return ret;
+}
+
+int rda5890_set_link_loss_threshold(struct rda5890_private *priv, unsigned char threshold)
+{
+ int ret;
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_TRACE,
+ "Set rda5890_set_link_loss_threshold 0x%02x\n", threshold);
+
+ ret = rda5890_generic_set_uchar(priv, WID_LINK_LOSS_THRESHOLD, threshold);
+ if (ret) {
+ goto out;
+ }
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_TRACE,
+ "Set rda5890_set_link_loss_threshold Done\n");
+
+out:
+ return ret;
+}
+
+
+int rda5890_set_wepkey(struct rda5890_private *priv,
+ unsigned short index, unsigned char *key, unsigned char key_len)
+{
+ int ret;
+ unsigned char key_str[26 + 1]; // plus 1 for debug print
+ unsigned char 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 {
+ RDA5890_ERRP("Error in WEP Key length %d\n", key_len);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_TRACE,
+ "Set WEP KEY[%d]: %s\n", index, key_str);
+
+ ret = rda5890_generic_set_str(priv,
+ (WID_WEP_KEY_VALUE0 + index), key_str, key_str_len);
+ if (ret) {
+ goto out;
+ }
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_TRACE,
+ "Set WEP KEY[%d] Done\n", index);
+
+out:
+ return ret;
+}
+
+static void dump_key(unsigned char *key, unsigned char key_len)
+{
+ RDA5890_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]);
+ RDA5890_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)
+ RDA5890_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)
+ RDA5890_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 rda5890_set_ptk(struct rda5890_private *priv,
+ unsigned char *key, unsigned char key_len)
+{
+ int ret;
+ unsigned char key_str[32 + ETH_ALEN + 1];
+ unsigned char key_str_len = key_len + ETH_ALEN + 1;
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_TRACE,
+ "Set PTK: len = %d\n", key_len);
+ if (RDA5890_DBGLA(RDA5890_DA_WID, RDA5890_DL_VERB))
+ dump_key(key, key_len);
+
+ if (priv->connect_status != MAC_CONNECTED) {
+ RDA5890_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, rda5890 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 = rda5890_generic_set_str(priv,
+ WID_ADD_WAPI_PTK, key_str, key_str_len);
+ else
+ ret = rda5890_generic_set_str(priv,
+ WID_ADD_PTK, key_str, key_str_len);
+ if (ret) {
+ goto out;
+ }
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_TRACE,
+ "Set PTK Done\n");
+
+out:
+ return ret;
+}
+
+int rda5890_set_gtk(struct rda5890_private *priv, unsigned char key_id,
+ unsigned char *key_rsc, unsigned char key_rsc_len,
+ unsigned char *key, unsigned char key_len)
+{
+ int ret;
+ unsigned char key_str[32 + ETH_ALEN + 8 + 2];
+ unsigned char 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 */
+ /*-------------------------------------*/
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_TRACE,
+ "Set GTK: len = %d\n", key_len);
+ if (RDA5890_DBGLA(RDA5890_DA_WID, RDA5890_DL_VERB))
+ dump_key(key, key_len);
+
+ if (priv->connect_status != MAC_CONNECTED) {
+ RDA5890_ERRP("Adding PTK 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, rda5890 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 = rda5890_generic_set_str(priv,
+ WID_ADD_WAPI_RX_GTK, key_str, key_str_len);
+ else
+ ret = rda5890_generic_set_str(priv,
+ WID_ADD_RX_GTK, key_str, key_str_len);
+ if (ret) {
+ goto out;
+ }
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_TRACE,
+ "Set GTK Done\n");
+
+out:
+ return ret;
+}
+
+int rda5890_set_scan_timeout(struct rda5890_private *priv)
+{
+ int ret;
+ char wid_req[14];
+ unsigned short wid_req_len = 19;
+ char wid_rsp[32];
+ unsigned short wid_rsp_len = 32;
+ char wid_msg_id = priv->wid_msg_id++;
+ char *ptr_payload;
+ unsigned short wid = 0;
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_TRACE,
+ "rda5890_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] = 50; //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] = 50; //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] = 50; //50 ms one channel
+ wid_req[18] = 0;
+
+ ret = rda5890_wid_request(priv, wid_req, wid_req_len, wid_rsp, &wid_rsp_len);
+ if (ret) {
+ RDA5890_ERRP("rda5890_set_scan_timeout fail, ret = %d\n", ret);
+ goto out;
+ }
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_TRACE,
+ "rda5890_set_scan_timeout >>> \n");
+
+out:
+ return ret;
+}
+
+
+int rda5890_set_pm_mode(struct rda5890_private *priv, unsigned char pm_mode)
+{
+ int ret;
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_TRACE,
+ "Set PM Mode 0x%02x\n", pm_mode);
+
+ ret = rda5890_generic_set_uchar(priv, WID_POWER_MANAGEMENT, pm_mode);
+ if (ret) {
+ goto out;
+ }
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_TRACE,
+ "Set PM Mode Done\n");
+
+out:
+ return ret;
+}
+
+int rda5890_set_preasso_sleep(struct rda5890_private *priv, unsigned int preasso_sleep)
+{
+ int ret;
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_TRACE,
+ "Set Preasso Sleep 0x%08x\n", preasso_sleep);
+
+ ret = rda5890_generic_set_ulong(priv, WID_PREASSO_SLEEP, preasso_sleep);
+ if (ret) {
+ goto out;
+ }
+
+ RDA5890_DBGLAP(RDA5890_DA_WID, RDA5890_DL_TRACE,
+ "Set Preasso Sleep Done\n");
+
+out:
+ return ret;
+}
+
--- /dev/null
+#ifndef _RDA5890_WID_H_
+#define _RDA5890_WID_H_
+
+#define MAX_STRING_LEN 256
+#define MAX_CMD_LEN MAX_STRING_LEN
+#define RDA5890_MAX_WID_LEN MAX_CMD_LEN - 2
+
+#define MAC_CONNECTED 1
+#define MAC_DISCONNECTED 0
+
+#define WID_STATUS_SUCCESS 1
+
+typedef enum
+{
+ G_SHORT_PREAMBLE = 0,
+ G_LONG_PREAMBLE = 1,
+ G_AUTO_PREAMBLE = 2
+}G_PREAMBLE_T;
+
+/* 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_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_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,
+ WID_ALL = 0x7FFE,
+ WID_MAX = 0xFFFF
+} WID_T;
+
+int rda5890_wid_request(struct rda5890_private *priv,
+ char *wid_req, unsigned short wid_req_len,
+ char *wid_rsp, unsigned short *wid_rsp_len);
+
+void rda5890_wid_response(struct rda5890_private *priv,
+ char *wid_rsp, unsigned short wid_rsp_len);
+
+void rda5890_wid_status(struct rda5890_private *priv,
+ char *wid_status, unsigned short wid_status_len);
+
+
+void rda5890_card_to_host(struct rda5890_private *priv,
+ char *packet, unsigned short packet_len);
+
+int rda5890_start_scan(struct rda5890_private *priv);
+int rda5890_start_scan_enable_network_info(struct rda5890_private *priv);
+int rda5890_start_join(struct rda5890_private *priv);
+
+int rda5890_get_fw_ver(struct rda5890_private *priv, unsigned long *fw_ver);
+int rda5890_get_mac_addr(struct rda5890_private *priv, unsigned char *mac_addr);
+int rda5890_get_scan_results(struct rda5890_private *priv,
+ struct rda5890_bss_descriptor *bss_desc);
+int rda5890_get_bssid(struct rda5890_private *priv, unsigned char *bssid);
+int rda5890_set_bssid(struct rda5890_private *priv, unsigned char *bssid);
+
+int rda5890_get_channel(struct rda5890_private *priv, unsigned char *channel);
+int rda5890_get_rssi(struct rda5890_private *priv, unsigned char *rssi);
+
+int rda5890_set_mac_addr(struct rda5890_private *priv, unsigned char *mac_addr);
+int rda5890_set_preamble(struct rda5890_private *priv, unsigned char preamble);
+
+int rda5890_set_ssid(struct rda5890_private *priv,
+ unsigned char *ssid, unsigned char ssid_len);
+int rda5890_get_ssid(struct rda5890_private *priv,
+ unsigned char *ssid, unsigned char *ssid_len);
+int rda5890_set_imode(struct rda5890_private *priv, unsigned char imode);
+int rda5890_set_authtype(struct rda5890_private *priv, unsigned char authtype);
+int rda5890_set_listen_interval(struct rda5890_private *priv, unsigned char interval);
+int rda5890_set_link_loss_threshold(struct rda5890_private *priv, unsigned char threshold);
+int rda5890_set_wepkey(struct rda5890_private *priv,
+ unsigned short index, unsigned char *key, unsigned char key_len);
+int rda5890_set_ptk(struct rda5890_private *priv,
+ unsigned char *key, unsigned char key_len);
+int rda5890_set_gtk(struct rda5890_private *priv, unsigned char key_id,
+ unsigned char *key_rsc, unsigned char key_rsc_len,
+ unsigned char *key, unsigned char key_len);
+
+int rda5890_set_pm_mode(struct rda5890_private *priv, unsigned char pm_mode);
+int rda5890_set_preasso_sleep(struct rda5890_private *priv, unsigned int preasso_sleep);
+
+int rda5890_generic_get_str(struct rda5890_private *priv,
+ unsigned short wid, unsigned char *val, unsigned char len);
+int rda5890_generic_set_str(struct rda5890_private *priv,
+ unsigned short wid, unsigned char *val, unsigned char len);
+
+int rda5890_generic_set_uchar(struct rda5890_private *priv,
+ unsigned short wid, unsigned char val);
+int rda5890_generic_get_ushort(struct rda5890_private *priv,
+ unsigned short wid, unsigned short *val);
+int rda5890_generic_set_ushort(struct rda5890_private *priv,
+ unsigned short wid, unsigned short val);
+
+int rda5890_generic_set_ulong(struct rda5890_private *priv,
+ unsigned short wid, unsigned long val);
+int rda5890_generic_get_ulong(struct rda5890_private *priv,
+ unsigned short wid, unsigned long *val);
+
+int rda5890_set_core_init(struct rda5890_private *priv, const unsigned int (*data)[2], unsigned char num);
+int rda5890_set_core_patch(struct rda5890_private *priv, const unsigned char (*patch)[2], unsigned char num);
+int rda5890_set_core_init_polling(struct rda5890_private *priv, const unsigned int (*data)[2], unsigned char num);
+int rda5890_set_core_patch_polling(struct rda5890_private *priv, const unsigned char (*patch)[2], unsigned char num);
+int rda5890_set_scan_timeout(struct rda5890_private *priv);
+
+int rda5890_set_txrate(struct rda5890_private *priv, unsigned char mbps);
+#ifdef GET_SCAN_FROM_NETWORK_INFO
+
+int rda5890_set_scan_complete(struct rda5890_private *priv);
+#endif
+int rda5890_wid_request_polling(struct rda5890_private *priv,
+ char *wid_req, unsigned short wid_req_len,
+ char *wid_rsp, unsigned short *wid_rsp_len);
+int rda5890_check_wid_response(char *wid_rsp, unsigned short wid_rsp_len,
+ unsigned short wid, char wid_msg_id,
+ char payload_len, char **ptr_payload);
+#endif
+