OSDN Git Service

wifi: auto-detect the module name and path
authorChih-Wei Huang <cwhuang@linux.org.tw>
Mon, 28 Nov 2011 08:15:39 +0000 (16:15 +0800)
committerChih-Wei Huang <cwhuang@linux.org.tw>
Thu, 5 May 2016 09:45:06 +0000 (17:45 +0800)
wifi/wifi.c

index e5a0252..a73b6bc 100644 (file)
@@ -97,6 +97,7 @@ static char primary_iface[PROPERTY_VALUE_MAX];
 #endif
 
 #define WIFI_DRIVER_LOADER_DELAY       1000000
+#define SYSFS_PATH_MAX                 256
 
 static const char IFACE_DIR[]           = "/data/system/wpa_supplicant";
 #ifdef WIFI_DRIVER_MODULE_PATH
@@ -115,6 +116,9 @@ static const char SUPP_CONFIG_FILE[]    = "/data/misc/wifi/wpa_supplicant.conf";
 static const char P2P_CONFIG_FILE[]     = "/data/misc/wifi/p2p_supplicant.conf";
 static const char CONTROL_IFACE_PATH[]  = "/data/misc/wifi/sockets";
 static const char MODULE_FILE[]         = "/proc/modules";
+static const char SYSFS_CLASS_NET[]     = "/sys/class/net";
+static const char MODULE_DEFAULT_DIR[]  = "/system/lib/modules";
+static const char SYS_MOD_NAME_DIR[]    = "device/driver/module";
 
 static const char IFNAME[]              = "IFNAME=";
 #define IFNAMELEN                      (sizeof(IFNAME) - 1)
@@ -213,17 +217,90 @@ int wifi_change_driver_state(const char *state)
 }
 #endif
 
