mirror of
https://github.com/genesi/linux-legacy.git
synced 2026-09-24 07:36:26 +00:00
Firmware will be copied to the /lib/firmware/ath6k/AR6102 directory so change the path in the driver. Signed-off-by: Alan Tull <r80115@freescale.com>
622 lines
18 KiB
C
622 lines
18 KiB
C
/*
|
|
*
|
|
* Copyright (c) 2004-2010 Atheros Communications Inc.
|
|
* All rights reserved.
|
|
*
|
|
*
|
|
// This program is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License version 2 as
|
|
// published by the Free Software Foundation;
|
|
//
|
|
// Software distributed under the License is distributed on an "AS
|
|
// IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
// implied. See the License for the specific language governing
|
|
// rights and limitations under the License.
|
|
//
|
|
//
|
|
*
|
|
*/
|
|
#include "ar6000_drv.h"
|
|
#include "htc.h"
|
|
#include <linux/vmalloc.h>
|
|
|
|
#include <linux/fs.h>
|
|
#ifdef CONFIG_PM
|
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
|
|
#include <linux/wakelock.h>
|
|
#endif
|
|
enum {
|
|
WLAN_PWR_CTRL_UP = 0,
|
|
WLAN_PWR_CTRL_CUT_PWR,
|
|
WLAN_PWR_CTRL_DEEP_SLEEP,
|
|
WLAN_PWR_CTRL_WOW
|
|
};
|
|
#include <linux/platform_device.h>
|
|
#include <linux/inetdevice.h>
|
|
|
|
#define IS_MAC_NULL(mac) (mac[0]==0 && mac[1]==0 && mac[2]==0 && mac[3]==0 && mac[4]==0 && mac[5]==0)
|
|
#define MAX_BUF (8*1024)
|
|
|
|
#ifdef DEBUG
|
|
|
|
#define ATH_DEBUG_DBG_LOG ATH_DEBUG_MAKE_MODULE_MASK(0)
|
|
|
|
static ATH_DEBUG_MASK_DESCRIPTION android_debug_desc[] = {
|
|
{ ATH_DEBUG_DBG_LOG , "Android Debug Logs"},
|
|
};
|
|
|
|
ATH_DEBUG_INSTANTIATE_MODULE_VAR(android,
|
|
"android",
|
|
"Android Driver Interface",
|
|
ATH_DEBUG_MASK_DEFAULTS | ATH_DEBUG_DBG_LOG,
|
|
ATH_DEBUG_DESCRIPTION_COUNT(android_debug_desc),
|
|
android_debug_desc);
|
|
|
|
#endif
|
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
|
|
char fwpath[256] = "/lib/firmware/ath6k/AR6102";
|
|
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) */
|
|
int buspm = WLAN_PWR_CTRL_CUT_PWR;
|
|
int wow2mode = WLAN_PWR_CTRL_CUT_PWR;
|
|
#define HAVE_WLAN_PWR_IMPL 0
|
|
#if HAVE_WLAN_PWR_IMPL
|
|
/** @brief Disable SDIO clock source and mask all interrupt */
|
|
extern void plat_disable_wlan_slot(void);
|
|
/** @brief Enable SDIO clock source and unmask all interrupt */
|
|
extern void plat_enable_wlan_slot(void);
|
|
#else
|
|
#define plat_disable_wlan_slot()
|
|
#define plat_enable_wlan_slot()
|
|
#endif
|
|
|
|
#endif /* CONFIG_PM */
|
|
extern int bmienable;
|
|
extern int wlaninitmode;
|
|
extern unsigned int wmitimeout;
|
|
extern wait_queue_head_t arEvent;
|
|
extern struct net_device *ar6000_devices[];
|
|
#ifdef CONFIG_HOST_TCMD_SUPPORT
|
|
extern unsigned int testmode;
|
|
#endif
|
|
extern char ifname[];
|
|
|
|
const char def_ifname[] = "wlan0";
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
|
|
module_param_string(fwpath, fwpath, sizeof(fwpath), 0644);
|
|
module_param(buspm, int, 0644);
|
|
#else
|
|
#define __user
|
|
/* for linux 2.4 and lower */
|
|
MODULE_PARM(buspm,"i");
|
|
#endif
|
|
|
|
struct wake_lock ar6k_init_wake_lock;
|
|
struct wake_lock ar6k_wow_wake_lock;
|
|
static A_STATUS (*ar6000_avail_ev_p)(void *, void *);
|
|
|
|
extern int ar6000_init(struct net_device *dev);
|
|
extern A_STATUS ar6000_configure_target(AR_SOFTC_T *ar);
|
|
extern void ar6000_stop_endpoint(struct net_device *dev, A_BOOL keepprofile);
|
|
extern A_STATUS ar6000_sysfs_bmi_get_config(AR_SOFTC_T *ar, A_UINT32 mode);
|
|
extern void ar6000_destroy(struct net_device *dev, unsigned int unregister);
|
|
|
|
static void ar6000_enable_mmchost_detect_change(int enable);
|
|
static void ar6000_restart_endpoint(struct net_device *dev);
|
|
|
|
#if defined(CONFIG_PM)
|
|
static A_STATUS ar6000_suspend_ev(void *context);
|
|
|
|
static A_STATUS ar6000_resume_ev(void *context);
|
|
#endif
|
|
|
|
int android_request_firmware(const struct firmware **firmware_p, const char *name,
|
|
struct device *device)
|
|
{
|
|
struct file *filp = (struct file *)-ENOENT;
|
|
int ret = 0;
|
|
mm_segment_t oldfs;
|
|
struct firmware *firmware;
|
|
char filename[2048];
|
|
#if 0
|
|
const char *raw_filename = strrchr(name, '/');
|
|
#else
|
|
const char *raw_filename = NULL;
|
|
#endif
|
|
*firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL);
|
|
if (!firmware)
|
|
return -ENOMEM;
|
|
if (raw_filename)
|
|
++raw_filename;
|
|
else
|
|
raw_filename = name;
|
|
sprintf(filename, "%s/%s", fwpath, raw_filename);
|
|
// Open file
|
|
oldfs = get_fs();
|
|
set_fs(KERNEL_DS);
|
|
do {
|
|
size_t length, bufsize, bmisize;
|
|
struct inode *inode;
|
|
filp = filp_open(filename, O_RDONLY, S_IRUSR);
|
|
if (IS_ERR(filp) || !filp->f_op) {
|
|
printk("%s: file %s filp_open error\n", __FUNCTION__, filename);
|
|
ret = -1;
|
|
break;
|
|
}
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
|
|
inode = filp->f_path.dentry->d_inode;
|
|
#else
|
|
inode = filp->f_dentry->d_inode;
|
|
#endif
|
|
if (!inode) {
|
|
printk("%s: Get inode from filp failed\n", __FUNCTION__);
|
|
ret = -1;
|
|
break;
|
|
}
|
|
length = i_size_read(inode->i_mapping->host);
|
|
bufsize = ALIGN(length, PAGE_SIZE);
|
|
bmisize = A_ROUND_UP(length, 4);
|
|
bufsize = max(bmisize, bufsize);
|
|
firmware->data = vmalloc(bufsize);
|
|
firmware->size = bmisize;
|
|
if (!firmware->data) {
|
|
printk("Cannot allocate buffer for firmware\n");
|
|
ret = -ENOMEM;
|
|
break;
|
|
}
|
|
if (filp->f_op->read(filp, (char*)firmware->data, length, &filp->f_pos) != length) {
|
|
printk("%s: file read error, remaining=%d\n", __FUNCTION__, length);
|
|
ret = -1;
|
|
break;
|
|
}
|
|
} while (0);
|
|
|
|
if (!IS_ERR(filp)) {
|
|
filp_close(filp, NULL);
|
|
}
|
|
set_fs(oldfs);
|
|
|
|
if (ret!=0) {
|
|
if (firmware) {
|
|
if (firmware->data)
|
|
vfree(firmware->data);
|
|
kfree(firmware);
|
|
}
|
|
*firmware_p = NULL;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void android_release_firmware(const struct firmware *firmware)
|
|
{
|
|
if (firmware) {
|
|
if (firmware->data)
|
|
vfree(firmware->data);
|
|
kfree(firmware);
|
|
}
|
|
}
|
|
|
|
#if defined(CONFIG_PM)
|
|
static void ar6k_send_asleep_event_to_app(AR_SOFTC_T *ar, A_BOOL asleep)
|
|
{
|
|
char buf[128];
|
|
union iwreq_data wrqu;
|
|
|
|
snprintf(buf, sizeof(buf), "HOST_ASLEEP=%s", asleep ? "asleep" : "awake");
|
|
A_MEMZERO(&wrqu, sizeof(wrqu));
|
|
wrqu.data.length = strlen(buf);
|
|
wireless_send_event(ar->arNetDev, IWEVCUSTOM, &wrqu, buf);
|
|
}
|
|
|
|
static void ar6000_wow_resume(AR_SOFTC_T *ar)
|
|
{
|
|
if (ar->arWowState) {
|
|
WMI_SET_HOST_SLEEP_MODE_CMD hostSleepMode = {TRUE, FALSE};
|
|
ar->arWowState = 0;
|
|
wmi_set_host_sleep_mode_cmd(ar->arWmi, &hostSleepMode);
|
|
wmi_scanparams_cmd(ar->arWmi, 0,0,60,0,0,0,0,0,0,0);
|
|
//wmi_set_keepalive_cmd(ar->arWmi, 0);
|
|
|
|
#if 1 /* we don't do it if the power consumption is already good enough. */
|
|
if (wmi_listeninterval_cmd(ar->arWmi, ar->arListenInterval, 0) == A_OK) {
|
|
}
|
|
#endif
|
|
ar6k_send_asleep_event_to_app(ar, FALSE);
|
|
if (ar->arTxPending[ar->arControlEp]) {
|
|
long timeleft = wait_event_interruptible_timeout(arEvent,
|
|
ar->arTxPending[ar->arControlEp] == 0, wmitimeout * HZ);
|
|
if (!timeleft || signal_pending(current)) {
|
|
printk("Failed to Resume Wow!!!!!!!!!!!!!!!!!!!!\n");
|
|
} else {
|
|
printk("Resume WoW successfully\n");
|
|
}
|
|
}
|
|
} else {
|
|
printk("WoW does not invoked. skip resume");
|
|
}
|
|
}
|
|
|
|
static void ar6000_wow_suspend(AR_SOFTC_T *ar)
|
|
{
|
|
#define ANDROID_WOW_LIST_ID 1
|
|
if (ar->arNetworkType != AP_NETWORK) {
|
|
/* Setup WoW for unicast & Aarp request for our own IP
|
|
disable background scan. Set listen interval into 1000 TUs
|
|
Enable keepliave for 110 seconds
|
|
*/
|
|
struct in_ifaddr **ifap = NULL;
|
|
struct in_ifaddr *ifa = NULL;
|
|
struct in_device *in_dev;
|
|
A_UINT8 macMask[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
|
A_STATUS status;
|
|
WMI_ADD_WOW_PATTERN_CMD addWowCmd = { .filter = { 0 } };
|
|
WMI_DEL_WOW_PATTERN_CMD delWowCmd;
|
|
WMI_SET_HOST_SLEEP_MODE_CMD hostSleepMode = {FALSE, TRUE};
|
|
WMI_SET_WOW_MODE_CMD wowMode = { .enable_wow = TRUE };
|
|
|
|
ar6000_TxDataCleanup(ar); /* IMPORTANT, otherwise there will be 11mA after listen interval as 1000*/
|
|
|
|
#if 1 /* we don't do it if the power consumption is already good enough. */
|
|
if (wmi_listeninterval_cmd(ar->arWmi, A_MAX_WOW_LISTEN_INTERVAL, 0) == A_OK) {
|
|
}
|
|
#endif
|
|
|
|
// wmi_set_keepalive_cmd(ar->arWmi, 110); /* keepalive otherwise, we will be disconnected*/
|
|
status = wmi_scanparams_cmd(ar->arWmi, 0,0,0xffff,0,0,0,0,0,0,0);
|
|
wmi_set_wow_mode_cmd(ar->arWmi, &wowMode);
|
|
|
|
/* clear up our WoW pattern first */
|
|
delWowCmd.filter_list_id = ANDROID_WOW_LIST_ID;
|
|
delWowCmd.filter_id = 0;
|
|
wmi_del_wow_pattern_cmd(ar->arWmi, &delWowCmd);
|
|
|
|
/* setup unicast packet pattern for WoW */
|
|
if (ar->arNetDev->dev_addr[1]) {
|
|
addWowCmd.filter_list_id = ANDROID_WOW_LIST_ID;
|
|
addWowCmd.filter_size = 6; /* MAC address */
|
|
addWowCmd.filter_offset = 2;
|
|
status = wmi_add_wow_pattern_cmd(ar->arWmi, &addWowCmd, ar->arNetDev->dev_addr, macMask, addWowCmd.filter_size);
|
|
}
|
|
/* setup ARP request for our own IP */
|
|
if ((in_dev = __in_dev_get_rtnl(ar->arNetDev)) != NULL) {
|
|
for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; ifap = &ifa->ifa_next) {
|
|
if (!strcmp(ar->arNetDev->name, ifa->ifa_label)) {
|
|
break; /* found */
|
|
}
|
|
}
|
|
}
|
|
if (ifa && ifa->ifa_local) {
|
|
WMI_SET_IP_CMD ipCmd;
|
|
memset(&ipCmd, 0, sizeof(ipCmd));
|
|
ipCmd.ips[0] = ifa->ifa_local;
|
|
status = wmi_set_ip_cmd(ar->arWmi, &ipCmd);
|
|
}
|
|
ar6k_send_asleep_event_to_app(ar, TRUE);
|
|
wmi_set_host_sleep_mode_cmd(ar->arWmi, &hostSleepMode);
|
|
if (ar->arTxPending[ar->arControlEp]) {
|
|
long timeleft = wait_event_interruptible_timeout(arEvent,
|
|
ar->arTxPending[ar->arControlEp] == 0, wmitimeout * HZ);
|
|
if (!timeleft || signal_pending(current)) {
|
|
/* what can I do? wow resume at once */
|
|
printk("Fail to setup WoW\n");
|
|
} else {
|
|
ar->arWowState = 1;
|
|
printk("Setup WoW successfully\n");
|
|
}
|
|
}
|
|
mdelay(10);
|
|
} else {
|
|
printk("Not allowed to go to WOW at this moment.\n");
|
|
}
|
|
}
|
|
|
|
static void ar6000_pwr_on(AR_SOFTC_T *ar)
|
|
{
|
|
if (ar == NULL) {
|
|
/* turn on for all cards */
|
|
}
|
|
printk("%s --enter\n", __func__);
|
|
|
|
}
|
|
|
|
static void ar6000_pwr_down(AR_SOFTC_T *ar)
|
|
{
|
|
if (ar == NULL) {
|
|
/* shutdown for all cards */
|
|
}
|
|
printk("%s --enter\n", __func__);
|
|
|
|
}
|
|
|
|
static A_STATUS ar6000_suspend_ev(void *context)
|
|
{
|
|
int pmmode = buspm;
|
|
AR_SOFTC_T *ar = (AR_SOFTC_T *)context;
|
|
printk("%s: enter ar %p devices %p\n", __func__, ar, ar6000_devices[0]? netdev_priv(ar6000_devices[0]) : NULL);
|
|
|
|
wow_not_connected:
|
|
|
|
switch (pmmode) {
|
|
case WLAN_PWR_CTRL_DEEP_SLEEP:
|
|
ar6000_set_wlan_state(ar, WLAN_DISABLED);
|
|
ar->arOsPowerCtrl = WLAN_PWR_CTRL_DEEP_SLEEP;
|
|
return A_EBUSY;
|
|
case WLAN_PWR_CTRL_WOW:
|
|
if (ar->arWmiReady && ar->arWlanState==WLAN_ENABLED && ar->arConnected) {
|
|
ar->arOsPowerCtrl = WLAN_PWR_CTRL_WOW;
|
|
/* leave for pm_device to setup wow */
|
|
return A_EBUSY;
|
|
} else {
|
|
pmmode = wow2mode;
|
|
goto wow_not_connected;
|
|
}
|
|
break;
|
|
case WLAN_PWR_CTRL_CUT_PWR:
|
|
/* fall through */
|
|
default:
|
|
ar->arOsPowerCtrl = WLAN_PWR_CTRL_CUT_PWR;
|
|
ar6000_stop_endpoint(ar->arNetDev, TRUE);
|
|
ar->arWlanState = WLAN_DISABLED;
|
|
break;
|
|
}
|
|
return A_OK;
|
|
}
|
|
|
|
static A_STATUS ar6000_resume_ev(void *context)
|
|
{
|
|
AR_SOFTC_T *ar = (AR_SOFTC_T *)context;
|
|
A_UINT16 powerCtrl = ar->arOsPowerCtrl;
|
|
wake_lock(&ar6k_init_wake_lock);
|
|
printk("%s: enter\n", __func__);
|
|
ar->arOsPowerCtrl = WLAN_PWR_CTRL_UP;
|
|
switch (powerCtrl) {
|
|
case WLAN_PWR_CTRL_WOW:
|
|
printk("Warning! resume but osPowerCtl is not clear\n");
|
|
break;
|
|
case WLAN_PWR_CTRL_CUT_PWR:
|
|
ar6000_restart_endpoint(ar->arNetDev);
|
|
break;
|
|
case WLAN_PWR_CTRL_DEEP_SLEEP:
|
|
ar6000_set_wlan_state(ar, WLAN_ENABLED);
|
|
break;
|
|
default:
|
|
printk("Strange SDIO bus power mode!!\n");
|
|
break;
|
|
}
|
|
wake_unlock(&ar6k_init_wake_lock);
|
|
return A_OK;
|
|
}
|
|
|
|
static A_STATUS ar6000_android_avail_ev(void *context, void *hif_handle)
|
|
{
|
|
A_STATUS ret;
|
|
wake_lock(&ar6k_init_wake_lock);
|
|
ret = ar6000_avail_ev_p(context, hif_handle);
|
|
wake_unlock(&ar6k_init_wake_lock);
|
|
return ret;
|
|
}
|
|
|
|
|
|
static int ar6000_pm_suspend(struct platform_device *dev, pm_message_t state)
|
|
{
|
|
int i;
|
|
for (i = 0; i < MAX_AR6000; i++) {
|
|
AR_SOFTC_T *ar;
|
|
|
|
if (ar6000_devices[i] == NULL)
|
|
continue;
|
|
ar = (AR_SOFTC_T*)netdev_priv(ar6000_devices[i]);
|
|
printk("%s: enter\n", __func__);
|
|
switch (ar->arOsPowerCtrl) {
|
|
case WLAN_PWR_CTRL_CUT_PWR:
|
|
ar6000_pwr_down(ar);
|
|
break;
|
|
case WLAN_PWR_CTRL_WOW:
|
|
ar6000_wow_suspend(ar);
|
|
plat_disable_wlan_slot();
|
|
break;
|
|
case WLAN_PWR_CTRL_DEEP_SLEEP:
|
|
/* nothing to do. keep the power on */
|
|
break;
|
|
default:
|
|
printk("Something is strange for ar6000_pm_suspend %d\n", ar->arOsPowerCtrl);
|
|
break;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int ar6000_pm_resume(struct platform_device *dev)
|
|
{
|
|
int i;
|
|
for (i = 0; i < MAX_AR6000; i++) {
|
|
AR_SOFTC_T *ar;
|
|
|
|
if (ar6000_devices[i] == NULL)
|
|
continue;
|
|
printk("%s: enter\n", __func__);
|
|
ar = (AR_SOFTC_T*)netdev_priv(ar6000_devices[i]);
|
|
switch (ar->arOsPowerCtrl) {
|
|
case WLAN_PWR_CTRL_CUT_PWR:
|
|
ar6000_pwr_on(ar);
|
|
break;
|
|
case WLAN_PWR_CTRL_WOW:
|
|
wake_lock_timeout(&ar6k_wow_wake_lock, 3*HZ);
|
|
plat_enable_wlan_slot();
|
|
ar6000_wow_resume(ar);
|
|
ar->arOsPowerCtrl = WLAN_PWR_CTRL_UP;
|
|
break;
|
|
case WLAN_PWR_CTRL_DEEP_SLEEP:
|
|
/* nothing to do. keep the power on */
|
|
break;
|
|
default:
|
|
printk("Something is strange for ar6000_pm_resume %d\n", ar->arOsPowerCtrl);
|
|
break;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int ar6000_pm_probe(struct platform_device *pdev)
|
|
{
|
|
ar6000_pwr_on(NULL);
|
|
return 0;
|
|
}
|
|
|
|
static int ar6000_pm_remove(struct platform_device *pdev)
|
|
{
|
|
ar6000_pwr_down(NULL);
|
|
return 0;
|
|
}
|
|
|
|
static struct platform_driver ar6000_pm_device = {
|
|
.probe = ar6000_pm_probe,
|
|
.remove = ar6000_pm_remove,
|
|
.suspend = ar6000_pm_suspend,
|
|
.resume = ar6000_pm_resume,
|
|
.driver = {
|
|
.name = "wlan_ar6000_pm_dev",
|
|
},
|
|
};
|
|
#endif /* CONFIG_PM */
|
|
|
|
/* Useful for qualcom platform to detect our wlan card for mmc stack */
|
|
static void ar6000_enable_mmchost_detect_change(int enable)
|
|
{
|
|
#ifdef CONFIG_MMC_MSM
|
|
mm_segment_t oldfs;
|
|
struct file *filp = (struct file*)-ENOENT;
|
|
int length;
|
|
oldfs = get_fs();
|
|
set_fs(KERNEL_DS);
|
|
do {
|
|
char buf[3];
|
|
filp = filp_open("/sys/devices/platform/msm_sdcc.2/detect_change", O_RDWR, S_IRUSR);
|
|
if (IS_ERR(filp) || !filp->f_op)
|
|
break;
|
|
length = snprintf(buf, sizeof(buf), "%d\n", enable ? 1 : 0);
|
|
if (filp->f_op->write(filp, buf, length, &filp->f_pos) != length) {
|
|
break;
|
|
}
|
|
} while (0);
|
|
if (!IS_ERR(filp)) {
|
|
filp_close(filp, NULL);
|
|
}
|
|
set_fs(oldfs);
|
|
#endif
|
|
}
|
|
|
|
static void
|
|
ar6000_restart_endpoint(struct net_device *dev)
|
|
{
|
|
A_STATUS status = A_OK;
|
|
AR_SOFTC_T *ar = (AR_SOFTC_T*)netdev_priv(dev);
|
|
if (down_interruptible(&ar->arSem)) {
|
|
AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s(): down_interruptible failed \n", __func__));
|
|
return ;
|
|
}
|
|
if (ar->bIsDestroyProgress) {
|
|
up(&ar->arSem);
|
|
return;
|
|
}
|
|
BMIInit();
|
|
do {
|
|
A_BOOL rtnl_lock_held_on_entry;
|
|
if ( (status=ar6000_configure_target(ar))!=A_OK)
|
|
break;
|
|
if ( (status=ar6000_sysfs_bmi_get_config(ar, wlaninitmode)) != A_OK)
|
|
{
|
|
AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("ar6000_avail: ar6000_sysfs_bmi_get_config failed\n"));
|
|
break;
|
|
}
|
|
rtnl_lock_held_on_entry = rtnl_trylock();
|
|
status = (ar6000_init(dev)==0) ? A_OK : A_ERROR;
|
|
if (rtnl_lock_held_on_entry) {
|
|
rtnl_unlock();
|
|
}
|
|
if (status!=A_OK) {
|
|
break;
|
|
}
|
|
ar->arWlanState = WLAN_ENABLED;
|
|
if (ar->arSsidLen) {
|
|
ar6000_connect_to_ap(ar);
|
|
}
|
|
} while (0);
|
|
|
|
up(&ar->arSem);
|
|
if (status==A_OK) {
|
|
return;
|
|
}
|
|
|
|
ar6000_devices[ar->arDeviceIndex] = NULL;
|
|
ar6000_destroy(ar->arNetDev, 1);
|
|
}
|
|
|
|
void android_module_init(OSDRV_CALLBACKS *osdrvCallbacks)
|
|
{
|
|
ar6000_enable_mmchost_detect_change(1);
|
|
bmienable = 1;
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
|
|
if (ifname[0] == '\0')
|
|
strcpy(ifname, def_ifname);
|
|
#endif
|
|
if (wow2mode!=WLAN_PWR_CTRL_CUT_PWR && wow2mode!=WLAN_PWR_CTRL_DEEP_SLEEP) {
|
|
wow2mode=WLAN_PWR_CTRL_CUT_PWR;
|
|
}
|
|
|
|
wake_lock_init(&ar6k_init_wake_lock, WAKE_LOCK_SUSPEND, "ar6k_init");
|
|
wake_lock_init(&ar6k_wow_wake_lock, WAKE_LOCK_SUSPEND, "ar6k_wow");
|
|
|
|
#if defined(CONFIG_PM)
|
|
osdrvCallbacks->deviceSuspendHandler = ar6000_suspend_ev;
|
|
osdrvCallbacks->deviceResumeHandler = ar6000_resume_ev;
|
|
#endif
|
|
ar6000_avail_ev_p = osdrvCallbacks->deviceInsertedHandler;
|
|
osdrvCallbacks->deviceInsertedHandler = ar6000_android_avail_ev;
|
|
|
|
#if defined(CONFIG_PM)
|
|
/* Register ar6000_pm_device into system.
|
|
* We should also add platform_device into the first item of array devices[] in
|
|
* file arch/xxx/mach-xxx/board-xxxx.c
|
|
* Otherwise, WoW may not work properly since we may trigger WoW GPIO before system suspend
|
|
*/
|
|
if (platform_driver_register(&ar6000_pm_device))
|
|
printk("ar6000: fail to register the power control driver.\n");
|
|
#endif
|
|
}
|
|
|
|
void android_module_exit(void)
|
|
{
|
|
wake_lock_destroy(&ar6k_wow_wake_lock);
|
|
wake_lock_destroy(&ar6k_init_wake_lock);
|
|
|
|
#ifdef CONFIG_PM
|
|
platform_driver_unregister(&ar6000_pm_device);
|
|
#endif
|
|
ar6000_enable_mmchost_detect_change(1);
|
|
}
|
|
|
|
A_BOOL android_ar6k_endpoint_is_stop(AR_SOFTC_T *ar)
|
|
{
|
|
#ifdef CONFIG_PM
|
|
return ar->arOsPowerCtrl == WLAN_PWR_CTRL_CUT_PWR;
|
|
#else
|
|
return FALSE;
|
|
#endif
|
|
}
|
|
|
|
void android_ar6k_check_wow_status(AR_SOFTC_T *ar)
|
|
{
|
|
#ifdef CONFIG_PM
|
|
if (ar->arWowState) {
|
|
ar6000_wow_resume(ar);
|
|
}
|
|
#endif /* CONFIG_PM */
|
|
}
|
|
|
|
A_STATUS android_ar6k_start(AR_SOFTC_T *ar)
|
|
{
|
|
return A_OK;
|
|
}
|