源码_添加wifi电源管理接口供jni调用

2817阅读 0评论2012-05-10 土豆和地瓜
分类:

源码_添加wifi电源管理接口供jni调用

===============================================================================
接收来自kernel的netlink,然后派发到所有"ATTACH"到该eth0接口的monitor_conn们
=>wpa_driver_wext_event_receive =>wpa_supplicant_event =>wpa_msg =>wpa_msg_cb
最终调用,将event发往所有"ATTACH"了的monitor_conn程序.
=>wpa_supplicant_ctrl_iface_msg_cb
===============================================================================
接收处理来自ctrl_conn或者monitor_conn发送过来的所有数据
=>wpa_supplicant_ctrl_iface_receive
=>wpa_supplicant_ctrl_iface_process
=>wpa_supplicant_driver_cmd
=>wpa_drv_driver_cmd
=>wpa_s->driver->driver_cmd就是wpa_driver_wext_ops.driver_cmd
=>wpa_driver_wext_driver_cmd
const struct wpa_driver_ops wpa_driver_wext_ops = {
    ...
    .get_bssid = wpa_driver_wext_get_bssid,
    .get_ssid = wpa_driver_wext_get_ssid,
    .set_wpa = wpa_driver_wext_set_wpa,
    .set_channel = wpa_driver_wext_set_channel,
    .set_ssid = wpa_driver_wext_set_ssid,
    .init = wpa_driver_wext_init,
    .driver_cmd = wpa_driver_wext_driver_cmd,//自己添加
    ...
};
===============================================================================
drivers/net/wireless/mrvl8688/wlan_priv.c

wlan_set_power
wlan_deepsleep_ioctl
wlan_hscfg_ioctl


struct iwreq iwr;
os_memset(&iwr, 0, sizeof(iwr));
iwr.u.power.disabled = 1;
ioctl(drv->ioctl_sock, SIOCSIWPOWER, &iwr);//主要是记住是union
//iwr对应kernel中struct ifreq *req;
sys_ioctl
=>vfs_ioctl
=>filp->f_op->unlocked_ioctl
=>sock_ioctl
=>dev_ioctl
=>wext_handle_ioctl
=>wireless_process_ioctl
=>wlan_do_ioctl

union iwreq_data
{

 char name[IFNAMSIZ];

 struct iw_point essid;
 struct iw_param nwid;
 struct iw_freq freq;

 struct iw_param sens;
 struct iw_param bitrate;
 struct iw_param txpower;
 struct iw_param rts;
 struct iw_param frag;
 __u32 mode;
 struct iw_param retry;

 struct iw_point encoding;
 struct iw_param power;
 struct iw_quality qual;

 struct sockaddr ap_addr;
 struct sockaddr addr;

 struct iw_param param;
 struct iw_point data;
};

struct iwreq
{
 union
 {
 char ifrn_name[IFNAMSIZ];
 } ifr_ifrn;

 union iwreq_data u;
};
======================================================================================
'-'表示output
'+'表示input
echo -170=0>/d/gpio
echo -96 =0>/d/gpio //必须让'='索引为4,所以需要补齐
以下添加参考iwpriv eth0 hscfg命令
iwpriv eth0 powergpio #gpio value
1.drivers/net/wireless/mrvl8688/wlan_priv.h
  >>>
  #define IWEVTXDROP    0x8C00        /* Packet dropped to excessive retry */
  而
  #define WLANPOWERGPIO            (WLANIOCTL + 32)刚好就等于0x8C00
  所以这样会导致错误,iwpriv总是提示错误
      {
     WLANPOWERGPIO,
     IW_PRIV_TYPE_INT | 16,
     IW_PRIV_TYPE_INT | 16,
     "powergpio"},
2.drivers/net/wireless/mrvl8688/wlan_priv.c
  >>>
    2.1 static int wlan_powergpio_ioctl(wlan_private * priv, struct iwreq *wrq)
    2.2 case WLANPOWERGPIO:
        ret = wlan_powergpio_ioctl(priv, wrq);
