T3 Android4.4平台的XR829的移植和XR819模块的兼容

13 篇文章 0 订阅
10 篇文章 0 订阅

一、电路原理和内核部分的配置

1、电路原理

 

其中,管脚连接如下:

电路连接管脚:
WIFI部分:
wlan_power----dldo2(3.3V)
wlan_io_regulator----dldo3(3.3V)
WIFI_PDn(wlan_on)-----PA04(GPIO)
WIFI_IRQ(wlan_hostwake)----PH18(GPIO)
SDIO使用SDIO3

BT部分:
UART口使用UART1
AP_WAKE_BT(bt_hostwake)-----PB10(GPIO)
GOC-BC8_EN(bt_rst_n)--------PA16(GPIO)
bt_power   ------------dldo1(3.3V)

2、系统管脚和电源配置:

lichee\tools\pack\chips\sun8iw11p1\configs\x217\sys_config.fex
......................................................
;UART1口的配置
[uart1]
uart1_used       = 1
uart1_port       = 1
uart1_type       = 4
uart1_tx         = port:PA10<4><1><default><default>
uart1_rx         = port:PA11<4><1><default><default>
uart1_rts        = port:PA12<4><1><default><default>
uart1_cts        = port:PA13<4><1><default><default>
uart1_dtr        =
uart1_dsr        =
uart1_dcd        =
uart1_ring       =

[uart1_suspend]
uart1_tx         = port:PA10<7><1><default><default>
uart1_rx         = port:PA11<7><1><default><default>
uart1_rts        = port:PA12<7><1><default><default>
uart1_cts        = port:PA13<7><1><default><default>
uart1_dtr        =
uart1_dsr        =
uart1_dcd        =
uart1_ring       =
....................................................
;SDIO3的配置
[sdc3]
sdc3_used          = 1
;non-removable	= 1
bus-width	 = 4
sdc3_clk           = port:PI05<2><1><2><default>
sdc3_cmd           = port:PI04<2><1><2><default>
sdc3_d0            = port:PI06<2><1><2><default>
sdc3_d1            = port:PI07<2><1><2><default>
sdc3_d2            = port:PI08<2><1><2><default>
sdc3_d3            = port:PI09<2><1><2><default>

;cd-gpios	   =
ctl-spec-caps      = 0x1
sunxi-power-save-mode =
sunxi-dis-signal-vol-sw =
;sunxi-power-save-mode =
;sd-uhs-sdr50			=
;sd-uhs-ddr50			=
;sd-uhs-sdr104			=
cap-sdio-irq			=
keep-power-in-suspend	=
ignore-pm-notify	=
;max-frequency	   = 150000000
min-frequency	   = 150000
......................................
............................................
;--------------------------------------------------------------------------------
;接口GPIO和电源配置
;wlan configuration
;wlan_used:         0-not use, 1- use
;wlan_busnum:       sdio/usb index
;clocks:            external low power clock input (32.768KHz)
;wlan_power:        input supply voltage
;wlan_io_regulator: wlan/sdio I/O voltage
;wlan_regon:        power up/down internal regulators used by wifi section
;wlan_hostwake:     wlan to wake-up host
;wlan_clk_gpio:     wlan low power clock output pin
;--------------------------------------------------------------------------------
[wlan]
wlan_used           = 1
wlan_busnum         = 3
;clocks             = "&clk_outa"
wlan_power          = "vcc-wifi"
wlan_io_regulator   = "vcc-wifi-ext"
wlan_18_power1      = "vcc-wifi-18"
wlan_18_power2      = "vdd-sata-12"
wlan_regon          = port:PA04<1><default><default><0>
wlan_hostwake       = port:PH18<6><default><default><0>
wlan_clk_gpio       =

;--------------------------------------------------------------------------------
;bluetooth configuration
;bt_used:           0- no used, 1- used
;clocks:            external low power clock input (32.768KHz)
;bt_power:          input supply voltage
;bt_io_regulator:   bluetooth I/O voltage
;bt_rst_n:          power up/down internal regulators used by BT section
;--------------------------------------------------------------------------------
[bt]
bt_used             = 1
;clocks             = "&clk_outa"
bt_power            = "vcc-io-wifi"
bt_io_regulator     = "vcc-io-wifi"
bt_rst_n            = port:PA16<1><0><default><0>
bt_ldo_en           = port:PA16<1><0><default><0>
ap_wakeup_bt        = port:PB10<1><default><1><0>

3、上电时序重新编写

WIFI上电时序(具体使用请参考T7 android8.1平台的WIFI部分的上电时序程序说明):
lichee\linux-3.10\drivers\misc\sunxi-rf\sunxi-wlan-xr829.c
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/err.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/of_gpio.h>
#include <linux/clk.h>
#include <linux/interrupt.h>
#include <linux/rfkill.h>
#include <linux/regulator/consumer.h>
#include <linux/platform_device.h>
#include <linux/sys_config.h>
#include <linux/if_ether.h>
#include <linux/etherdevice.h>
#include <linux/crypto.h>
#include <linux/err.h>
#include <linux/scatterlist.h>
#include <linux/pinctrl/pinconf-sunxi.h>
#include <linux/pm_runtime.h>
#include <mach/sw-board-ctrl.h>

struct sunxi_wlan_platdata {
	int bus_index;
	struct regulator *wlan_power;
	struct regulator *wlan_power_ext;
	struct regulator *io_regulator;
	struct regulator *wlan_18_power1;
	struct regulator *wlan_18_power2;
	struct clk 	*lpo;
	int gpio_wlan_regon;
	int gpio_wlan_hostwake;

	char *wlan_power_name;
	char *wlan_power_ext_name;
	char *io_regulator_name;
	char *wlan_18_power1_name;
	char *wlan_18_power2_name;

	int power_state;
	int enable_state;
	int power_flag;
	struct platform_device *pdev;
};
static struct sunxi_wlan_platdata *wlan_data = NULL;

static int hw_ver = 0x0;
static int g_wifi_module = 0;  //default xradio
static int sunxi_wlan_on(struct sunxi_wlan_platdata *data, bool on_off);
static int sunxi_wlan_enable(struct sunxi_wlan_platdata *data, bool enable);
static DEFINE_MUTEX(sunxi_wlan_mutex);

u8  wlan_power = 0;
void sunxi_wlan_set_enable(bool enable)
{
	struct platform_device *pdev;
	int ret = 0;
	if (!wlan_data)
		return;

	pdev = wlan_data->pdev;
	mutex_lock(&sunxi_wlan_mutex);
	if (enable != wlan_data->enable_state) {
		ret = sunxi_wlan_enable(wlan_data, enable);
		if (ret)
			dev_err(&pdev->dev, "set enable failed\n");
	}
	mutex_unlock(&sunxi_wlan_mutex);
	wlan_power = enable;
	dev_info(&pdev->dev,"%s,%d\n",__func__,enable);
}
EXPORT_SYMBOL(wlan_power);
EXPORT_SYMBOL_GPL(sunxi_wlan_set_enable);

void sunxi_wlan_set_power(bool on_off)
{
	struct platform_device *pdev;
	int ret = 0;
	if (!wlan_data)
		return;

	pdev = wlan_data->pdev;
	mutex_lock(&sunxi_wlan_mutex);
	if(on_off != wlan_data->power_state){
		ret = sunxi_wlan_on(wlan_data, on_off);
		if(ret)
			dev_err(&pdev->dev,"set power failed\n");
	}
	mutex_unlock(&sunxi_wlan_mutex);
}
EXPORT_SYMBOL_GPL(sunxi_wlan_set_power);

//nwd-wangtao add for recognize wifi module
void sunxi_wlan_set_module(int flag)
{
	printk("nwd-wangtao set wifi module : %s\n", flag?"xr829":"xradio");
	g_wifi_module = flag;
}
EXPORT_SYMBOL_GPL(sunxi_wlan_set_module);

int sunxi_wlan_get_bus_index(void)
{
	struct platform_device *pdev;
	if (!wlan_data)
		return -EINVAL;

	pdev = wlan_data->pdev;
	dev_info(&pdev->dev,"bus_index: %d\n",wlan_data->bus_index);
	return wlan_data->bus_index;
}
EXPORT_SYMBOL_GPL(sunxi_wlan_get_bus_index);

int sunxi_wlan_get_oob_irq(void)
{
	struct platform_device *pdev;
	int host_oob_irq = 0;
	if (!wlan_data || !gpio_is_valid(wlan_data->gpio_wlan_hostwake))
		return 0;

	pdev = wlan_data->pdev;
	host_oob_irq = gpio_to_irq(wlan_data->gpio_wlan_hostwake);
	if (IS_ERR_VALUE(host_oob_irq)) 
		dev_err(&pdev->dev,"map gpio [%d] to virq failed, errno = %d\n",
			wlan_data->gpio_wlan_hostwake,host_oob_irq);

	return host_oob_irq;
}
EXPORT_SYMBOL_GPL(sunxi_wlan_get_oob_irq);

int sunxi_wlan_get_oob_irq_flags(void)
{
	int oob_irq_flags;
	if (!wlan_data)
		return 0;

	oob_irq_flags = (IRQF_TRIGGER_HIGH | IRQF_SHARED | IRQF_NO_SUSPEND);

	return oob_irq_flags;
}
EXPORT_SYMBOL_GPL(sunxi_wlan_get_oob_irq_flags);

