atheros wifi芯片ics高通平台 wifi睡眠策略分析


首先无论是froyo,gingerbrand还是ics,wifi上层有默认设置有三个睡眠策略
以ics为例,在休眠状态下保持WLAN连接
1:始终     --代码中是wow模式睡眠,在待机状态下保持wifi连接
2:仅限充电时--在充电时才始终保持

3:从不     --采用deepsleep模式睡眠,不断电但是断网的模式睡眠,下次唤醒再重新连接。

有些android手机睡眠策略调节无效,就是这部分功能没有实现。没有一下代码,很多手机有这种Bug。

无论是gb还是ics qct上的代码都不能直接与上层联系的,它只选用一个固定模式,要么是deepsleep要么是wow模式。但是在高通qrd代码则实现了关联。

实现方法:通过kobject在sys下创建虚拟文件系统/sys/android_wlan/wlan_power/sleep_policy通过上层设置传如不同值。以下是实现代码。通过store和show来实现上层写入和读出。

很值得学习,故把代码贴出来了。 

gb上的store

static ssize_t ar6000_sleep_policy_store(struct kobject *kobj, struct kobj_attribute *attr,
             const char *buf, size_t size)
{
    if (sysfs_streq(buf, "0"))      //判断buf?=0
            sleep_policy = EARLY_SLEEP;
    else if (sysfs_streq(buf, "1"))要是1则调度deepsleep模式睡眠函数
            sleep_policy = DEEP_SLEEP;
    else if (sysfs_streq(buf, "2"))要是2则调度wow模式睡眠
            sleep_policy = NEVER_SLEEP;
    else {
            pr_err("%s: invalid value %d\n", __func__, *buf);
    }

    return 0;
}  


ics上的store函数

static ssize_t ath6kl_sleep_policy_store(struct device *dev,
                                struct device_attribute *attr,
                                const char *buf, size_t size)
{
    struct sdio_func *func = dev_to_sdio_func(dev);
    struct ath6kl_sdio *ar_sdio = sdio_get_drvdata(func);
    unsigned int new_policy;

    new_policy = simple_strtoul(buf, NULL, 10); //在buf中读出上层传下的值 0,1deepsleep 2 wow

    ath6kl_err("invalid new_policy(%d)\n", (int)new_policy);
        
    switch (new_policy) {
    case 0:
    case 1:
        ar_sdio->ar->suspend_mode = WLAN_POWER_STATE_DEEP_SLEEP;//new_policy 0和1都是deepsleep,通过传入suspend_mode不同的值进入不同的模式
        break;
    case 2:
        ar_sdio->ar->suspend_mode = WLAN_POWER_STATE_WOW;      //2是wow模式
        break;
    default:
        ath6kl_err("invalid new_policy(%d)\n", (int)new_policy);
        return -EINVAL;
    }

    return size;
}
suspend_mode:
/* WLAN low power state */
enum {
    WLAN_POWER_STATE_ON = 0,
    WLAN_POWER_STATE_CUT_PWR = 1,
    WLAN_POWER_STATE_DEEP_SLEEP,
    WLAN_POWER_STATE_WOW
};

show函数

static ssize_t ath6kl_sleep_policy_show(struct device *dev,

                                 struct device_attribute *attr, char *buf)
{
        struct sdio_func *func = dev_to_sdio_func(dev);
        struct ath6kl_sdio *ar_sdio = sdio_get_drvdata(func);

        return sprintf(buf, "%d\n", ar_sdio->ar->suspend_mode);
}


static DEVICE_ATTR(sleep_policy, S_IRUGO | S_IWUSR | S_IWGRP,
                   ath6kl_sleep_policy_show, ath6kl_sleep_policy_store);//创建最终的sleep_policy

static struct attribute *ath6kl_sleep_policy_attrs[] = {
        &dev_attr_sleep_policy.attr,
        NULL
};

static struct attribute_group ath6kl_sleep_policy_attribute = {
        .attrs = ath6kl_sleep_policy_attrs,
};

