Android wifi driver development Diary

Source: Internet
Author: User

I have been learning about android wifi for a week. Today, I will post my daily learning achievements for future reference, from the framework to the adaptation layer of wpa_supplicant (wifi. c) There are many posts on the Internet, and they are not complicated. The framework part should be noted in the wifiService and wifiMoniter sections, one is the CMD of the forwarding AP, and the other is the CMD from wpa_supplicant. They connect to the local database through the JNI method. The specific implementation method is in android_net_wifi_Wifi.cpp. In this file, we can roughly see which commands the AP will give to wpa_supplicant. These commands are run through wifi. c's wifi_command is sent to wpa_supplicant. During the command sending process, wpa_ctrl_request is called to complete the command sending. wpa_ctrl_request communicates with wpa_supplicant through socket, then, wpa_ctrl_recv is used to receive the command from wpa_supplicant and return the command ID to wifi_wait_for_event. However, since wpa_supplicant is a standard open-source project, it has been transplanted to many platforms, I haven't looked at the intermediate process yet. The concern is how wpa_supplicant sends the command to the DRIVER after receiving the upper-layer command, the parsing action of the DRIVER after receiving the command, the process of calling the DRIVER function, and the details of the DRIVER's register control. Because the code should be kept confidential, I will not mention which WIFI chip is used or the platform or product on which the Wi-Fi DRIVER is. First paste a standard wpa_supplicant structure diagram: Focus on the lower part of the diagram, that is, how wpa_supplicant is linked with the DRIVER. The whole process is currently dominated by the SCAN Command issued by the AP. Since most WIFI drivers currently support wext, we assume that our devices use the wext line. In fact, the process is similar to that of ndis. First of all, in the Driver. the hfile contains a struct wpa_driver_ops:/*** struct wpa_driver_ops-Driver interface API definition ** This structure defines the API that each driver interface needs to implement * for core wpa_supplicant code. all driver specific functionality is captured * in this wrapper. */struct wpa_driver_ops the struct is in the Driver. c is declared as: # ifdef CONFIG_DRIVER_WEXTextern struct wpa_driver_ops wpa_driver_wext_ops; /* Driver_wext.c */then fill in the struct member in driver_wext.c, const struct wpa_driver_ops wpa_driver_wext_ops = {. name = "wext ",. desc = "Linux wireless extensions (generic )",. get_bssid = wpa_driver_wext_get_bssid ,. get_ssid = wpa_driver_wext_get_ssid ,. set_wpa = wpa_driver_wext_set_wpa ,. set_key = wpa_driver_wext_set_key ,. set_countermeasures = wpa_driver_wext_set_countermeasures ,. set_drop_unencrypted = wpa _ Driver_wext_set_drop_unencrypted ,. scan = wpa_driver_wext_scan ,. combo_scan = wpa_driver_wext_combo_scan ,. get_scan_results2 = wpa_driver_wext_get_scan_results ,. deauthenticate = wpa_driver_wext_deauthenticate ,. disassociate = wpa_driver_wext_disassociate ,. set_mode = wpa_driver_wext_set_mode ,. associate = wpa_driver_wext_associate ,. set_auth_alg = wpa_driver_wext_set_auth_alg ,. init = wpa_driver _ Wext_init ,. deinit = wpa_driver_wext_deinit ,. add_pmkid = wpa_driver_wext_add_pmkid ,. remove_pmkid = wpa_driver_wext_remove_pmkid ,. flush_pmkid = wpa_driver_wext_flush_pmkid ,. get_capa = wpa_driver_wext_get_capa ,. set_operstate = wpa_driver_wext_set_operstate, # ifdef ANDROID. driver_cmd = wpa_driver_priv_driver_cmd, # endif}; these members are actually the interfaces of the driver and wpa_supplicant. Take SCAN as an example: int wpa_driver_wext_scan (void * priv, LINE1174: if (ioctl (drv-> ioctl_sock, SIOCSIWSCAN, & iwr) in const u8 * ssid, size_t ssid_len) <0) here we can see that wpa_cupplicant uses IOCTL to call SOCKET to communicate with the DRIVER, and issue the SIOCSIWSCAN command to the DRIVER. In this way, the route for a command from the AP to the FRAMEWORK to the local C ++ library and then to the wpa_supplicant adaptation layer, and then the CMD command under wpa_supplicant to the DRIVER is connected, although not much written, it is also a small achievement. It's been a very short time. It's been three weeks since I graduated. I regret that I didn't learn about WIFI in the lab. Now I have to start from scratch. Fortunately, the company environment is relatively easy, so you can have time to grasp the details. Later, we will begin to clarify the structure and process of the DRIVER. In this project, the WIFI module is controlled by the SDIO bus. Therefore, the structure of the SDIO part of the client driver is recorded first. The SDIO part is divided into three layers: sdioDrv, SdioAdapter, and SdioBusDrv. SdioBusDrv is the interface between SDIO and WIFI modules in Client Driver, SdioAdapter is the Adaptation Layer Between SdioDrv and SdioBusDrv, and SdioDrv is the interface between SDIO in Client Driver and mmc sdio in linux kernel. The three parts only need to focus on SdioDrv, and the other two layers only encapsulate it. These functions are provided in SdioDrv: (1) static struct sdio_driver tiwlan_sdio_drv = {. probe = tiwlan_sdio_probe ,. remove = tiwlan_sdio_remove ,. name = "sdio_tiwlan ",. id_table = tiwl12xx_devices,}; (2) int sdioDrv_EnableFunction (unsigned int uFunc) (3) int sdioDrv_EnableInterrupt (unsigned int uFunc) (4) Reading and Writing SDIO, actually, the static int mmc_io_rw_direct_host () function in MMC \ Core is called. The SDIO function is easy to understand. Generally, some chip manufacturers of the HOST will do well. My main task is the WIFI module. First, we can see from the entry function wlanDrvIf_ModuleInit () of the WIFI module. Here we call wlanDrvIf_Create (). Code body: static int wlanDrvIf_Create (void) {TWlanDrvIfObj * drv; // This struct represents the device, including the LINUX network device struct net_device pDrvStaticHandle = drv; /* save for module destroy */drv-> pWorkQueue = create_singlethread_workqueue (TIWLAN_DRV_NAME); // create a work queue/* Setup driver network interface. */rc = wlanDrvIf_SetupNetif (drv); // This function is very important. For details, see drv-> wl_sock = netlink_kernel_create (NETLINK_USERSOCK, 0, NULL, NULL, THIS_MOD. ULE); // Create a SOCKET interface that accepts wpa_supplicant/* Create all driver modules and link their handles */rc = drvMain_Create (drv, & drv-> tCommon. hDrvMain, & drv-> tCommon. hCmdHndlr, & drv-> tCommon. hContext, & drv-> tCommon. hTxDataQ, & drv-> tCommon. hTxMgmtQ, & drv-> tCommon. hTxCtrl, & drv-> tCommon. hTWD, & drv-> tCommon. hEvHandler, & drv-> tCommon. hsf-dispatch, & drv-> tCommon. hReport, & drv-> tCommon. hPwrState);/** Initiali Ze interrupts (or polling mode for debug): * // * Normal mode: Interrupts (the default mode) */rc = hPlatform_initInterrupt (drv, (void *) wlanDrvIf_HandleInterrupt ); return 0;} after calling the wlanDrvIf_Create () function, the initialization of the WIFI module is actually complete. The following describes how to initialize the function. First look at the body of the wlanDrvIf_SetupNetif (drv) function, static int wlanDrvIf_SetupNetif (TWlanDrvIfObj * drv) {struct net_device * dev; int res; /* Allocate network interface structure for the driver */dev = alloc_etherdev (0); // apply for a LINUX network device if (dev = NULL) /* Setup the network interface */ether_setup (dev); // create a network interface, both of which are the standard functions of the LINUX network Device Driver dev-> netdev_ops = & wlan_netdev_ops; /* Initialize Wireless Extensions interface (WEXT) */wlanDrvWext_Init (dev); res = register_netdev (dev);/* Setup power-management callbacks */hPlatform_SetupPm (scheme, wlanDrvIf_Resume, pDrvStaticHandle);} note, wlanDrvWext_Inti (dev) is initialized here, which means that the direct connection between wpa_supplicant and Driver is the WEXT path. That is to say, the event reception and processing should also be done in WEXT. Make sure that this reduces the remaining workload by 1/3, hahaha. The network device dev is also registered later. The features defined in wlan_netdev_ops are as follows: static const struct net_device_ops wlan_netdev_ops = {. ndo_open = wlanDrvIf_Open ,. ndo_stop = wlanDrvIf_Release ,. ndo_do_ioctl = NULL ,. ndo_start_xmit = wlanDrvIf_Xmit ,. ndo_get_stats = wlanDrvIf_NetGetStat ,. ndo_validate_addr = NULL,}; the function will be known at the first glance. If you don't talk about it, the corresponding commands are all available for LINUX network device drivers, for details, see chapter 16th of LINUX device driver development. After that, rc = drvMain_CreateI is called. The initialization of related modules is completed in this function. Not to mention it. The next step is to wait for the event sent by the Android upper layer. WIFI is ready to work, and most of the features required in android wifisetting are also implemented. However, there are two other problems to record here: 1. softap cannot be used 2. when you connect to the Internet through WPS, you may fail. For softap, when wifi tethering is selected in setting, softapcontroller sends a private command to the DRIVER. However, before sending a private command, the SIOCGIWPRIV command is sent to the DRIVER through IOCTL. This command is used to obtain the private commands supported by the current DRIVER. (Because SOFTAP is not standard cmd, it must be placed in a private command if it is to be supported.) Does DRIVER support private commands, or which private commands are supported depends on the Value assignment of the iw_handler_def struct in the DRIVER: const struct iw_handler_def wl_iw_handler_def = {. num_standard = ARRAYSIZE (wl_iw_handler ),. standard = (iw_handler *) wl_iw_handler ,. num_private = ARRAYSIZE (wl_iw_priv_handler ),. num_private_args = ARRAY_SIZE (wl_iw_priv_args ),. private = (iw_handler *) wl_iw_priv_handler ,. private_args = (void *) Wl_iw_priv_args,}; however, I do not know which private cmd is supported by the module. Therefore, I cannot add this item myself. I only need to contact the supplier to provide support. Now, I will wait for the support to be OK. But for Question 2, I got a big head. Sometimes it is good, sometimes it is not good. If it is not good, the hardware returns a fail, which makes it impossible for me to solve it. I don't know if WPS is inherently unstable, or what other situations are there. This may also be one of the sorrows of switching to the manufacturer instead of working in the equipment manufacturer company. Once the device has a problem, the manufacturer can only wait for the device manufacturer to solve the problem by itself, and can't do anything except to urge others! However, I am not able to access so many interesting terminal products when working in the equipment manufacturer company.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.