static int sunxi_wlan_enable(struct sunxi_wlan_platdata *data, bool enable)
{
	struct platform_device *pdev = data->pdev;
	struct device *dev = &pdev->dev;

	if (gpio_is_valid(data->gpio_wlan_regon)) {
		if (enable) {
			gpio_direction_output(data->gpio_wlan_regon, 1);
		} else {
			gpio_direction_output(data->gpio_wlan_regon, 0);
		}
		dev_info(dev, "set wlan enable: %s\n", enable ? "1" : "0");
	}
	wlan_data->enable_state = enable;
	return 0;
}

static int sunxi_wlan_on(struct sunxi_wlan_platdata *data, bool on_off)
{
	struct platform_device *pdev = data->pdev;
	struct device *dev = &pdev->dev;
	int ret = 0;

	if(data->wlan_power_name){
		data->wlan_power = regulator_get(dev, data->wlan_power_name);
		if (!IS_ERR(data->wlan_power)) {
			if(on_off){
				ret = regulator_enable(data->wlan_power);
				if (ret < 0){
					dev_err(dev, "regulator wlan_power enable failed\n");
					regulator_put(data->wlan_power);
					return ret;
				}

				ret = regulator_get_voltage(data->wlan_power);
				if (ret < 0){
					dev_err(dev, "regulator wlan_power get voltage failed\n");
					regulator_put(data->wlan_power);
					return ret;
				}
				dev_info(dev, "check wlan wlan_power voltage: %d\n",ret);
			}else{
				ret = regulator_disable(data->wlan_power);
				if (ret < 0){
					dev_err(dev, "regulator wlan_power disable failed\n");
					regulator_put(data->wlan_power);
					return ret;
				}
			}
			regulator_put(data->wlan_power);
		}
	}

	if(data->wlan_power_ext_name){
		data->wlan_power_ext = regulator_get(dev, data->wlan_power_ext_name);
		if (!IS_ERR(data->wlan_power_ext)) {
			if(on_off){
				ret = regulator_enable(data->wlan_power_ext);
				if (ret < 0){
					dev_err(dev, "regulator wlan_power_ext enable failed\n");
					regulator_put(data->wlan_power_ext);
					//return ret;
				}

				ret = regulator_get_voltage(data->wlan_power_ext);
				if (ret < 0){
					dev_err(dev, "regulator wlan_power_ext get voltage failed\n");
					regulator_put(data->wlan_power_ext);
					//return ret;
				}
				dev_err(dev, "check wlan wlan_power_ext voltage: %d\n",ret);
			}else{
				ret = regulator_disable(data->wlan_power_ext);
				if (ret < 0){
					dev_err(dev, "regulator wlan_power_ext disable failed\n");
					regulator_put(data->wlan_power_ext);
					//return ret;
				}
			}
			regulator_put(data->wlan_power_ext);
		}
	}

	if(data->io_regulator_name){
		data->io_regulator = regulator_get(dev, data->io_regulator_name);
		if (!IS_ERR(data->io_regulator)) {
			if(on_off){
				ret = regulator_enable(data->io_regulator);
				if (ret < 0){
					dev_err(dev, "regulator io_regulator enable failed\n");
					regulator_put(data->io_regulator);
					return ret;
				}

				ret = regulator_get_voltage(data->io_regulator);
				if (ret < 0){
					dev_err(dev, "regulator io_regulator get voltage failed\n");
					regulator_put(data->io_regulator);
					return ret;
				}
				dev_info(dev, "check wlan io_regulator voltage: %d\n",ret);
			}else{
				ret = regulator_disable(data->io_regulator);
				if (ret < 0){
					dev_err(dev, "regulator io_regulator disable failed\n");
					regulator_put(data->io_regulator);
					return ret;
				}
			}
			regulator_put(data->io_regulator);
		}
	}

	if (hw_ver == HW_VER_V1_0 || hw_ver == HW_VER_V4_0) {
		if (data->wlan_18_power1_name) {
			data->wlan_18_power1 = regulator_get(dev,
					data->wlan_18_power1_name);
			if (!IS_ERR(data->wlan_18_power1)) {
				if (on_off) {
					if(1 == g_wifi_module)
					{
						regulator_set_voltage(data->wlan_18_power1,
								(int)3300*1000,
								(int)3300*1000);
					}
					else if(0 == g_wifi_module)
					{
						regulator_set_voltage(data->wlan_18_power1,
								(int)1800*1000,
								(int)1800*1000);
					}
					ret = regulator_enable(data->wlan_18_power1);
					if (ret < 0) {
						dev_err(dev, "regulator wlan_18_power1 enable "
								"failed\n");
						regulator_put(data->wlan_18_power1);
						return ret;
					}
					ret = regulator_get_voltage(data->wlan_18_power1);
					if (ret < 0) {
						dev_err(dev, "regulator wlan_18_power1 get voltage "
								"failed\n");
						regulator_put(data->wlan_18_power1);
						return ret;
					}
					dev_info(dev, "check wlan wlan_18_power1 voltage: %d\n",
							ret);
				} else {
					ret = regulator_disable(data->wlan_18_power1);
					if (ret < 0) {
						dev_err(dev, "regulator wlan_18_power1 disable "
								"failed\n");
						regulator_put(data->wlan_18_power1);
						return ret;
					}
				}
				regulator_put(data->wlan_18_power1);
			}
		}
		if (data->wlan_18_power2_name) {
			data->wlan_18_power2 = regulator_get(dev,
					data->wlan_18_power2_name);
			if (!IS_ERR(data->wlan_18_power2)) {
				if (on_off) {
					regulator_set_voltage(data->wlan_18_power2,
							(int)1800*1000,
							(int)1800*1000);
					ret = regulator_enable(data->wlan_18_power2);
					if (ret < 0) {
						dev_err(dev, "regulator wlan_18_power2 enable "
								"failed\n");
						regulator_put(data->wlan_18_power2);
						return ret;
					}
					ret = regulator_get_voltage(data->wlan_18_power2);
					if (ret < 0) {
						dev_err(dev, "regulator wlan_18_power2 get voltage "
								"failed\n");
						regulator_put(data->wlan_18_power2);
						return ret;
					}
					dev_info(dev, "check wlan wlan_18_power2 voltage: %d\n",
							ret);
				} else {
					ret = regulator_disable(data->wlan_18_power2);
					if (ret < 0) {
						dev_err(dev, "regulator wlan_18_power2 disable "
								"failed\n");
						regulator_put(data->wlan_18_power2);
						return ret;
					}
				}
				regulator_put(data->wlan_18_power2);
			}
		}
	}

	wlan_data->power_state = on_off;

	return 0;
}

static ssize_t power_state_show(struct device *dev,
	struct device_attribute *attr, char *buf)
{
	return sprintf(buf, "%d\n", wlan_data->power_state);
}

static ssize_t power_state_store(struct device *dev,
	struct device_attribute *attr, const char *buf, size_t count)
{
	unsigned long state;
	int err;

	if (!capable(CAP_NET_ADMIN))
		return -EPERM;

	err = kstrtoul(buf, 0, &state);
	if (err)
		return err;

	if (state > 1 )
		return -EINVAL;

	mutex_lock(&sunxi_wlan_mutex);
	if(state != wlan_data->power_state){
		err = sunxi_wlan_on(wlan_data, state);
		if(err)
			dev_err(dev,"set power failed\n");
	}
	mutex_unlock(&sunxi_wlan_mutex);

	return count;
}

int wlan_flag = -1;
static ssize_t wlan_flag_show(struct device *dev,
	struct device_attribute *attr, char *buf)
{
	return sprintf(buf, "%d\n", wlan_flag);
}

static ssize_t wlan_flag_store(struct device *dev,
	struct device_attribute *attr, const char *buf, size_t count)
{
	unsigned long state;
	int err;

	err = kstrtoul(buf, 0, &state);
	if(err)
		return err;

	wlan_flag = state;
	dev_info(dev, "%s: wlan_flag:%d\n", __func__, wlan_flag);
	return count;
}
EXPORT_SYMBOL(wlan_flag);

static ssize_t enable_state_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	return sprintf(buf, "%d\n", wlan_data->enable_state);
}

static ssize_t enable_state_store(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t count)
{
	unsigned long state;
	int err;

	if (!capable(CAP_NET_ADMIN))
		return -EPERM;

	err = kstrtoul(buf, 0, &state);
	if (err)
		return err;

	if (state > 1)
		return -EINVAL;

	mutex_lock(&sunxi_wlan_mutex);
	if (state != wlan_data->enable_state) {
		err = sunxi_wlan_enable(wlan_data, state);
		if (err)
			dev_err(dev,"set enable failed\n");
	}
	mutex_unlock(&sunxi_wlan_mutex);

	return count;
}

extern void sunxi_mmc_rescan_card(unsigned ids);
static ssize_t scan_device_store(struct device *dev,
	struct device_attribute *attr, const char *buf, size_t count)
{
	int bus = wlan_data->bus_index;

	dev_info(dev, "start scan device on bus_index: %d\n",
			wlan_data->bus_index);
	if (bus < 0) {
		dev_err(dev, "scan device fail!\n");
		return -1;
	}
	sunxi_mmc_rescan_card(bus);
	return count;
}

extern void sunxi_mmc_remove_sdio(unsigned ids);
static ssize_t remove_card_store(struct device *dev,
	struct device_attribute *attr, const char *buf, size_t count)
{
	int bus = wlan_data->bus_index;

	dev_info(dev, "start remove card on bus_index: %d\n",
			wlan_data->bus_index);
	if (bus < 0) {
		dev_err(dev, "remove card fail!\n");
		return -1;
	}
	sunxi_mmc_remove_sdio(bus);
	return count;
}

