linux/drivers/staging/ath6kl/os/linux/ar6000_android.c
<<
>>
Prefs
   1//------------------------------------------------------------------------------
   2// Copyright (c) 2004-2010 Atheros Communications Inc.
   3// All rights reserved.
   4//
   5// 
   6//
   7// Permission to use, copy, modify, and/or distribute this software for any
   8// purpose with or without fee is hereby granted, provided that the above
   9// copyright notice and this permission notice appear in all copies.
  10//
  11// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  12// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  13// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  14// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  15// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  16// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  17// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  18//
  19//
  20//
  21// Author(s): ="Atheros"
  22//------------------------------------------------------------------------------
  23#include "ar6000_drv.h"
  24#include "htc.h"
  25#include <linux/vmalloc.h>
  26#include <linux/fs.h>
  27
  28#ifdef CONFIG_HAS_WAKELOCK
  29#include <linux/wakelock.h>
  30#endif
  31#ifdef CONFIG_HAS_EARLYSUSPEND
  32#include <linux/earlysuspend.h>
  33#endif
  34
  35A_BOOL enable_mmc_host_detect_change = 0;
  36static void ar6000_enable_mmchost_detect_change(int enable);
  37
  38
  39char fwpath[256] = "/system/wifi";
  40int wowledon;
  41unsigned int enablelogcat;
  42
  43extern int bmienable;
  44extern struct net_device *ar6000_devices[];
  45extern char ifname[];
  46
  47#ifdef CONFIG_HAS_WAKELOCK
  48extern struct wake_lock ar6k_wow_wake_lock;
  49struct wake_lock ar6k_init_wake_lock;
  50#endif
  51
  52const char def_ifname[] = "wlan0";
  53module_param_string(fwpath, fwpath, sizeof(fwpath), 0644);
  54module_param(enablelogcat, uint, 0644);
  55module_param(wowledon, int, 0644);
  56
  57#ifdef CONFIG_HAS_EARLYSUSPEND
  58static int screen_is_off;
  59static struct early_suspend ar6k_early_suspend;
  60#endif
  61
  62static A_STATUS (*ar6000_avail_ev_p)(void *, void *);
  63
  64#if defined(CONFIG_ANDROID_LOGGER) && (!defined(CONFIG_MMC_MSM))
  65int logger_write(const enum logidx index,
  66                const unsigned char prio,
  67                const char __kernel * const tag,
  68                const char __kernel * const fmt,
  69                ...)
  70{
  71    int ret = 0;
  72    va_list vargs;
  73    struct file *filp = (struct file *)-ENOENT;
  74    mm_segment_t oldfs;
  75    struct iovec vec[3];
  76    int tag_bytes = strlen(tag) + 1, msg_bytes;
  77    char *msg;      
  78    va_start(vargs, fmt);
  79    msg = kvasprintf(GFP_ATOMIC, fmt, vargs);
  80    va_end(vargs);
  81    if (!msg)
  82        return -ENOMEM;
  83    if (in_interrupt()) {
  84        /* we have no choice since aio_write may be blocked */
  85        printk(KERN_ALERT "%s", msg);
  86        goto out_free_message;
  87    }
  88    msg_bytes = strlen(msg) + 1;
  89    if (msg_bytes <= 1) /* empty message? */
  90        goto out_free_message; /* don't bother, then */
  91    if ((msg_bytes + tag_bytes + 1) > 2048) {
  92        ret = -E2BIG;
  93        goto out_free_message;
  94    }
  95            
  96    vec[0].iov_base  = (unsigned char *) &prio;
  97    vec[0].iov_len    = 1;
  98    vec[1].iov_base   = (void *) tag;
  99    vec[1].iov_len    = strlen(tag) + 1;
 100    vec[2].iov_base   = (void *) msg;
 101    vec[2].iov_len    = strlen(msg) + 1; 
 102
 103    oldfs = get_fs();
 104    set_fs(KERNEL_DS);
 105    do {
 106        filp = filp_open("/dev/log/main", O_WRONLY, S_IRUSR);
 107        if (IS_ERR(filp) || !filp->f_op) {
 108            AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: filp_open /dev/log/main error\n", __FUNCTION__));
 109            ret = -ENOENT;
 110            break;
 111        }
 112
 113        if (filp->f_op->aio_write) {
 114            int nr_segs = sizeof(vec) / sizeof(vec[0]);
 115            int len = vec[0].iov_len + vec[1].iov_len + vec[2].iov_len;
 116            struct kiocb kiocb;
 117            init_sync_kiocb(&kiocb, filp);
 118            kiocb.ki_pos = 0;
 119            kiocb.ki_left = len;
 120            kiocb.ki_nbytes = len;
 121            ret = filp->f_op->aio_write(&kiocb, vec, nr_segs, kiocb.ki_pos);
 122        }
 123        
 124    } while (0);
 125
 126    if (!IS_ERR(filp)) {
 127        filp_close(filp, NULL);
 128    }
 129    set_fs(oldfs);
 130out_free_message:
 131    if (msg) {
 132        kfree(msg);
 133    }
 134    return ret;
 135}
 136#endif
 137
 138int android_logger_lv(void *module, int mask)
 139{
 140    switch (mask) {
 141    case ATH_DEBUG_ERR:
 142        return 6;
 143    case ATH_DEBUG_INFO:
 144        return 4;
 145    case ATH_DEBUG_WARN:
 146        return 5; 
 147    case ATH_DEBUG_TRC:        
 148        return 3; 
 149    default:
 150#ifdef DEBUG
 151        if (!module) {
 152            return 3;
 153        } else if (module == &GET_ATH_MODULE_DEBUG_VAR_NAME(driver)) {
 154            return (mask <=ATH_DEBUG_MAKE_MODULE_MASK(3)) ? 3 : 2;
 155        } else if (module == &GET_ATH_MODULE_DEBUG_VAR_NAME(htc)) {
 156            return 2;
 157        } else {
 158            return 3;
 159        }
 160#else
 161        return 3; /* DEBUG */
 162#endif
 163    }
 164}
 165
 166static int android_readwrite_file(const A_CHAR *filename, A_CHAR *rbuf, const A_CHAR *wbuf, size_t length)
 167{
 168    int ret = 0;
 169    struct file *filp = (struct file *)-ENOENT;
 170    mm_segment_t oldfs;
 171    oldfs = get_fs();
 172    set_fs(KERNEL_DS);
 173    do {
 174        int mode = (wbuf) ? O_RDWR : O_RDONLY;
 175        filp = filp_open(filename, mode, S_IRUSR);
 176        if (IS_ERR(filp) || !filp->f_op) {
 177            AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: file %s filp_open error\n", __FUNCTION__, filename));
 178            ret = -ENOENT;
 179            break;
 180        }
 181    
 182        if (length==0) {
 183            /* Read the length of the file only */
 184            struct inode    *inode;
 185
 186            inode = GET_INODE_FROM_FILEP(filp);
 187            if (!inode) {
 188                AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: Get inode from %s failed\n", __FUNCTION__, filename));
 189                ret = -ENOENT;
 190                break;
 191            }
 192            ret = i_size_read(inode->i_mapping->host);
 193            break;
 194        }
 195
 196        if (wbuf) {
 197            if ( (ret=filp->f_op->write(filp, wbuf, length, &filp->f_pos)) < 0) {
 198                AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: Write %u bytes to file %s error %d\n", __FUNCTION__, 
 199                                length, filename, ret));
 200                break;
 201            }
 202        } else {
 203            if ( (ret=filp->f_op->read(filp, rbuf, length, &filp->f_pos)) < 0) {
 204                AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: Read %u bytes from file %s error %d\n", __FUNCTION__,
 205                                length, filename, ret));
 206                break;
 207            }
 208        }
 209    } while (0);
 210
 211    if (!IS_ERR(filp)) {
 212        filp_close(filp, NULL);
 213    }
 214    set_fs(oldfs);
 215
 216    return ret;
 217}
 218
 219int android_request_firmware(const struct firmware **firmware_p, const char *name,
 220                     struct device *device)
 221{
 222    int ret = 0;
 223    struct firmware *firmware;
 224    char filename[256];
 225    const char *raw_filename = name;
 226        *firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL);
 227    if (!firmware) 
 228                return -ENOMEM;
 229        sprintf(filename, "%s/%s", fwpath, raw_filename);
 230    do {
 231        size_t length, bufsize, bmisize;
 232
 233        if ( (ret=android_readwrite_file(filename, NULL, NULL, 0)) < 0) {
 234            break;
 235        } else {
 236            length = ret;
 237        }
 238    
 239        bufsize = ALIGN(length, PAGE_SIZE);
 240        bmisize = A_ROUND_UP(length, 4);
 241        bufsize = max(bmisize, bufsize);
 242        firmware->data = vmalloc(bufsize);
 243        firmware->size = length;
 244        if (!firmware->data) {
 245            AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("%s: Cannot allocate buffer for firmware\n", __FUNCTION__));
 246            ret = -ENOMEM;
 247            break;
 248        }
 249    
 250        if ( (ret=android_readwrite_file(filename, (char*)firmware->data, NULL, length)) != length) {
 251            AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("%s: file read error, ret %d request %d\n", __FUNCTION__, ret, length));
 252            ret = -1;
 253            break;
 254        }
 255    
 256    } while (0);
 257
 258    if (ret<0) {
 259        if (firmware) {
 260            if (firmware->data)
 261                vfree(firmware->data);
 262            kfree(firmware);
 263        }
 264        *firmware_p = NULL;
 265    } else {
 266        ret = 0;
 267    }
 268    return ret;    
 269}
 270
 271void android_release_firmware(const struct firmware *firmware)
 272{
 273        if (firmware) {
 274        if (firmware->data)
 275            vfree(firmware->data);
 276        kfree(firmware);
 277    }
 278}
 279
 280static A_STATUS ar6000_android_avail_ev(void *context, void *hif_handle)
 281{
 282    A_STATUS ret;    
 283#ifdef CONFIG_HAS_WAKELOCK
 284    wake_lock(&ar6k_init_wake_lock);
 285#endif
 286    ar6000_enable_mmchost_detect_change(0);
 287    ret = ar6000_avail_ev_p(context, hif_handle);
 288#ifdef CONFIG_HAS_WAKELOCK
 289    wake_unlock(&ar6k_init_wake_lock);
 290#endif
 291    return ret;
 292}
 293
 294/* Useful for qualcom platform to detect our wlan card for mmc stack */
 295static void ar6000_enable_mmchost_detect_change(int enable)
 296{
 297#ifdef CONFIG_MMC_MSM
 298#define MMC_MSM_DEV "msm_sdcc.1"
 299    char buf[3];
 300    int length;
 301
 302    if (!enable_mmc_host_detect_change) {
 303        return;
 304    }
 305    length = snprintf(buf, sizeof(buf), "%d\n", enable ? 1 : 0);
 306    if (android_readwrite_file("/sys/devices/platform/" MMC_MSM_DEV "/detect_change", 
 307                               NULL, buf, length) < 0) {
 308        /* fall back to polling */
 309        android_readwrite_file("/sys/devices/platform/" MMC_MSM_DEV "/polling", NULL, buf, length);
 310    }
 311#endif
 312}
 313
 314#ifdef CONFIG_HAS_EARLYSUSPEND
 315static void android_early_suspend(struct early_suspend *h)
 316{
 317    screen_is_off = 1;
 318}
 319
 320static void android_late_resume(struct early_suspend *h)
 321{
 322    screen_is_off = 0;
 323}
 324#endif
 325
 326void android_module_init(OSDRV_CALLBACKS *osdrvCallbacks)
 327{
 328    bmienable = 1;
 329    if (ifname[0] == '\0')
 330        strcpy(ifname, def_ifname);
 331#ifdef CONFIG_HAS_WAKELOCK
 332    wake_lock_init(&ar6k_init_wake_lock, WAKE_LOCK_SUSPEND, "ar6k_init");
 333#endif
 334#ifdef CONFIG_HAS_EARLYSUSPEND
 335    ar6k_early_suspend.suspend = android_early_suspend;
 336    ar6k_early_suspend.resume  = android_late_resume;
 337    ar6k_early_suspend.level   = EARLY_SUSPEND_LEVEL_BLANK_SCREEN;
 338    register_early_suspend(&ar6k_early_suspend);
 339#endif
 340
 341    ar6000_avail_ev_p = osdrvCallbacks->deviceInsertedHandler;
 342    osdrvCallbacks->deviceInsertedHandler = ar6000_android_avail_ev;
 343
 344    ar6000_enable_mmchost_detect_change(1);
 345}
 346
 347void android_module_exit(void)
 348{
 349#ifdef CONFIG_HAS_EARLYSUSPEND
 350    unregister_early_suspend(&ar6k_early_suspend);
 351#endif
 352#ifdef CONFIG_HAS_WAKELOCK
 353    wake_lock_destroy(&ar6k_init_wake_lock);
 354#endif
 355    ar6000_enable_mmchost_detect_change(1);
 356}
 357
 358#ifdef CONFIG_PM
 359void android_ar6k_check_wow_status(AR_SOFTC_T *ar, struct sk_buff *skb, A_BOOL isEvent)
 360{
 361    if (
 362#ifdef CONFIG_HAS_EARLYSUSPEND
 363        screen_is_off && 
 364#endif 
 365            skb && ar->arConnected) {
 366        A_BOOL needWake = FALSE;
 367        if (isEvent) {
 368            if (A_NETBUF_LEN(skb) >= sizeof(A_UINT16)) {
 369                A_UINT16 cmd = *(const A_UINT16 *)A_NETBUF_DATA(skb);
 370                switch (cmd) {
 371                case WMI_CONNECT_EVENTID:
 372                case WMI_DISCONNECT_EVENTID:
 373                    needWake = TRUE;
 374                    break;
 375                default:
 376                    /* dont wake lock the system for other event */
 377                    break;
 378                }
 379            }
 380        } else if (A_NETBUF_LEN(skb) >= sizeof(ATH_MAC_HDR)) {
 381            ATH_MAC_HDR *datap = (ATH_MAC_HDR *)A_NETBUF_DATA(skb);
 382            if (!IEEE80211_IS_MULTICAST(datap->dstMac)) {
 383                switch (A_BE2CPU16(datap->typeOrLen)) {
 384                case 0x0800: /* IP */
 385                case 0x888e: /* EAPOL */
 386                case 0x88c7: /* RSN_PREAUTH */
 387                case 0x88b4: /* WAPI */
 388                     needWake = TRUE;
 389                     break;
 390                case 0x0806: /* ARP is not important to hold wake lock */
 391                default:
 392                    break;
 393                }
 394            }
 395        }
 396        if (needWake) {
 397            /* keep host wake up if there is any event and packate comming in*/
 398#ifdef CONFIG_HAS_WAKELOCK
 399            wake_lock_timeout(&ar6k_wow_wake_lock, 3*HZ);
 400#endif
 401            if (wowledon) {
 402                char buf[32];
 403                int len = sprintf(buf, "on");
 404                android_readwrite_file("/sys/power/state", NULL, buf, len);
 405
 406                len = sprintf(buf, "%d", 127);
 407                android_readwrite_file("/sys/class/leds/lcd-backlight/brightness",
 408                                       NULL, buf,len);
 409            }
 410        }
 411    }
 412}
 413#endif /* CONFIG_PM */
 414