static int
wlan_powergpio_ioctl(wlan_private * priv, struct iwreq *wrq)
{
    wlan_adapter *Adapter = priv->adapter;
    int data[2] = { -1, 0xff};
    int ret = WLAN_STATUS_SUCCESS;

    if (wrq->u.data.length >= 1 && wrq->u.data.length <= 2) {
        if (copy_from_user(data, wrq->u.data.pointer, sizeof(int) * wrq->u.data.length)) {
            PRINTM(INFO, "Copy from user failed\n");
            return -EFAULT;
        }
        PRINTM(INFO,
               "wlan_powergpio_ioctl: data[0]=%#08x, data[1]=%#02x\n",
               data[0], data[1]);
    } else {
        PRINTM(MSG, "Sample: iwpriv eth0 powergpio #gpio [value]\n");
        return -EINVAL;
    }
    
    switch(wrq->u.data.length) {
        case 2:
            if(data[0] < ARCH_NR_GPIOS) {
                //if(!(ret = gpio_request(mfp_to_gpio(data[0]), "powergpio"))) {
                    //mfp_cfg_t powergpio_mfp_cfg = (mfp_to_gpio(data[0]) << 16) | MFPR_DEFAULT | MFP_AF0;
                    //pxa3xx_mfp_config(&powergpio_mfp_cfg, 1);
                    ret = gpio_direction_output(mfp_to_gpio(data[0]), data[1]);
                //}
            } else {
                ret = -EINVAL;
            }
            break;
    }
    
    if(ret >= 0) {
        data[0] = data[0];
        data[1] = gpio_get_value(mfp_to_gpio(data[0]));//read gpio value;
        wrq->u.data.length = 2;
        if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * wrq->u.data.length)) {
            PRINTM(INFO, "Copy to user failed\n");
            return -EFAULT;
        }
    }
    return ret;
}
======================================================================================
int wpa_driver_wext_driver_cmd( void *priv, char *cmd, char *buf, size_t buf_len )
{
    ...
    if (os_strncasecmp(cmd, "POWERMODE", sizeof("POWERMODE") - 1) == 0) {
        //wpa_printf(MSG_DEBUG, "POWERMODE command = \"%s\"", cmd);
        ret = wpa_driver_wext_powermode(drv, atoi(strchr(cmd, ' ')));
    }
    ...
}

static inline int
iw_get_ext(int            skfd,        /* Socket to the kernel */
     const char * ifname,        /* Device name */
     int             request,    /* WE ID */
     struct iwreq* piwr)        /* Fixed part of the request */
{
  os_strncpy(piwr->ifr_name, ifname, IFNAMSIZ);
  return(ioctl(skfd, request, piwr));
}
static int
wpa_driver_wext_powermode(struct wpa_driver_wext_data *drv, int mode)
{
#define ANDROID_DRIVER_POWER_MODE_AUTO 0
#define ANDROID_DRIVER_POWER_MODE_ACTIVE 1
#define ANDROID_DRIVER_POWER_MODE_DEEPSLEEP 2
#define ANDROID_DRIVER_POWER_MODE_DEEPSLEEP_EXIT 3
    struct iwreq iwr;
    int request_cmd;
    char buffer[16];
    int ret = -1;
    const char *ifname = drv->ifname;
    int skfd = drv->ioctl_sock;

    os_memset(&iwr, 0, sizeof(iwr));
    switch (mode) {
        case ANDROID_DRIVER_POWER_MODE_AUTO:
            request_cmd = SIOCSIWPOWER;
            iwr.u.power.disabled = 1;
            break;
        case ANDROID_DRIVER_POWER_MODE_ACTIVE:
            /* get power info */
            if ((ret = iw_get_ext(skfd, ifname, SIOCGIWPOWER, &iwr)) < 0) {
                fprintf(stderr, "ANDROID_DRIVER_POWER_MODE_AUTO erro\n");
                goto __wpa_driver_wext_powermode_out;
            }
            request_cmd = SIOCSIWPOWER;
            iwr.u.power.flags = 0;
            iwr.u.power.disabled = 0;
            break;
        case ANDROID_DRIVER_POWER_MODE_DEEPSLEEP:
            request_cmd = WLANDEEPSLEEP;
            buffer[0] = '1';
            iwr.u.data.pointer = (caddr_t) buffer;
            iwr.u.data.length = 1;
            break;
        case ANDROID_DRIVER_POWER_MODE_DEEPSLEEP_EXIT:
            request_cmd = WLANDEEPSLEEP;
            buffer[0] = '0';
            iwr.u.data.pointer = (caddr_t) buffer;
            iwr.u.data.length = 1;
            break;
        default:
            goto __wpa_driver_wext_powermode_out;
            break;
    }

    ret = iw_get_ext(skfd, ifname, request_cmd, &iwr);
__wpa_driver_wext_powermode_out:
    return ret;
}
======================================================================================
./wpa_supplicant -c ./wpa_supplicant.conf -i eth0 &
./iwpriv eth0 drvdbg 0x6002007f
./wpa_cli
> driver powermode 0
> driver powermode 1
> driver powermode 2
> driver powermode 3

上一篇:[原创]WPA_SUPPLICANT源码分析(1):EVENT LOOP的实现
下一篇:Wi-Fi Direct 亲身体验