static DEVICE_ATTR(power_state, S_IWUSR | S_IWGRP | S_IRUGO,
		power_state_show, power_state_store);
static DEVICE_ATTR(enable_state, S_IWUGO | S_IRUGO,
		enable_state_show, enable_state_store);
static DEVICE_ATTR(scan_device, S_IWUSR | S_IWGRP,
		NULL, scan_device_store);
static DEVICE_ATTR(remove_card, S_IWUSR | S_IWGRP | S_IWOTH,
		NULL, remove_card_store);
static DEVICE_ATTR(power_flag, S_IWUGO | S_IRUGO,
		wlan_flag_show, wlan_flag_store);


static struct attribute *misc_attributes[] = {
	//&dev_attr_power_state.attr,
	&dev_attr_enable_state.attr,
	&dev_attr_scan_device.attr,
	&dev_attr_remove_card.attr,
	&dev_attr_power_flag.attr,
	NULL,
};

static struct attribute_group misc_attribute_group = {
	.name  = "rf-ctrl",
	.attrs = misc_attributes,
};

static struct miscdevice sunxi_wlan_dev = {
	.minor = MISC_DYNAMIC_MINOR,
	.name  = "sunxi-wlan",
};

static char wifi_mac_str[18] = {0};
/*extern int sunxi_get_soc_chipid(uint8_t *chipid);*/
static void sunxi_wlan_chipid_mac_address(u8 *mac)
{
#define MD5_SIZE	16
#define CHIP_SIZE	16

	struct crypto_hash *tfm;
	struct hash_desc desc;
	struct scatterlist sg;
	u8 result[MD5_SIZE];
	u8 chipid[CHIP_SIZE];
	int i = 0;
	int ret = -1;

	memset(chipid, 0, sizeof(chipid));
	memset(result, 0, sizeof(result));

	/*sunxi_get_soc_chipid((u8 *)chipid);*/

	tfm = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC);
	if (IS_ERR(tfm)) {
		pr_err("Failed to alloc md5\n");
		return;
	}
	desc.tfm = tfm;
	desc.flags = 0;

	ret = crypto_hash_init(&desc);
	if (ret < 0) {
		pr_err("crypto_hash_init() failed\n");
		goto out;
	}

	sg_init_one(&sg, chipid, sizeof(chipid) - 1);
	ret = crypto_hash_update(&desc, &sg, sizeof(chipid) - 1);
	if (ret < 0) {
		pr_err("crypto_hash_update() failed for id\n");
		goto out;
	}

	crypto_hash_final(&desc, result);
	if (ret < 0) {
		pr_err("crypto_hash_final() failed for result\n");
		goto out;
	}

	/* Choose md5 result's [0][2][4][6][8][10] byte as mac address */
	for (i = 0; i < 6; i++)
		mac[i] = result[2*i];
	mac[0] &= 0xfe;     /* clear multicast bit */
	mac[0] &= 0xfd;     /* clear local assignment bit (IEEE802) */

out:
	crypto_free_hash(tfm);
}
EXPORT_SYMBOL(sunxi_wlan_chipid_mac_address);

void sunxi_wlan_custom_mac_address(u8 *mac)
{
	char *p = wifi_mac_str;
	u8 mac_addr[ETH_ALEN] = {0};

	if (!strlen(p))
		return;

/*
	kstrtoul(p, 16, mac_addr);
*/

	memcpy(mac, mac_addr, sizeof(mac_addr));
}
EXPORT_SYMBOL(sunxi_wlan_custom_mac_address);

#ifndef MODULE
static int __init set_wlan_mac_addr(char *str)
{
	char *p = str;

	if (str != NULL && *str)
		strlcpy(wifi_mac_str, p, 18);

	return 0;
}
__setup("wifi_mac=", set_wlan_mac_addr);
#endif

static int sunxi_wlan_probe(struct platform_device *pdev)
{
	struct device_node *np = pdev->dev.of_node;
	struct device *dev = &pdev->dev;
	struct sunxi_wlan_platdata *data;
	struct gpio_config config;
	unsigned long pin_config;
	u32 val;
	const char *power,*io_regulator,*power_ext;
	const char *wlan_18_power1, *wlan_18_power2;
	int ret = 0;
	int clk_gpio;
	char pin_name[32];

	hw_ver = get_hw_ver();
	dev_info(dev, "hardware version is (0x%2x)\n", hw_ver);

	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
	if (!dev)
		return -ENOMEM;

	data->pdev = pdev;
	wlan_data = data;

	data->bus_index = -1;
	if (!of_property_read_u32(np, "wlan_busnum", &val)) {
		switch (val) {
		case 0:
		case 1:
		case 2:
		case 3:
			data->bus_index = val;
			break;
		default:
			dev_err(dev, "unsupported wlan_busnum (%u)\n", val);
			return -EINVAL;
		}
	}
	dev_info(dev, "wlan_busnum (%u)\n", val);

	if (of_property_read_string(np, "wlan_power", &power)) {
		dev_warn(dev, "Missing wlan_power.\n");
	}else{
		data->wlan_power_name = devm_kzalloc(dev, 64, GFP_KERNEL);
		if(!data->wlan_power_name)
			return -ENOMEM;
		else
			strcpy(data->wlan_power_name,power);
	}
	dev_info(dev, "wlan_power_name (%s)\n", data->wlan_power_name);
/***************************************************************/	
   if (of_property_read_string(np, "wlan_power_ext", &power_ext)) {
		dev_warn(dev, "Missing wlan_power_ext.\n");
	}else{
		data->wlan_power_ext_name = devm_kzalloc(dev, 64, GFP_KERNEL);
		if(data->wlan_power_ext_name)
			strcpy(data->wlan_power_ext_name,power_ext);

	}
	dev_info(dev, "wlan_power_ext_name (%s)\n", data->wlan_power_ext_name);
/*******************************************************************/
	if (of_property_read_string(np, "wlan_io_regulator", &io_regulator)) {
		dev_warn(dev, "Missing wlan_io_regulator.\n");
	}else{
		data->io_regulator_name = devm_kzalloc(dev, 64, GFP_KERNEL);
		if(!data->io_regulator_name)
			return -ENOMEM;
		else
			strcpy(data->io_regulator_name,io_regulator);
	}
	dev_info(dev, "io_regulator_name (%s)\n", data->io_regulator_name);
/*******************************************************************/
	if (hw_ver == HW_VER_V1_0 || hw_ver == HW_VER_V4_0) {
		if (of_property_read_string(np, "wlan_18_power1", &wlan_18_power1)) {
			dev_warn(dev, "Missing wlan_18_power1.\n");
		}else{
			data->wlan_18_power1_name = devm_kzalloc(dev, 64, GFP_KERNEL);
			if(!data->wlan_18_power1_name)
				return -ENOMEM;
			else
				strcpy(data->wlan_18_power1_name,wlan_18_power1);
		}
		dev_info(dev, "wlan_18_power1_name (%s)\n", data->wlan_18_power1_name);

		if (of_property_read_string(np, "wlan_18_power2", &wlan_18_power2)) {
			dev_warn(dev, "Missing wlan_18_power2.\n");
		}else{
			data->wlan_18_power2_name = devm_kzalloc(dev, 64, GFP_KERNEL);
			if(!data->wlan_18_power2_name)
				return -ENOMEM;
			else
				strcpy(data->wlan_18_power2_name,wlan_18_power2);
		}
		dev_info(dev, "wlan_18_power2_name (%s)\n", data->wlan_18_power2_name);
	}

	data->gpio_wlan_regon = of_get_named_gpio_flags(np, "wlan_regon", 0, (enum of_gpio_flags *)&config);
	if (!gpio_is_valid(data->gpio_wlan_regon)) {
		dev_err(dev, "get gpio wlan_regon failed\n");
	} else {
		dev_info(dev, "wlan_regon gpio=%d  mul-sel=%d  pull=%d  drv_level=%d  data=%d\n",
				config.gpio,
				config.mul_sel,
				config.pull,
				config.drv_level,
				config.data);

		ret = devm_gpio_request(dev, data->gpio_wlan_regon,
				"wlan_regon");
		if (ret < 0) {
			dev_err(dev, "can't request wlan_regon gpio %d\n",
				data->gpio_wlan_regon);
			return ret;
		}

		ret = gpio_direction_output(data->gpio_wlan_regon, 0);
		if (ret < 0) {
			dev_err(dev, "can't request output direction wlan_regon gpio %d\n",
				data->gpio_wlan_regon);
			return ret;
		}
	}

	data->gpio_wlan_hostwake = of_get_named_gpio_flags(np, "wlan_hostwake", 0, (enum of_gpio_flags *)&config);
	if (!gpio_is_valid(data->gpio_wlan_hostwake)) {
		dev_err(dev, "get gpio wlan_hostwake failed\n");
	} else {
		dev_info(dev, "wlan_hostwake gpio=%d  mul-sel=%d  pull=%d  drv_level=%d  data=%d\n",
				config.gpio,
				config.mul_sel,
				config.pull,
				config.drv_level,
				config.data);

		ret = devm_gpio_request(dev, data->gpio_wlan_hostwake,
				"wlan_hostwake");
		if (ret < 0) {
			dev_err(dev, "can't request wlan_hostwake gpio %d\n",
				data->gpio_wlan_hostwake);
			return ret;
		}

		gpio_direction_input(data->gpio_wlan_hostwake);
		if (ret < 0) {
			dev_err(dev, "can't request input direction wlan_hostwake gpio %d\n",
				data->gpio_wlan_hostwake);
			return ret;
		}
	}

	clk_gpio = of_get_named_gpio_flags(np, "wlan_clk_gpio", 0,
						(enum of_gpio_flags *)&config);
	if (!gpio_is_valid(clk_gpio)) {
		dev_err(dev, "get gpio wlan_clk_gpio failed\n");
	} else {
		dev_info(dev, "wlan_clk_gpio gpio=%d  mul-sel=%d  pull=%d  drv_level=%d  data=%d\n",
				config.gpio,
				config.mul_sel,
				config.pull,
				config.drv_level,
				config.data);

		ret = devm_gpio_request(dev, clk_gpio, "wlan_clk_gpio");
		if (ret < 0) {
			dev_err(dev, "can't request wlan_clk_gpio gpio %d\n",
				clk_gpio);
			return ret;
		}

		sunxi_gpio_to_name(config.gpio, pin_name);
		pin_config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_FUNC,
					config.mul_sel);
		pin_config_set(SUNXI_PINCTRL, pin_name, pin_config);
	}

	data->lpo = of_clk_get(np, 0);
	if (IS_ERR_OR_NULL(data->lpo)){
		dev_warn(dev, "clk not config\n");
	}else{
		dev_warn(dev, "enable clk\n");
		ret = clk_prepare_enable(data->lpo);
		if (ret < 0) 
			dev_warn(dev, "can't enable clk\n");
	}

	ret = misc_register(&sunxi_wlan_dev);
	if (ret) {
		dev_err(dev, "sunxi-wlan register driver as misc device error!\n");
		return ret;
	}
	ret = sysfs_create_group(&sunxi_wlan_dev.this_device->kobj,
			&misc_attribute_group);
	if (ret) {
		dev_err(dev, "sunxi-wlan register sysfs create group failed!\n");
		return ret;
	}

	data->power_state = 0;
	data->enable_state = 0;
	wlan_flag = 0;

	pm_runtime_set_active(dev);
	pm_runtime_get(dev);
	pm_runtime_enable(dev);

	if (hw_ver == HW_VER_V1_0 || hw_ver == HW_VER_V4_0) {
		//return 0;
	}

	sunxi_wlan_set_power(1);
	//sunxi_wlan_set_enable(1);

	return 0;
}