tatic struct kobject *wlan_properties_kobj = NULL;
static int ath6kl_sdio_probe(struct sdio_func *func,
                 const struct sdio_device_id *id)
{
    int ret;
    struct ath6kl_sdio *ar_sdio;
    struct ath6kl *ar;
    int count;

    ath6kl_dbg(ATH6KL_DBG_BOOT,
           "sdio new func %d vendor 0x%x device 0x%x block 0x%x/0x%x\n",
           func->num, func->vendor, func->device,
           func->max_blksize, func->cur_blksize);

    ar_sdio = kzalloc(sizeof(struct ath6kl_sdio), GFP_KERNEL);//申请结构体内存
    if (!ar_sdio)
        return -ENOMEM;

    ar_sdio->dma_buffer = kzalloc(HIF_DMA_BUFFER_SIZE, GFP_KERNEL); //申请dma缓冲区
    if (!ar_sdio->dma_buffer) {
        ret = -ENOMEM;
        goto err_hif;
    }
//初始化
    ar_sdio->func = func;
    sdio_set_drvdata(func, ar_sdio);

    ar_sdio->id = id;
    ar_sdio->is_disabled = true;

    spin_lock_init(&ar_sdio->lock);
    spin_lock_init(&ar_sdio->scat_lock);
    spin_lock_init(&ar_sdio->wr_async_lock);
    mutex_init(&ar_sdio->dma_buffer_mutex);

    INIT_LIST_HEAD(&ar_sdio->scat_req);
    INIT_LIST_HEAD(&ar_sdio->bus_req_freeq);
    INIT_LIST_HEAD(&ar_sdio->wr_asyncq);

    INIT_WORK(&ar_sdio->wr_async_work, ath6kl_sdio_write_async_work);
    init_waitqueue_head(&ar_sdio->irq_wq);

    for (count = 0; count < BUS_REQUEST_MAX_NUM; count++)
        ath6kl_sdio_free_bus_req(ar_sdio, &ar_sdio->bus_req[count]);

    ar = ath6kl_core_alloc(&ar_sdio->func->dev);
    if (!ar) {
        ath6kl_err("Failed to alloc ath6kl core\n");
        ret = -ENOMEM;
        goto err_dma;
    }

    ar_sdio->ar = ar;
    ar->hif_type = ATH6KL_HIF_TYPE_SDIO;
    ar->hif_priv = ar_sdio;
    ar->hif_ops = &ath6kl_sdio_ops;
    ar->bmi.max_data_size = 256;

        wlan_properties_kobj = kobject_create_and_add( \
                "android_wlan", NULL);//创建sys目录下android_wlan
        if (wlan_properties_kobj) {
                ret = sysfs_create_group(&ar_sdio->func->dev.kobj, \
                        &ath6kl_sleep_policy_attribute);
                if (ret) {
                        ath6kl_err("Fail to create sysfs android_wlan dir\n");
                        goto err_create_group;
                }

                ret = sysfs_create_link(wlan_properties_kobj, \
                        &ar_sdio->func->dev.kobj, "wlan_power");创建/sys/android_wlan/wlan_power
                if (ret) {
                        ath6kl_err("Fail to create sleep_policy link\n");
                        goto err_create_link;
                }
        } else {
                ath6kl_err("Fail to create sleep_policy link\n");
        ret = -ENOMEM;
                goto err_create_properties;
        }

    ath6kl_sdio_set_mbox_info(ar);

    ret = ath6kl_sdio_config(ar);
    if (ret) {
        ath6kl_err("Failed to config sdio: %d\n", ret);
        goto err_sdio_config;
    }

    ret = ath6kl_core_init(ar);
    if (ret) {
        ath6kl_err("Failed to init ath6kl core\n");
        goto err_sdio_config;
    }

    return ret;

err_sdio_config:
    sysfs_remove_link(wlan_properties_kobj, "sleep_policy");
err_create_link:
    sysfs_remove_group(&ar_sdio->func->dev.kobj,
                           &ath6kl_sleep_policy_attribute);
err_create_group:
    kobject_put(wlan_properties_kobj);
err_create_properties:
    ath6kl_core_free(ar_sdio->ar);
err_dma:
    kfree(ar_sdio->dma_buffer);
err_hif:
    kfree(ar_sdio);

    return ret;
}

static void ath6kl_sdio_remove(struct sdio_func *func)
{
    struct ath6kl_sdio *ar_sdio;

    ath6kl_dbg(ATH6KL_DBG_BOOT,
           "sdio removed func %d vendor 0x%x device 0x%x\n",
           func->num, func->vendor, func->device);

    ar_sdio = sdio_get_drvdata(func);

    sysfs_remove_link(wlan_properties_kobj, "sleep_policy");
    sysfs_remove_group(&ar_sdio->func->dev.kobj,
            &ath6kl_sleep_policy_attribute);
    kobject_put(wlan_properties_kobj);


    ath6kl_stop_txrx(ar_sdio->ar);
    cancel_work_sync(&ar_sdio->wr_async_work);

    ath6kl_core_cleanup(ar_sdio->ar);


    kfree(ar_sdio->dma_buffer);
    kfree(ar_sdio);

}

上层代码位置wifi sleep_policy  代码位置 wifiservice.java advancedwifisetting.java

gb实现传递的代码 wifiservice.java

   /**
         * Determines whether the Wi-Fi chipset should stay awake or be
put to
         * sleep. Looks at the setting for the sleep policy and the
current
         * conditions.
         *
         * @see #shouldDeviceStayAwake(int, int)
         */
        private void writeSleepOptions(int policy) {
            try {
                FileOutputStream os = new FileOutputStream(
                    "/sys/android_wlan/sleep_policy", true);
                if(policy == 2)
                    os.write(new byte[] { (byte)'2' });
                else if(policy == 1)
                    os.write(new byte[] { (byte)'1' });
                else
                    os.write(new byte[] { (byte)'0' });                                 
                os.close();
            } catch (Exception e) {
                Slog.w(TAG, "Failed setting sleep policy");
            }
        }

        private boolean shouldWifiStayAwake(int stayAwakeConditions, int
pluggedType) {
            int wifiSleepPolicy =
Settings.System.getInt(mContext.getContentResolver(),
                    Settings.System.WIFI_SLEEP_POLICY,
Settings.System.WIFI_SLEEP_POLICY_DEFAULT);

            if (wifiSleepPolicy ==
Settings.System.WIFI_SLEEP_POLICY_NEVER) {
                // Never sleep
                writeSleepOptions(2);
                return true;
            } else if ((wifiSleepPolicy ==
Settings.System.WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED) &&
                    (pluggedType != 0)) {
                // Never sleep while plugged, and we're plugged
                writeSleepOptions(1);
                return true;
            } else {
                // Default
                writeSleepOptions(0);
                return shouldDeviceStayAwake(stayAwakeConditions,
pluggedType);
            }
        }

gb sleep_policy高级设置默认属性 代码位置advancedwifisetting.java


    private void initSleepPolicyPreference() {
        ListPreference pref = (ListPreference) findPreference(KEY_SLEEP_POLICY);
        pref.setOnPreferenceChangeListener(this);
         int value = Settings.System.getInt(getContentResolver(),
                Settings.System.WIFI_SLEEP_POLICY,Settings. System.WIFI_SLEEP_POLICY_NEVER);
          pref.setValue(String.valueOf(value));

    }


好了,知道了睡眠策略,就可以更改默认的睡眠策略了,本人最喜欢默认为WOW。

thanks.

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值