+#ifdef WIFI_DRIVER_MODULE_PATH
+static int get_driver_path(const char *mod, const char *path, char *buf) {
+    DIR *dir;
+    struct dirent *de;
+    char modpath[SYSFS_PATH_MAX];
+    int ret = 0;
+
+    if ((dir = opendir(path))) {
+        while ((de = readdir(dir))) {
+            struct stat sb;
+            if (de->d_name[0] == '.')
+                continue;
+            snprintf(modpath, SYSFS_PATH_MAX, "%s/%s", path, de->d_name);
+            if (!strcmp(de->d_name, mod)) {
+                strncpy(buf, modpath, SYSFS_PATH_MAX - 1);
+                buf[SYSFS_PATH_MAX - 1] = '\0';
+                ret = 1;
+                break;
+            }
+            if (!stat(modpath, &sb) && (sb.st_mode & S_IFMT) == S_IFDIR)
+                if ((ret = get_driver_path(mod, modpath, buf)))
+                    break;
+        }
+        closedir(dir);
+    }
+    return ret;
+}
+
+static int get_driver_info(char *buf) {
+    DIR *netdir;
+    struct dirent *de;
+    char path[SYSFS_PATH_MAX];
+    char link[SYSFS_PATH_MAX];
+    int ret = 0;
+
+    if ((netdir = opendir(SYSFS_CLASS_NET))) {
+        while ((de = readdir(netdir))) {
+            int cnt;
+            char *pos;
+            if (de->d_name[0] == '.')
+                continue;
+            snprintf(path, SYSFS_PATH_MAX, "%s/%s/wireless", SYSFS_CLASS_NET, de->d_name);
+            if (access(path, F_OK)) {
+                snprintf(path, SYSFS_PATH_MAX, "%s/%s/phy80211", SYSFS_CLASS_NET, de->d_name);
+                if (access(path, F_OK))
+                    continue;
+            }
+            /* found the wifi interface */
+            property_set("wlan.interface", de->d_name);
+            snprintf(path, SYSFS_PATH_MAX, "%s/%s/%s", SYSFS_CLASS_NET, de->d_name, SYS_MOD_NAME_DIR);
+            if ((cnt = readlink(path, link, SYSFS_PATH_MAX - 1)) < 0) {
+                ALOGW("can not find link of %s", path);
+                continue;
+            }
+            link[cnt] = '\0';
+            if ((pos = strrchr(link, '/'))) {
+                property_set(DRIVER_NAME_PROP, ++pos);
+                strncpy(buf, pos, PROPERTY_VALUE_MAX - 1);
+                buf[PROPERTY_VALUE_MAX - 1] = '\0';
+                ret = 1;
+                break;
+            }
+        }
+        closedir(netdir);
+    }
+
+    return ret;
+}
+#endif
+
 int is_wifi_driver_loaded() {
 #ifdef WIFI_DRIVER_MODULE_PATH
     char modname[PROPERTY_VALUE_MAX];
     char line[PROPERTY_VALUE_MAX];
     FILE *proc;
-    int cnt = property_get(DRIVER_NAME_PROP, modname, WIFI_DRIVER_MODULE_NAME);
+    int cnt = property_get(DRIVER_NAME_PROP, modname, NULL);
 
-    if (cnt > 0)
-        modname[cnt++] = ' ';
-    else
-        goto unloaded;
+    if (!cnt) {
+        if (get_driver_info(modname))
+            cnt = strlen(modname);
+        else
+            goto unloaded;
+    }
+    modname[cnt++] = ' ';
 
     /*
      * If the property says the driver is loaded, check to
@@ -256,16 +333,23 @@ int wifi_load_driver()
 {
 #ifdef WIFI_DRIVER_MODULE_PATH
     char driver_status[PROPERTY_VALUE_MAX];
+    char modname[PROPERTY_VALUE_MAX];
+    char modpath[SYSFS_PATH_MAX];
     int count = 100; /* wait at most 20 seconds for completion */
 
     if (is_wifi_driver_loaded()) {
         return 0;
     }
 
-    if (!property_get(DRIVER_PATH_PROP, driver_status, WIFI_DRIVER_MODULE_PATH))
-        return -1;
+    if (!property_get(DRIVER_PATH_PROP, modpath, NULL)) {
+        property_get(DRIVER_NAME_PROP, modname, NULL);
+        strcat(modname, ".ko");
+        if (!get_driver_path(modname, MODULE_DEFAULT_DIR, modpath))
+            strcpy(modpath, WIFI_DRIVER_MODULE_PATH);
+    }
 
-    if (insmod(driver_status, DRIVER_MODULE_ARG) < 0)
+    ALOGI("got module path %s", modpath);
+    if (insmod(modpath, DRIVER_MODULE_ARG) < 0)
         return -1;
 
     if (strcmp(FIRMWARE_LOADER,"") == 0) {
@@ -278,9 +362,10 @@ int wifi_load_driver()
     sched_yield();
     while (count-- > 0) {
         if (property_get(DRIVER_PROP_NAME, driver_status, NULL)) {
-            if (strcmp(driver_status, "ok") == 0)
+            if (strcmp(driver_status, "ok") == 0) {
+                get_driver_info(modname);
                 return 0;
-            else if (strcmp(driver_status, "failed") == 0) {
+            else if (strcmp(driver_status, "failed") == 0) {
                 wifi_unload_driver();
                 return -1;
             }
@@ -309,7 +394,7 @@ int wifi_unload_driver()
     usleep(200000); /* allow to finish interface down */
 #ifdef WIFI_DRIVER_MODULE_PATH
     char modname[PROPERTY_VALUE_MAX];
-    if (!property_get(DRIVER_NAME_PROP, modname, WIFI_DRIVER_MODULE_NAME))
+    if (!property_get(DRIVER_NAME_PROP, modname, NULL))
         return -1;
 
     if (rmmod(modname) == 0) {
@@ -501,7 +586,7 @@ int wifi_start_supplicant(int p2p_supported)
     if (pi != NULL) {
         serial = __system_property_serial(pi);
     }
-    property_get("wifi.interface", primary_iface, WIFI_TEST_INTERFACE);
+    property_get("wlan.interface", primary_iface, WIFI_TEST_INTERFACE);
 
     property_set("ctl.start", supplicant_name);
     sched_yield();