static int sunxi_wlan_remove(struct platform_device *pdev)
{
	pm_runtime_disable(&pdev->dev);
	pm_runtime_set_suspended(&pdev->dev);

	WARN_ON(0 != misc_deregister(&sunxi_wlan_dev));
	sysfs_remove_group(&(sunxi_wlan_dev.this_device->kobj),
			&misc_attribute_group);

	if (!IS_ERR_OR_NULL(wlan_data->lpo)) {
		clk_disable_unprepare(wlan_data->lpo);
		clk_put(wlan_data->lpo);
	}

	return 0;
}

static int wlan_pm_suspend(struct device *dev)
{
	//struct sunxi_wlan_platdata *platdata = dev_get_drvdata(dev);

	printk("CONFIG_PM:enter wlan_pm_suspend.\n");

	if (pm_runtime_suspended(dev))
		return 0;

	if (hw_ver == HW_VER_V1_0 || hw_ver == HW_VER_V4_0) {
		//return 0;
	}

	//sunxi_wlan_set_enable(0);
	sunxi_wlan_set_power(0);

	return 0;
}

static int wlan_pm_resume(struct device *dev)
{
	//struct sunxi_wlan_platdata *platdata = dev_get_drvdata(dev);

	printk("CONFIG_PM:enter wlan_pm_resume.\n");

	if (pm_runtime_suspended(dev))
		return 0;

	if (hw_ver == HW_VER_V1_0 || hw_ver == HW_VER_V4_0) {
		//return 0;
	}

	sunxi_wlan_set_power(1);
	//sunxi_wlan_set_enable(1);

	return 0;
}

static struct dev_pm_ops wlan_pm_ops = {
	.suspend = wlan_pm_suspend,
	.resume  = wlan_pm_resume,
};

static const struct of_device_id sunxi_wlan_ids[] = {
	{ .compatible = "allwinner,sunxi-wlan" },
	{ /* Sentinel */ }
};

static struct platform_driver sunxi_wlan_driver = {
	.probe	= sunxi_wlan_probe,
	.remove	= sunxi_wlan_remove,
	.driver	= {
		.owner	= THIS_MODULE,
		.name	= "sunxi-wlan",
		.pm     = &wlan_pm_ops,
		.of_match_table	= sunxi_wlan_ids,
	},
};

module_platform_driver(sunxi_wlan_driver);

MODULE_DESCRIPTION("sunxi wlan driver");
MODULE_LICENSE(GPL);
BT部分的上电时序:
lichee\linux-3.10\drivers\misc\sunxi-rf\sunxi-bluetooth-xr829.c
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/err.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/of_gpio.h>
#include <linux/clk.h>
#include <linux/rfkill.h>
#include <linux/regulator/consumer.h>
#include <linux/platform_device.h>
#include <linux/sys_config.h>
#include <linux/pm_runtime.h>

extern int set_bt_uart_enable(int enable);

struct sunxi_bt_platdata {
	struct regulator *bt_power;
	struct regulator *io_regulator;
	struct clk 	*lpo;
	int gpio_bt_rst;
	char *bt_power_name;
	char *io_regulator_name;

	int power_state;
	int uart_enable;
	struct rfkill *rfkill;
	struct platform_device *pdev;
};
static struct sunxi_bt_platdata *bt_data = NULL;

static DEFINE_MUTEX(sunxi_bt_mutex);

static int sunxi_bt_on(struct sunxi_bt_platdata *data, bool on_off)
{
	struct platform_device *pdev = data->pdev;
	struct device *dev = &pdev->dev;
	int ret = 0;

#if 0
	if (!on_off && gpio_is_valid(data->gpio_bt_rst))
		gpio_direction_output(data->gpio_bt_rst, 0);
#endif

	if(data->bt_power_name){
		data->bt_power = regulator_get(dev, data->bt_power_name);
		if (!IS_ERR(data->bt_power)) {
			if(on_off){
				regulator_set_voltage(data->bt_power,
						(int)3300*1000,
						(int)3300*1000);

				ret = regulator_enable(data->bt_power);
				if (ret < 0){
					dev_err(dev, "regulator bt_power enable failed\n");
					regulator_put(data->bt_power);
					return ret;
				}

				ret = regulator_get_voltage(data->bt_power);
				if (ret < 0){
					dev_err(dev, "regulator bt_power get voltage failed\n");
					regulator_put(data->bt_power);
					return ret;
				}
				dev_info(dev, "check bluetooth bt_power voltage: %d\n",ret);
			}else{
				ret = regulator_disable(data->bt_power);
				if (ret < 0){
					dev_err(dev, "regulator bt_power disable failed\n");
					regulator_put(data->bt_power);
					return ret;
				}
			}
			regulator_put(data->bt_power);
		}
	}

#if 0
	if(data->io_regulator_name){
		data->io_regulator = regulator_get(dev, data->io_regulator_name);
		if (!IS_ERR(data->io_regulator)) {
			if(on_off){
				ret = regulator_enable(data->io_regulator);
				if (ret < 0){
					dev_err(dev, "regulator io_regulator enable failed\n");
					regulator_put(data->io_regulator);
					return ret;
				}

				ret = regulator_get_voltage(data->io_regulator);
				if (ret < 0){
					dev_err(dev, "regulator io_regulator get voltage failed\n");
					regulator_put(data->io_regulator);
					return ret;
				}
				dev_info(dev, "check bluetooth io_regulator voltage: %d\n",ret);
			}else{
				ret = regulator_disable(data->io_regulator);
				if (ret < 0){
					dev_err(dev, "regulator io_regulator disable failed\n");
					regulator_put(data->io_regulator);
					return ret;
				}
			}
			regulator_put(data->io_regulator);
		}
	}

	if (on_off && gpio_is_valid(data->gpio_bt_rst)) {
		mdelay(10);
		gpio_direction_output(data->gpio_bt_rst, 1);
	}
#endif

	data->power_state = on_off;

	return 0;
}

static int sunxi_bt_set_block(void *data, bool blocked)
{
	struct sunxi_bt_platdata *platdata = data;
	struct platform_device *pdev = platdata->pdev;
	int ret;

	if(blocked != platdata->power_state){
		dev_warn(&pdev->dev, "block state already is %d\n",blocked);
		return 0;
	}

	dev_info(&pdev->dev, "set block: %d\n",blocked);
	//ret = sunxi_bt_on(platdata,!blocked);
	//if(ret){
	//	dev_err(&pdev->dev, "set block failed\n");
	//	return ret;
	//}

	return 0;
}

static const struct rfkill_ops sunxi_bt_rfkill_ops = {
	.set_block = sunxi_bt_set_block,
};

static ssize_t power_state_show(struct class *class,
		struct class_attribute *attr, char *buf)
{
	return sprintf(buf, "%d\n", bt_data->power_state);
}

void bt_xr829_enable(int enable);
static ssize_t power_state_store(struct class *class,
		struct class_attribute *attr, const char *buf, size_t count)
{
	unsigned long state;
	int err;

	err = kstrtoul(buf, 0, &state);
	if (err)
		return err;
	bt_data->power_state = state;
	printk("bt_xr829_enable = %ld\n",state);
	if(state)
		bt_xr829_enable(1);
	else
		bt_xr829_enable(0);
	return count;
/*	
	if (state > 1 )
		return -EINVAL;

	mutex_lock(&sunxi_bt_mutex);
	if (state != bt_data->power_state) {
		dev_info(&bt_data->pdev->dev, "set power: %s\n", state ? "on" : "off");
		err = sunxi_bt_on(bt_data, state);
		if (err) {
			dev_err(&bt_data->pdev->dev, "set power failed\n");
			return err;
		}
	}
	mutex_unlock(&sunxi_bt_mutex);

	return count;
*/
}

static ssize_t uart_enable_store(struct class *class,
		struct class_attribute *attr, const char *buf, size_t count)
{
	unsigned long enable;
	int err;

	err = kstrtoul(buf, 0, &enable);
	if (err)
		return err;

	if (enable > 1 )
		return -EINVAL;

	if (enable != bt_data->uart_enable) {
		dev_info(&bt_data->pdev->dev, "bt uart: %s\n", enable ? "on" : "off");
		err = set_bt_uart_enable(enable);
		if (0 == err) {
			if (0 == enable) {
				bt_data->uart_enable = 0;
			} else {
				bt_data->uart_enable = 1;
			}
		}
	}

	return count;
}

static struct class_attribute bt_attribute_group[] = {
	__ATTR(power_state, S_IWUGO | S_IRUGO,
			power_state_show, power_state_store),
	__ATTR(uart_enable, S_IWUGO,
			NULL, uart_enable_store),
	__ATTR_NULL
};

static struct class bt_power_class = {
	.name = "bt_power",
	.class_attrs = bt_attribute_group,
};
static int bt_xr829_reset = 0;
static int bt_xr829_wake = 0;
void bt_xr829_enable(int enable)
{
	printk("%s aa enable=%d\n",__func__,enable);
	if(enable){
	gpio_direction_output(bt_xr829_reset, 1);
	gpio_direction_output(bt_xr829_wake, 1);
	}else{
			gpio_direction_output(bt_xr829_wake, 0);
			gpio_direction_output(bt_xr829_reset, 0);
	}
}

static int sunxi_bt_probe(struct platform_device *pdev)
{
	struct device_node *np = pdev->dev.of_node;
	struct device *dev = &pdev->dev;
	struct sunxi_bt_platdata *data;
	struct gpio_config config;
	const char *power,*io_regulator;
	int ret = 0;

	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
	if (!dev)
		return -ENOMEM;
	
	data->pdev = pdev;
	bt_data = data;
	if (of_property_read_string(np, "bt_power", &power)) {
		dev_warn(dev, "Missing bt_power.\n");
	}else{
		data->bt_power_name = devm_kzalloc(dev, 64, GFP_KERNEL);
		if(!data->bt_power_name)
			return -ENOMEM;
		else
			strcpy(data->bt_power_name,power);
	}
	dev_info(dev, "bt_power_name (%s)\n", data->bt_power_name);
	bt_xr829_reset = of_get_named_gpio_flags(np, "bt_rst_n", 0, (enum of_gpio_flags *)&config);
	if (!gpio_is_valid(bt_xr829_reset)) {
		printk("get gpio bt_rst failed\n");
	} else {
		printk("bt_rst gpio=%d gpio=%d  mul-sel=%d  pull=%d  drv_level=%d  data=%d\n",bt_xr829_reset,
				config.gpio,
				config.mul_sel,
				config.pull,
				config.drv_level,
				config.data);

		ret = devm_gpio_request(dev, bt_xr829_reset, "bt_xr829_reset");
		if (ret < 0) {
			printk(dev, "can't request bt_rst gpio %d\n",
				bt_xr829_reset);
			return ret;
		}

		ret = gpio_direction_output(bt_xr829_reset, 0);
		if (ret < 0) {
			printk(dev, "can't request output direction bt_rst gpio %d\n",
				bt_xr829_reset);
			return ret;
		}
	}

	bt_xr829_wake = of_get_named_gpio_flags(np, "ap_wakeup_bt", 0, (enum of_gpio_flags *)&config);
	if (!gpio_is_valid(bt_xr829_wake)) {
		printk("get gpio bt_xr829_wake failed\n");
	} else {
		printk("bt_xr829_wake gpio=%d gpio=%d  mul-sel=%d  pull=%d  drv_level=%d  data=%d\n",bt_xr829_wake,
				config.gpio,
				config.mul_sel,
				config.pull,
				config.drv_level,
				config.data);

		ret = devm_gpio_request(dev, bt_xr829_wake, "ap_wakeup_bt");
		if (ret < 0) {
			printk(dev, "can't request bt_xr829_wake gpio %d\n",
				bt_xr829_wake);
			return ret;
		}

		ret = gpio_direction_output(bt_xr829_wake, 0);
		if (ret < 0) {
			printk(dev, "can't request output direction bt_xr829_wake %d\n",
				bt_xr829_wake);
			return ret;
		}
	}

#if 0
	if (of_property_read_string(np, "bt_io_regulator", &io_regulator)) {
		dev_warn(dev, "Missing bt_io_regulator.\n");
	}else{
		data->io_regulator_name = devm_kzalloc(dev, 64, GFP_KERNEL);
		if(!data->io_regulator_name)
			return -ENOMEM;
		else
			strcpy(data->io_regulator_name,io_regulator);
	}
	dev_info(dev, "io_regulator_name (%s)\n", data->io_regulator_name);

	data->gpio_bt_rst = of_get_named_gpio_flags(np, "bt_rst_n", 0, (enum of_gpio_flags *)&config);
	if (!gpio_is_valid(data->gpio_bt_rst)) {
		dev_err(dev, "get gpio bt_rst failed\n");
	} else {
		dev_info(dev, "bt_rst gpio=%d  mul-sel=%d  pull=%d  drv_level=%d  data=%d\n",
				config.gpio,
				config.mul_sel,
				config.pull,
				config.drv_level,
				config.data);

		ret = devm_gpio_request(dev, data->gpio_bt_rst, "bt_rst");
		if (ret < 0) {
			dev_err(dev, "can't request bt_rst gpio %d\n",
				data->gpio_bt_rst);
			return ret;
		}

		ret = gpio_direction_output(data->gpio_bt_rst, 0);
		if (ret < 0) {
			dev_err(dev, "can't request output direction bt_rst gpio %d\n",
				data->gpio_bt_rst);
			return ret;
		}
	}

	data->lpo = of_clk_get(np, 0);
	if (IS_ERR_OR_NULL(data->lpo)){
		dev_warn(dev, "clk not config\n");
	}else{
		ret = clk_prepare_enable(data->lpo);
		if (ret < 0) 
			dev_warn(dev,"can't enable clk\n");
	}
#endif

	data->rfkill = rfkill_alloc("sunxi-bt", dev, RFKILL_TYPE_BLUETOOTH,
				&sunxi_bt_rfkill_ops, data);
	if (!data->rfkill) {
		ret = -ENOMEM;
		goto failed_alloc;
	}

	rfkill_set_states(data->rfkill, true, false);

	ret = rfkill_register(data->rfkill);
	if (ret){
		goto fail_rfkill;
	}
	platform_set_drvdata(pdev, data);

	class_register(&bt_power_class);

	data->power_state = 0;
	data->uart_enable = 1;

	pm_runtime_set_active(dev);
	pm_runtime_get(dev);
	pm_runtime_enable(dev);

	if (1 != data->power_state) {
		sunxi_bt_on(data, 1);
	}

	return 0;

fail_rfkill:
	if (data->rfkill) 
		rfkill_destroy(data->rfkill);
failed_alloc:
	//if (!IS_ERR_OR_NULL(data->lpo)) {
	//	clk_disable_unprepare(data->lpo);
	//	clk_put(data->lpo);
	//}
	return ret;
}

static int sunxi_bt_remove(struct platform_device *pdev)
{
	struct sunxi_bt_platdata *data = platform_get_drvdata(pdev);
	struct rfkill *rfk = data->rfkill;

	pm_runtime_disable(&pdev->dev);
	pm_runtime_set_suspended(&pdev->dev);

	class_unregister(&bt_power_class);

	platform_set_drvdata(pdev, NULL);
	
	if(rfk){
		rfkill_unregister(rfk);
		rfkill_destroy(rfk);
	}

	//if (!IS_ERR_OR_NULL(data->lpo)) {
	//	clk_disable_unprepare(data->lpo);
	//	clk_put(data->lpo);
	//}

	return 0;
}

static int bt_pm_suspend(struct device *dev)
{
	struct sunxi_bt_platdata *platdata = dev_get_drvdata(dev);

	printk("CONFIG_PM:enter bt_pm_suspend.\n");

	if (pm_runtime_suspended(dev))
		return 0;

	if (platdata) {
		if (0 != platdata->power_state) {
			sunxi_bt_on(platdata, 0);
		}
	}

	return 0;
}

static int bt_pm_resume(struct device *dev)
{
	struct sunxi_bt_platdata *platdata = dev_get_drvdata(dev);

	printk("CONFIG_PM:enter bt_pm_resume.\n");

	if (pm_runtime_suspended(dev))
		return 0;

	if (platdata) {
		if (1 != platdata->power_state) {
			sunxi_bt_on(platdata, 1);
		}
	}

	return 0;
}

static struct dev_pm_ops bt_pm_ops = {
	.suspend = bt_pm_suspend,
	.resume  = bt_pm_resume,
};

static const struct of_device_id sunxi_bt_ids[] = {
	{ .compatible = "allwinner,sunxi-bt" },
	{ /* Sentinel */ }
};

static struct platform_driver sunxi_bt_driver = {
	.probe	= sunxi_bt_probe,
	.remove	= sunxi_bt_remove,
	.driver	= {
		.owner	= THIS_MODULE,
		.name	= "sunxi-bt",
		.pm     = &bt_pm_ops,
		.of_match_table	= sunxi_bt_ids,
	},
};

module_platform_driver(sunxi_bt_driver);

MODULE_DESCRIPTION("sunxi bluetooth driver");
MODULE_LICENSE(GPL);

lichee\linux-3.10\drivers\misc\sunxi-rf\Makefile
#
# Makefile for wifi bluetooth power controller drivers
#
ifdef CONFIG_XR_829
obj-$(CONFIG_SUNXI_RFKILL)   += sunxi-wlan-xr829.o sunxi-bluetooth-xr829.o sunxi-gps-xr829.o
else
obj-$(CONFIG_SUNXI_RFKILL)   += sunxi-wlan.o sunxi-bluetooth.o sunxi-gps.o
endif

4、内核代码的整合

将XR829模块原厂给的驱动拷贝到lichee\linux-3.10\drivers\net\wireless\xr829\目录中,修改KCONFIG和Makefile文件,如下:

lichee\linux-3.10\drivers\net\wireless\Kconfig 添加:
source "drivers/net/wireless/xradio/Kconfig"
source "drivers/net/wireless/xr829/Kconfig" //添加

lichee\linux-3.10\drivers\net\wireless\Makefile
obj-$(CONFIG_XR_WLAN)		+= xradio/
obj-$(CONFIG_XR_829)		+= xr829/ //添加

lichee\linux-3.10\drivers\net\wireless\xr829\Kconfig 内容如下:
menuconfig XR_829
	tristate "XRadio WLAN support(xr829)"
	default n
	select CFG80211
	select AVERAGE
	select CRYPTO
	select CRYPTO_ARC4
	---help---
	  To compile this code as a module, choose M here.

if XR_829

source "drivers/net/wireless/xr829/umac/Kconfig"
source "drivers/net/wireless/xr829/wlan/Kconfig"

endif #XR_829

lichee\linux-3.10\drivers\net\wireless\xr829\Makefile 内容如下:
NOSTDINC_FLAGS := -I$(srctree)/drivers/net/wireless/xr829/include/

obj-$(CONFIG_XR_829) += umac/
obj-$(CONFIG_XR_829) += wlan/

clean-files += Module.symvers Module.markers modules modules.order

修改配置,使其编译出来xr829_xxx.ko文件,如下:
lichee\linux-3.10\drivers\net\wireless\xr829\umac\Makefile 内容如下,将xradio的字样修改成xr829,如下:
obj-$(CONFIG_XRMAC) += xr829_mac.o

ldflags-y += --strip-debug

# xr829_mac objects
xr829_mac-y := \
	main.o status.o \
	sta_info.o \
	wep.o \
	wpa.o \
	wapi.o \
	scan.o offchannel.o \
	ht.o agg-tx.o agg-rx.o \
	ibss.o \
	mlme.o work.o \
	iface.o \
	rate.o \
	michael.o \
	tkip.o \
	aes_ccm.o \
	aes_cmac.o \
	cfg.o \
	rx.o \
	spectmgmt.o \
	tx.o \
	key.o \
	util.o \
	wme.o \
	event.o \
	chan.o

xr829_mac-$(CONFIG_XRMAC_LEDS) += led.o
xr829_mac-$(CONFIG_XRMAC_DEBUGFS) += \
	debugfs.o \
	debugfs_sta.o \
	debugfs_netdev.o \
	debugfs_key.o

xr829_mac-$(CONFIG_XRMAC_MESH) += \
	mesh.o \
	mesh_pathtbl.o \
	mesh_plink.o \
	mesh_hwmp.o

xr829_mac-$(CONFIG_PM) += pm.o

xr829_mac-$(CONFIG_XRMAC_DRIVER_API_TRACER) += driver-trace.o
CFLAGS_driver-trace.o := -I$(src)

# objects for PID algorithm
rc80211_pid-y := rc80211_pid_algo.o
rc80211_pid-$(CONFIG_XRMAC_DEBUGFS) += rc80211_pid_debugfs.o

rc80211_minstrel-y := rc80211_minstrel.o
rc80211_minstrel-$(CONFIG_XRMAC_DEBUGFS) += rc80211_minstrel_debugfs.o

rc80211_minstrel_ht-y := rc80211_minstrel_ht.o
rc80211_minstrel_ht-$(CONFIG_XRMAC_DEBUGFS) += rc80211_minstrel_ht_debugfs.o

xr829_mac-$(CONFIG_XRMAC_RC_PID) += $(rc80211_pid-y)
xr829_mac-$(CONFIG_XRMAC_RC_MINSTREL) += $(rc80211_minstrel-y)
xr829_mac-$(CONFIG_XRMAC_RC_MINSTREL_HT) += $(rc80211_minstrel_ht-y)

ccflags-y += -D__CHECK_ENDIAN__
# Extra IE for probe response from upper layer is needed in P2P GO
# For offloading probe response to FW, the extra IE must be included
# in the probe response template
ccflags-y += -DPROBE_RESP_EXTRA_IE
ccflags-y += -DIPV6_FILTERING
#ccflags-y += -DCONFIG_XRMAC_XR_ROAMING_CHANGES
ccflags-y += -DUSE_RSSI_SMOOTH

lichee\linux-3.10\drivers\net\wireless\xr829\wlan\Makefile 内容如下:
xr829_core-y := \
	common.o \
	fwio.o \
	txrx.o \
	main.o \
	queue.o \
	hwio.o \
	bh.o \
	wsm.o \
	sta.o \
	ap.o \
	scan.o \
	platform.o \
	fw_dbg_inf.o

xr829_core-$(CONFIG_PM)            += pm.o
xr829_core-$(CONFIG_XRADIO_SDIO)   += sdio.o
xr829_core-$(CONFIG_XRADIO_DEBUG)  += debug.o
xr829_core-$(CONFIG_XRADIO_ITP)    += itp.o
xr829_core-$(CONFIG_XRADIO_ETF)    += etf.o

ldflags-y += --strip-debug

xr829_wlan-y := wlan_init.o

obj-$(CONFIG_XRADIO) += xr829_core.o
obj-m += xr829_wlan.o

##=======  User Options ======= 
## Use vfs for firmware load when request_firmware
# can't work on other platform.
ccflags-y += -DUSE_VFS_FIRMWARE
## Mac addr config, disable hex for default.
#ccflags-y += -DXRADIO_MACPARAM_HEX
ccflags-y += -DMONITOR_MODE

##======= Follows just for xradio internal, Don't change these macro if not ensure. =======
ccflags-y += -DCONFIG_XRADIO_USE_EXTENSIONS
ccflags-y += -DP2P_MULTIVIF
ccflags-y += -DMCAST_FWDING
ccflags-y += -DXRADIO_SUSPEND_RESUME_FILTER_ENABLE
ccflags-y += -DAP_AGGREGATE_FW_FIX
ccflags-y += -DAP_HT_CAP_UPDATE
ccflags-y += -DAP_HT_COMPAT_FIX
#ccflags-y += -DAP_ARP_COMPAT_FIX
ccflags-y += -DENHANCE_ANTI_INTERFERE
#ccflags-y += -DUSE_RSSI_OFFSET
ccflags-y += -DSCAN_FAILED_WORKAROUND_OF_FW_EXCEPTION
ccflags-y += -DHW_RESTART
ccflags-y += -DHW_ERROR_WIFI_RESET

## Use semaphore to sync bh txrx.
#ccflags-y += -DBH_USE_SEMAPHORE
ccflags-y += -DBH_PROC_THREAD
ccflags-y += -DBH_COMINGRX_FORECAST

# Modified for power save.
#ccflags-y += -DXRADIO_USE_LONG_DTIM_PERIOD
ccflags-y += -DXRADIO_USE_LONG_KEEP_ALIVE_PERIOD

## Extra IE for probe response from upper layer is needed in P2P GO
## For offloading probe response to FW, the extra IE must be included
## in the probe response template
ccflags-y += -DPROBE_RESP_EXTRA_IE
ccflags-y += -DIPV6_FILTERING

## Modified for P2P stability.
ccflags-y += -DTES_P2P_0002_ROC_RESTART
ccflags-y += -DTES_P2P_000B_EXTEND_INACTIVITY_CNT
ccflags-y += -DTES_P2P_000B_DISABLE_EAPOL_FILTER

## for chips.
ccflags-y += -DSUPPORT_HT40
ccflags-y += -DSUPPORT_EPTA
ccflags-y += -DSUPPORT_DPLL_CHECK
#ccflags-y += -DSUPPORT_NON_HT40_CHIP
ccflags-y += -DBOOT_NOT_READY_FIX

## for interal debug.
ccflags-y += -DSUPPORT_FW_DBG_INF
#ccflags-y += -DERROR_HANG_DRIVER

lichee\linux-3.10\drivers\net\wireless\xr829\wlan\Kconfig 添加:
config XRADIO_SUSPEND_POWER_OFF
	bool "Wlan power off in suspend"
	depends on XRADIO && PM
	default n
	---help---
	  Say Y if you want to wlan power off in suspend,
	  and then WoW will be disable.
	  If unsure, say N.

config XRADIO_EXTEND_SUSPEND //添加选项
	bool "Support extend suspend(both Wow and power off)"
	depends on XRADIO && PM
	select XRADIO_SUSPEND_POWER_OFF
	default n
	---help---
	  Say Y if you want to support extend supend, but
	  extend suspend need to be support on your platform.
	  If unsure, say N.

config XRADIO_NOMAL_SUSPEND_FORCE
........................................

修改lichee\linux-3.10\drivers\net\wireless\xr829\wlan\platform.c 添加模块的上电时序

/*
extern void xradio_wlan_set_power(int on);
extern int xradio_wlan_get_bus_index(void);
extern int xradio_wlan_get_oob_irq(void);
extern int xradio_wlan_get_oob_irq_flags(void);
*/
//add start
extern void sunxi_wlan_set_module(int flag);
extern void sunxi_wlan_set_power(bool on);
extern int sunxi_wlan_get_bus_index(void);
extern int sunxi_wlan_get_oob_irq(void);
extern int sunxi_wlan_get_oob_irq_flags(void);
extern void sunxi_wlan_set_enable(int on);
extern void sunxi_mmc_remove_sdio(unsigned ids);
//add end
static int wlan_bus_id     = 0;
static u32 gpio_irq_handle = 0;

int xradio_get_syscfg(void)
{
	int wlan_bus_index = 0;
	//wlan_bus_index = xradio_wlan_get_bus_index();
	wlan_bus_index = sunxi_wlan_get_bus_index();
	if(wlan_bus_index < 0)
		return wlan_bus_index;
	else
		wlan_bus_id = wlan_bus_index;
	//gpio_irq_handle = xradio_wlan_get_oob_irq();
	gpio_irq_handle = sunxi_wlan_get_oob_irq();
	return wlan_bus_index;
}
/*********************Interfaces called by xradio core. *********************/
int  xradio_plat_init(void)
{
  return 0;
}

void xradio_plat_deinit(void)
{
;
}
//chanage
int xradio_wlan_power(int on)
{
	int ret = 0;
	if(on){
	    ret = xradio_get_syscfg();
		if(ret < 0)
			return ret;
	}
	
	sunxi_wlan_set_module(1);
#if 1 
	if (on) {
		//sunxi_wlan_set_power(on);
		//mdelay(100);
		sunxi_wlan_set_enable(on);
		mdelay(200);
	} else {
		sunxi_wlan_set_enable(on);
		//sunxi_wlan_set_power(on);
		mdelay(200);
	}
#endif
	return ret;
}
//end chanage
void xradio_sdio_detect(int enable)
{
	if (0 == enable) { //add start
		xradio_dbg(XRADIO_DBG_ALWY, "%s SDIO card %d\n",
				enable?"Detect":"Remove", wlan_bus_id);
		sunxi_mmc_remove_sdio(wlan_bus_id);
		mdelay(10);
		return;
	}
   //add end
	MCI_RESCAN_CARD(wlan_bus_id);
	xradio_dbg(XRADIO_DBG_ALWY, "%s SDIO card %d\n", 
	           enable?"Detect":"Remove", wlan_bus_id);
	mdelay(10);
}

修改XR819模块:
lichee\linux-3.10\drivers\net\wireless\xradio\wlan\platform.c
/* Select hardware platform.*/
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0))
extern void sunxi_mmc_rescan_card(unsigned ids);
#define MCI_RESCAN_CARD(id)  sunxi_mmc_rescan_card(id)
#ifdef CONFIG_XR_829
extern void sunxi_wlan_set_module(int flag);
#endif
extern void sunxi_wlan_set_power(int on);
extern void sunxi_wlan_set_enable(int on);
extern int sunxi_wlan_get_bus_index(void);
extern int sunxi_wlan_get_oob_irq(void);
extern void sunxi_mmc_remove_sdio(unsigned ids);
/*extern int sunxi_wlan_get_oob_irq_flags(void);*/
#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0))
#define PLAT_ALLWINNER_SUNXI
extern void sunxi_mci_rescan_card(unsigned id, unsigned insert);
#define MCI_RESCAN_CARD(id, ins)  sunxi_mci_rescan_card(id, ins)
#else
#define PLAT_ALLWINNER_SUN6I
extern void sw_mci_rescan_card(unsigned id, unsigned insert);
#define MCI_RESCAN_CARD(id, ins)  sw_mci_rescan_card(id, ins)
#endif


static int wlan_bus_id     = 0;
static u32 gpio_irq_handle = 0;

static int xradio_get_syscfg(void)
{
	int wlan_bus_index = 0;
	wlan_bus_index = sunxi_wlan_get_bus_index();
	if(wlan_bus_index < 0)
		return wlan_bus_index;
	else
		wlan_bus_id = wlan_bus_index;
	
	gpio_irq_handle = sunxi_wlan_get_oob_irq();
	return wlan_bus_index;
}

#if 0
static int h64_wlan_soc_power(int on)
{
	struct regulator *ldo = NULL;
	int ret = 0;
	if (on) {
			//wifi vcc 1.8v .
			ldo = regulator_get(NULL, "axp81x_dldo2");
		if (ldo) {
			regulator_set_voltage(ldo,1800000, 1800000);
			ret = regulator_enable(ldo);
			if(ret < 0){
			}
			regulator_put(ldo);
		}
	}
	else{
		//wifi vcc 1.8v 
		ldo = regulator_get(NULL, "axp81x_dldo2");
		if (ldo) {
			ret = regulator_disable(ldo);
			regulator_put(ldo);
		}	
	}
  return ret;
}
#endif

/*********************Interfaces called by xradio core. *********************/
int  xradio_plat_init(void)
{
	return 0;
}

void xradio_plat_deinit(void)
{
}

int xradio_wlan_power(int on)
{
	int ret = 0;
	if(on){
		ret = xradio_get_syscfg();
		if(ret < 0)
			return ret;
	}
#ifdef CONFIG_XR_829
	sunxi_wlan_set_module(0);
#endif
	if (on) {
		sunxi_wlan_set_power(on);
		mdelay(10);
		sunxi_wlan_set_enable(on);
		mdelay(200);
	} else {
		sunxi_wlan_set_enable(on);
		sunxi_wlan_set_power(on);
		mdelay(200);
	}
	return ret;
}

void xradio_sdio_detect(int enable)
{
	if (0 == enable) {
		xradio_dbg(XRADIO_DBG_ALWY, "%s SDIO card %d\n",
				enable?"Detect":"Remove", wlan_bus_id);
		sunxi_mmc_remove_sdio(wlan_bus_id);
		mdelay(10);
		return;
	}
	MCI_RESCAN_CARD(wlan_bus_id);
	xradio_dbg(XRADIO_DBG_ALWY, "%s SDIO card %d\n", 
	           enable?"Detect":"Remove", wlan_bus_id);
	mdelay(10);
}

修改SDIO总线挂载部分:

lichee\linux-3.10\drivers\mmc\core\sdio_bus.c(CONFIG_XR_829部分就是添加的部分)
#ifdef CONFIG_XR_829
#define SDIO_VENDOR_ID_XRADIO 0x0020
#define SDIO_DEVICE_ID_XRADIO 0x2281
#define SDIO_VENDOR_ID_XR829 0x0A9E
#define SDIO_DEVICE_ID_XR829 0x2282
extern void sunxi_wlan_set_module(int flag);
#endif

static int
sdio_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
{
	struct sdio_func *func = dev_to_sdio_func(dev);
#ifdef CONFIG_XR_829
	if(func->vendor == SDIO_VENDOR_ID_XRADIO && func->device == SDIO_DEVICE_ID_XRADIO) //xradio
	{
		sunxi_wlan_set_module(0);
	}
	else if(func->vendor == SDIO_VENDOR_ID_XR829 && func->device == SDIO_DEVICE_ID_XR829)
	{
		sunxi_wlan_set_module(1);
	}
#endif
	if (add_uevent_var(env,
			"SDIO_CLASS=%02X", func->class))
		return -ENOMEM;
#ifdef CONFIG_XR_829
	printk("nwd-wangtao SDIO_ID=%04X:%04X\n", func->vendor, func->device);
#endif
	if (add_uevent_var(env, 
			"SDIO_ID=%04X:%04X", func->vendor, func->device))
		return -ENOMEM;

	if (add_uevent_var(env,
			"MODALIAS=sdio:c%02Xv%04Xd%04X",
			func->class, func->vendor, func->device))
		return -ENOMEM;

	return 0;
}

内核配置部分:

lichee\linux-3.10\arch\arm\configs\sun8iw11p1_android_x217_defconfig
# CONFIG_XR_WLAN is not set
CONFIG_XRMAC=m
CONFIG_XRMAC_RC_DEFAULT="minstrel_ht"
# CONFIG_XRMAC_RC_PID is not set
CONFIG_XRMAC_RC_MINSTREL=y
CONFIG_XRMAC_RC_MINSTREL_HT=y
CONFIG_XRMAC_DEBUGFS=y
CONFIG_XRADIO=m
CONFIG_XRADIO_SDIO=y
CONFIG_XRADIO_NON_POWER_OF_TWO_BLOCKSIZES=y
CONFIG_XRADIO_USE_GPIO_IRQ=y
CONFIG_XRADIO_USE_EXTENSIONS=y
# CONFIG_XRADIO_SUSPEND_POWER_OFF is not set
# CONFIG_XRADIO_EXTEND_SUSPEND is not set
# CONFIG_XRADIO_NOMAL_SUSPEND_FORCE is not set

#
# Driver debug features
#
CONFIG_XRADIO_DEBUG=y
CONFIG_XRADIO_ETF=y
# CONFIG_XRADIO_DUMP_ON_ERROR is not set
CONFIG_XRADIO_DEBUGFS=y
CONFIG_XR_829=m
# CONFIG_XRADIO_NOMAL_SUSPEND_FORCE is not set

即编译XR829模块:
CONFIG_XR_829=m
CONFIG_XR_WLAN is not set
即编译XR819模块:
CONFIG_XR_WLAN=m 
CONFIG_XR_829 is not set

二、Android os部分的配置

1、hardware层的修改:

android\hardware\libhardware_legacy\wifi_hardware_info\wifi_hardware_info.c
static const struct wifi_hardware_info wifi_list[] = {
..............................................................
+	{
+		.device_id   = 0x12282,
+		.module_name = "xr829",
+		.driver_name = "xr829_wlan",
+		.vendor_name = "xradio",
+		.fw_path_sta = "STA",
+		.fw_path_ap  = "AP",
+		.fw_path_p2p = "P2P",
+	},
 };
static void parse_uevent(char *msg)
{
    char sdio_device_id[10] = {0};
    char device_type[10] = {0};
    char *subsystem = "";
    char *sdio_id = "";
    char *usb_product = "";
    unsigned long device_id = 0;

    while(*msg) {
        if(!strncmp(msg, "SUBSYSTEM=", 10)) {
            msg += 10;
            subsystem = msg;
        } else if(!strncmp(msg, "SDIO_ID=", 8)) {
            msg += 8;
            sdio_id = msg;
        } else if(!strncmp(msg, "PRODUCT=", 8)) {
            msg += 8;
            usb_product = msg;
        }

        /* advance to after the next \0 */
        while(*msg++) {
            /* do nothing */
        }
    }

    if(!strncmp(subsystem, "sdio", 4)) {
        ALOGI("get uevent, sdio_id = %s", sdio_id);
        strcpy(device_type, "sdio");
        char *subid = strrchr(sdio_id, ':');
        if(subid == NULL) {
            return;
        }
        subid++;
        strcpy(sdio_device_id, subid);
        device_id = strtoul(sdio_device_id, NULL, 16);
        device_id += 0x10000;
    } else if(!strncmp(subsystem, "usb", 3)) {
        strcpy(device_type, "usb");
        char *subid = NULL;

        strtok(usb_product, "/");
        subid = strtok( NULL, "/");
        if(subid == NULL) {
            return;
        }
        device_id = strtoul(subid, NULL, 16);
    } else {
        return;
    }

    if(!get_hardware_info_by_device_id(device_id)) {
        FILE *file = fopen(WIFI_HARDWARE_INFO_PATH, "w");
        char info[PROPERTY_VALUE_MAX] = {0};
        snprintf(info, sizeof(info), "%s:%s", selected_wifi.vendor_name, selected_wifi.module_name);
        if(file == NULL){
            ALOGE("cannot open file %s to write", WIFI_HARDWARE_INFO_PATH);
            return;
        }
        ALOGD("write wifi_hardware_info into file: %s:%s", selected_wifi.vendor_name,
                selected_wifi.module_name);
       //add by zhaojr
		if(!strcmp(selected_wifi.module_name, "xr829"))
			property_set("persist.sys.bluetooth_goc", "1");
		else if(!strcmp(selected_wifi.module_name, "xr819"))
			property_set("persist.sys.goc", "1");
        //end add
        fprintf(file,"%s\n", info);
        fflush(file);
        fsync(fileno(file));
        fclose(file);
        property_set("wlan.hardware.info", info);
        thread_state = exiting;
    }
}

将xr829的固件目录拷贝到android\hardware\broadcom\wlan\bcmdhd\firmware\xr829目录,编写

android\hardware\broadcom\wlan\bcmdhd\firmware\xr829\device-xr829.mk文件,内容如下:

android\hardware\broadcom\wlan\bcmdhd\firmware\xr829\device-xr829.mk
########################

PRODUCT_COPY_FILES += \
    hardware/broadcom/wlan/bcmdhd/firmware/xr829/boot_xr829.bin:system/etc/firmware/boot_xr829.bin \
    hardware/broadcom/wlan/bcmdhd/firmware/xr829/fw_xr829.bin:system/etc/firmware/fw_xr829.bin \
    hardware/broadcom/wlan/bcmdhd/firmware/xr829/sdd_xr829.bin:system/etc/firmware/sdd_xr829.bin \
    hardware/broadcom/wlan/bcmdhd/firmware/xr829/etf_xr829.bin:system/etc/firmware/etf_xr829.bin \
    hardware/broadcom/wlan/bcmdhd/firmware/xr829/fw_xr829_bt.bin:system/etc/firmware/fw_xr829_bt.bin \
    hardware/broadcom/wlan/bcmdhd/firmware/xr829/fw_xr829_bt_sco_hci_uart.bin:system/etc/firmware/fw_xr829_bt_sco_hci_uart.bin
########################

将以上文件添加到:
android\hardware\broadcom\wlan\bcmdhd\firmware\firmware-bcm.mk
#include hardware/broadcom/wlan/bcmdhd/firmware/ap6210/device-bcm.mk
#include hardware/broadcom/wlan/bcmdhd/firmware/ap6330/device-bcm.mk
#include hardware/broadcom/wlan/bcmdhd/firmware/ap6335/device-bcm.mk
#include hardware/broadcom/wlan/bcmdhd/firmware/ap6212/device-bcm.mk
#include hardware/broadcom/wlan/bcmdhd/firmware/ssv6051/device-esp.mk
#include hardware/broadcom/wlan/bcmdhd/firmware/rtl8189fs/device-rtw.mk
include hardware/broadcom/wlan/bcmdhd/firmware/xr819/device-xradio.mk
include hardware/broadcom/wlan/bcmdhd/firmware/xr829/device-xr829.mk //添加

2、平台配置:

android\device\softwinner\x217\BoardConfig.mk
# wifi and bt configuration
# 1. wifi Configuration
WPA_SUPPLICANT_VERSION := VER_0_8_X
BOARD_WPA_SUPPLICANT_DRIVER := NL80211
BOARD_WPA_SUPPLICANT_PRIVATE_LIB := lib_driver_cmd
BOARD_HOSTAPD_DRIVER        := NL80211
BOARD_HOSTAPD_PRIVATE_LIB   := lib_driver_cmd
include hardware/broadcom/wlan/bcmdhd/firmware/firmware-bcm.mk
include hardware/broadcom/wlan/bcmdhd/config/config-bcm.mk

android\device\softwinner\x217\init.rc
添加服务:
service dhcpcd_lte0 /system/bin/dhcpcd -ABKL
	class main
	disabled
	oneshot

service iprenew_lte0 /system/bin/dhcpcd -n
	class main
    	disabled
	oneshot
..............................................
# wifi service
# 1 wifi station and softap
service wpa_supplicant /system/bin/logwrapper /system/bin/wpa_supplicant \
    p2p_supported=false
    class main
    socket wpa_wlan0 dgram 660 wifi wifi
    disabled
    oneshot

# 2 wifi sta p2p concurrent service
service p2p_supplicant /system/bin/logwrapper /system/bin/wpa_supplicant \
    p2p_supported=true
    class main
    socket wpa_wlan0 dgram 660 wifi wifi
    disabled
    oneshot
#nwd patch, added by ww, 2016.1.17
#wenqiang bluetooch
service gocsdk /system/bin/gocsdk /dev/ttyS1 500000
        class main
        user root
        group root
        disabled

service gocsdk_xr829 /system/bin/gocsdk_xr829 /dev/ttyS1 1500000
    class main
    user root
    group root
    disabled
on property:persist.sys.goc=1
	insmod /system/vendor/modules/xradio_mac.ko
	insmod /system/vendor/modules/xradio_core.ko
    start gocsdk

on property:persist.sys.bluetooth_goc=1
	insmod /system/vendor/modules/xr829_mac.ko
	insmod /system/vendor/modules/xr829_core.ko
    start gocsdk_xr829

android\device\softwinner\x217\ueventd.sun8iw11p1.rc
...................................................
/dev/snd/pcmC0D0c           0770    media       media
/dev/snd/pcmC0D0p           0770    media       media
......................................................
/dev/ttyS1                0777    system      system
..................................................
/dev/audio                 0666    system      system
.......................................................

android\device\softwinner\t3-common\t3-common.mk
#open wireless debugging feature
PRODUCT_PROPERTY_OVERRIDES += \
        service.adb.tcp.port=5555 \
        ro.adb.secure=0 \
        persist.service.adb.enable=1 \
        ro.debuggable=1 \
	    persist.sys.i2s=0 \
	    persist.sys.camera.debug=0 \
	    persist.sys.nwd.ethernet.ctrl=0 \
	    sys.nwd.tve.enable=1 \
	    persist.sys.bluetooth_goc=1 \  ------->//加载XR829模块
	    persist.bt.sco.uart=true \ ----------->蓝牙电话和蓝牙音乐走蓝牙模块的串口,不走PCM
	    ro.single.double.mic=0

 

最后,全新编译整个系统,编译之后,将协议栈厂家给的gocsdk_xr829放到系统中的/system/bin/目录中,如下:

adb push gocsdk_xr829 /system/bin/
adb shell
chmod 777 /system/bin/gocsdk_xr829
sync

之后重启系统,运行起来之后打开WIFI,即可连接到路由器,之后打开蓝牙电话,手机连接之后,到蓝牙音乐界面,手机播放音乐OK之后,手机打电话测试,经过测试是OK的。

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值