[bc9]

- Contents
#Contents

* Overview [#v53b5875]
>
This article shows how to add an USB WiFi device to bc9. In this article, the example of the device is specific, and it is available~
only in Japan. However, the critical parts of this article are explaining how to integrate a driver of device and Linux kernel and~
how to modify of several files for the integration. The driver for the USB WiFi device is called '''rt73''', and it is commonly used in~
Linux community. If users cannot obtain the specific device, this methodology is mostly applicable for '''rt73''' compatible devices.

>
- The device used here is [[I-O data WN-G54/USB:http://www.iodata.jp/product/network/adp/wn-g54usb/]] (the information site is in Japanese). This device is fully compatible with '''android-1.5r3'''.
- The device used here is [[I-O data WN-G54/USB:http://www.iodata.jp/product/network/adp/wn-g54usb/]] (the information site is in Japanese). This device is fully compatible with '''android-1.5r3'''.~
~
- To control the device from the GUI of android, the file located at '''android-1.5r3/hardware/libhardware_legacy/wifi/wifi.c/''' is needed to be~
modified. (Once this file is build, it is linked to '''libnetutils'''.) As this directory is needed to be specifically altered for the use of a certain~
device, this directory is required a new modification for a newly added device.
device, this directory is required a new modification for a newly added device.~
~
- Because of the android's current structure, easily change the devices as long as they use the same driver. However, it is very difficult~
to use the different drivers of the same kind of devices, simultaneously.
to use the different drivers of the same kind of devices, simultaneously.~
~
- There is a wifi porting manual at '''android-1.5r3/development/pdk/docs/guide/wifi.jd''' For changing the formats of documents from~
'''javadoc''' to '''html''', please look at '''mydroid/development/pdk/README'''.

* Instructions [#gd1c51f4]
>
Following the directions of [[bc9/bc9-oe-sdk setup]] and [[bc9/bc9-android-sdk setup]],  rebuild kerne,l and build android userland.

** Create Kernel with Wireless LAN driver [#j1aacef3]
>
In this article,  the USB WiFi device used here is I-O data WN G54/USB, which has been tested with gumstix/bc9. The driver is~
'''linux-2.6.29/drivers/net/wireless/rt2x00/rt73usb.ko'''. This driver is dependent on '''rt2x00lib.ko''' and '''rt2x00usb.ko''', and needed~
the firmware of '''rt73.bin'''. The firmware can be downloaded from the link below.

>
&ref(RT71W_Firmware_V1.8.zip);
>
First, the driver is built as a module, and try the module on OpenEmbedded Linux. '''rt73.bin''' is placed at '''/lib/firmware/'''.~
The connection method, which utilizes '''wpa_supplicant''', is studied from the information at '''/etc/network/interfaces/'''.
 $ wpa_passphrase SSID PASS_PHRASE
Even though the output of the command above is written into '''/etc/wpa_supplicant.conf''', due to the lack of some critical~
information, such as the encryption figure, the connection is failed.
>
Taking [[this:http://ubuntuforums.org/showthread.php?t=263136&page=11]] advice, add the extra information to '''/etc /wpa_supplicant.conf'''. 
 network={
     ssid="hoge"
     key_mgmt=WPA-PSK
     proto=WPA WPA2
     pairwise=CCMP TKIP
     group=CCMP TKIP WEP104 WEP40
     # psk="beatcraft"
     psk=1954c17037ac0255e310e30377008d5e732edb603bb4b27ee92d14e4b0d91919
 } 
As writing the information correctly, check the connection by the command.
 $ wpa_supplicant -Dwext -iwlan0 -c/etc/wpa_supplicant.conf
For OpenEmbedded Linux, '''wlan0''' is up and obtain an IP address by '''dhcp'''.

** android build with wpa_ supplicant [#if1183fc]
>
Making '''wpa_supplicant''' effective, build android and test the wireless connection by command lines.

*** build wpa_supplicant [#y6dfc9c7]
>
Modify  '''.config''' file, which is located at '''android-1.5r3/external/wpa_supplicant/.config'''. The  modifications are shown below. 
 $ diff -u .config.orig .config
 --- .config.orig	2009-08-05 22:00:52.000000000 +0900
 +++ .config	2009-08-11 16:22:36.000000000 +0900
 @@ -19,13 +19,13 @@
  CONFIG_PKCS12=y
  # CONFIG_PCSC=y
  CONFIG_SMARTCARD=y
 -# CONFIG_WIRELESS_EXTENSION=y
 +CONFIG_WIRELESS_EXTENSION=y
  CONFIG_CTRL_IFACE=y
  # CONFIG_DRIVER_HOSTAP=y
  # CONFIG_DRIVER_HERMES=y
  # CONFIG_DRIVER_MADWIFI=y
  # CONFIG_DRIVER_ATMEL=y
 -# CONFIG_DRIVER_WEXT=y
 +CONFIG_DRIVER_WEXT=y
  # CONFIG_DRIVER_NDISWRAPPER=y
  # CONFIG_DRIVER_BROADCOM=y
  # CONFIG_DRIVER_IPW=y
The extra code defined below is added to '''BoardConfig.mk''', which is placed at '''android-1.5r3/build/target/board/generic/BoardConfig.mk'''
 WPA_BUILD_SUPPLICANT := true
 BOARD_WPA_SUPPLICANT_DRIVER := WEXT
Alter the file, '''wpa_supplicant.conf''', which is under the directory '''android-1.5r3/external/wpa_suplicant/wpa_supplicant.conf'''.~
Change the code  as it is described below.
 ~/android-1.5r3$ diff -u external/wpa_supplicant/wpa_supplicant.conf.orig external/wpa_supplicant/wpa_supplicant.conf
 --- external/wpa_supplicant/wpa_supplicant.conf.orig	2009-08-11 16:31:15.000000000 +0900
 +++ external/wpa_supplicant/wpa_supplicant.conf	2009-08-11 16:31:58.000000000 +0900
 @@ -72,7 +72,8 @@
  # DACL (which will reject all connections). See README-Windows.txt for more
  # information about SDDL string format.
  #
 -ctrl_interface=tiwlan0
 +#ctrl_interface=wlan0
 +ctrl_interface=DIR=/data/system/wpa_supplicant GROUP=system
  
  # IEEE 802.1X/EAPOL version
  # wpa_supplicant is implemented based on IEEE Std 802.1X-2004 which defines
>
As executing '''make''' again, '''wpa_supplicant''' and '''wpa_cli''' are built at '''out/target/product/generic/system/bin/'''. Testing~
wireless connection, execute shell command from android. Make sure that bc9 is connected to a wireless access~
point. On android, as executing '''insmod''', firmwares can be read. However '''wlan0''' does not start up automatically.~
Executing two commands shown below, obtain an address via '''dhcp''', which requires few commands.~
 # system/bin/wpa_supplicant -Dwext -iwlan0 -c/system/etc/wpa_supplicant.conf
 # netcfg wlan0 dhcp

*** Modification of wifi.c [#df1c856b]
>
The modification of  '''wifi.c''' enables WiFi control from the GUI of android possible. As Executimg '''insmod''' on '''rt73usb.ko'''~
and the drivers depending on '''rt73usb.ko''', '''rt73.bin''' is loaded into USB wifi, and '''wlan''' can use. (As android does not~
have '''modprobe''' drivers,  the drivers depending on '''rt73usb.ko''' cannot be loaded at once. To maintain the relationship~
with dependencies, '''insmod''' is executed on a single driver individually every once.) Configuring wifi's SSID and PSK~
via '''wpa_supplicant''', start up '''wlan0''',  and obtain the address by '''dhcp'''. The Code below show how '''wifi.c''' is modified.~
'''wifi.c''' is located at '''android-1.5r3/hardware/libhardware_legacy/wifi/wifi.c/'''.~

>
 --- wifi.c.orig 2009-08-11 10:56:03.000000000 +0900
 +++ wifi.c      2009-08-12 17:02:49.000000000 +0900
 @@ -48,10 +48,16 @@
  // TODO: use new ANDROID_SOCKET mechanism, once support for multiple
  // sockets is in
 
 -static const char IFACE_DIR[]           = "/data/system/wpa_supplicant";
 -static const char DRIVER_MODULE_NAME[]  = "wlan";
 -static const char DRIVER_MODULE_TAG[]   = "wlan ";
 -static const char DRIVER_MODULE_PATH[]  = "/system/lib/modules/wlan.ko";
 +static const char IFACE_DIR[]                          = "/data/system/wpa_supplicant";
 +static const char DRIVER_MODULE_NAME[]                 = "rt73usb";
 +static const char DRIVER_MODULE_TAG[]                  = "rt73usb ";
 +static const char DRIVER_MODULE_PATH[]                 = "/system/lib/modules/rt73usb.ko";
 +static const char RT2X00_LIB_DRIVER_MODULE_NAME[]      = "rt2x00lib";
 +static const char RT2X00_LIB_DRIVER_MODULE_TAG[]       = "rt2x00lib ";
 +static const char RT2X00_LIB_DRIVER_MODULE_PATH[]      = "/system/lib/modules/rt2x00lib.ko";
 +static const char RT2X00_LIB_USB_DRIVER_MODULE_NAME[]  = "rt2x00usb";
 +static const char RT2X00_LIB_USB_DRIVER_MODULE_TAG[]   = "rt2x00usb";
 +static const char RT2X00_LIB_USB_DRIVER_MODULE_PATH[]  = "/system/lib/modules/rt2x00usb.ko";
  static const char FIRMWARE_LOADER[]     = "wlan_loader";
  static const char DRIVER_PROP_NAME[]    = "wlan.driver.status";
  static const char SUPPLICANT_NAME[]     = "wpa_supplicant";
 @@ -66,6 +72,7 @@
      unsigned int size;
      int ret;
 
 +    LOGI("%s\n", __FUNCTION__);
      module = load_file(filename, &size);
      if (!module)
          return -1;
 @@ -82,6 +89,7 @@
      int ret = -1;
      int maxtry = 10; 
 
 +    LOGI("%s\n", __FUNCTION__);
      while (maxtry-- > 0) {
          ret = delete_module(modname, O_NONBLOCK | O_EXCL);
         if (ret < 0 && errno == EAGAIN)
 @@ -91,30 +99,35 @@
      }
 
      if (ret != 0)
 -        LOGD("Unable to unload driver module \"%s\": %s\n",
 +        LOGE("Unable to unload driver module \"%s\": %s\n",
               modname, strerror(errno));
      return ret;
  }
 
  int do_dhcp_request(int *ipaddr, int *gateway, int *mask,
                      int *dns1, int *dns2, int *server, int *lease) {
 +    LOGI("1. inside %s\n", __FUNCTION__);
      /* For test driver, always report success */
 -    if (strcmp(iface, "sta") == 0)
 +    if (strcmp(iface, "wlan0") == 0)
          return 0;
 
 +    LOGI("2. inside %s\n", __FUNCTION__);
      if (ifc_init() < 0)
          return -1;
 
 +    LOGI("3. inside %s\n", __FUNCTION__);
      if (do_dhcp(iface) < 0) {
          ifc_close();
          return -1;
      }
      ifc_close();
      get_dhcp_info(ipaddr, gateway, mask, dns1, dns2, server, lease);
 +    LOGI("4. inside %s\n", __FUNCTION__);
      return 0;
  }
 
  const char *get_dhcp_error_string() {
 +    LOGI("Inside %s\n", __FUNCTION__);
      return dhcp_lasterror();
  }
 
 @@ -123,8 +136,10 @@
      FILE *proc;
      char line[sizeof(DRIVER_MODULE_TAG)+10];
 
 +    LOGI("%s\n", __FUNCTION__);
      if (!property_get(DRIVER_PROP_NAME, driver_status, NULL)
              || strcmp(driver_status, "ok") != 0) {
 +         LOGE("driver %s has NOT been installed",DRIVER_MODULE_TAG);
          return 0;  /* driver not loaded */
      }
      /*
 @@ -140,10 +155,12 @@
      }
      while ((fgets(line, sizeof(line), proc)) != NULL) {
          if (strncmp(line, DRIVER_MODULE_TAG, strlen(DRIVER_MODULE_TAG)) == 0) {
 +            LOGI("driver %s has been installed\n",DRIVER_MODULE_TAG);
              fclose(proc);
              return 1; 
          }
      }
 +    LOGE("Cannot find driver %s in proc",DRIVER_MODULE_TAG);
      fclose(proc);
      property_set(DRIVER_PROP_NAME, "unloaded");
      return 0;
 @@ -154,23 +171,34 @@
      char driver_status[PROPERTY_VALUE_MAX];
      int count = 100; /* wait at most 20 seconds for completion */
 
 +    LOGI("Loading WiFi Modules\n");
 +    sleep(1);
 +
 +    // Hack taken from EEPC WiFi path. We have statically linked the WiFi driver
 +    // into the kernel, so we simply return and don't attempt to load the driver.
 +    // So we set the driver property to ok, since we have already installed it.
 +    property_set(DRIVER_PROP_NAME, "ok");
      if (check_driver_loaded()) {
          return 0;
      }
 -
 -    if (insmod(DRIVER_MODULE_PATH) < 0)
 -        return -1;
 -      
 -    property_set("ctl.start", FIRMWARE_LOADER);
 +    insmod(RT2X00_LIB_DRIVER_MODULE_PATH);
 +    insmod(RT2X00_LIB_USB_DRIVER_MODULE_PATH);
 +    insmod(DRIVER_MODULE_PATH);
 +    property_set("ctl.start", 0); 
      sched_yield();
      while (count-- > 0) {
 +               usleep(500000);
          if (property_get(DRIVER_PROP_NAME, driver_status, NULL)) {
 -            if (strcmp(driver_status, "ok") == 0)
 +            if (strcmp(driver_status, "ok") == 0) {
 +               property_set("ctl.start", "ifcfg_ralink");
 +                               usleep(1000000);
 +                               //property_set("ctl.start", "dhcpcd");
                  return 0;
 -            else if (strcmp(DRIVER_PROP_NAME, "failed") == 0)
 +            }
 +            else if (strcmp(DRIVER_PROP_NAME, "failed") == 0) {
                  return -1;
 +            }
          }
 -        usleep(200000);
      }
      property_set(DRIVER_PROP_NAME, "timeout");
      return -1;
 @@ -178,20 +206,31 @@
 
  int wifi_unload_driver()
  {
 -    int count = 20; /* wait at most 10 seconds for completion */
 -    
 +    LOGI("Unloading WiFi Modules\n");
 +    sleep(1);
 +
      if (rmmod(DRIVER_MODULE_NAME) == 0) {
 -       while (count-- > 0) {
 -           if (!check_driver_loaded())
 -               break;
 -           usleep(500000);
 -       }
 -       if (count) {
 -           return 0;
 -       }
 -       return -1;
 -    } else
 +        usleep(1000000);
 +    } else {
 +        LOGE("Unloading Ralink RT73USB WLAN Module Failed\n");
 +        return -1;
 +    }
 +
 +    if (rmmod(RT2X00_LIB_USB_DRIVER_MODULE_NAME) == 0) {
 +        usleep(1000000);
 +    } else {
 +        LOGE("Unloading RT2X00_LIB_USB Module Failed\n");
          return -1;
 +    }
 +
 +    if (rmmod(RT2X00_LIB_DRIVER_MODULE_NAME) == 0) {
 +        usleep(1000000);
 +    } else {
 +        LOGE("Unloading RT2X00_LIB Module Failed\n");
 +        return -1;
 +    }
 +
 +    return 0;
  }
 
  int ensure_config_file_exists()
 @@ -200,6 +239,7 @@
      int srcfd, destfd;
      int nread;
 
 +    LOGE("%s\n", __FUNCTION__);
      if (access(SUPP_CONFIG_FILE, R_OK|W_OK) == 0) {
          return 0;
      } else if (errno != ENOENT) {
 @@ -252,6 +292,7 @@
      unsigned serial = 0;
  #endif
 
 +    LOGI("start %s",__FUNCTION__);
      /* Check whether already running */
      if (property_get(SUPP_PROP_NAME, supp_status, NULL)
              && strcmp(supp_status, "running") == 0) {
 @@ -260,7 +301,7 @@
 
      /* Before starting the daemon, make sure its config file exists */
      if (ensure_config_file_exists() < 0) {
 -        LOGE("Wi-Fi will not be enabled");
 +        LOGE("Configuration file does not exis. Wi-Fi will not be enabled");
          return -1;
      } 
 
 @@ -291,9 +332,11 @@
          if (pi != NULL) {
              __system_property_read(pi, NULL, supp_status);
              if (strcmp(supp_status, "running") == 0) {
 +                LOGI("Wi-Fi is running\n");
                 return 0;
              } else if (pi->serial != serial &&
                      strcmp(supp_status, "stopped") == 0) {
 +                LOGI("Wi-Fi has been stopped");
                  return -1;
              }
          }
 @@ -313,6 +356,7 @@
      char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
      int count = 50; /* wait at most 5 seconds for completion */
 
 +    LOGI("%s called",__func__);
      /* Check whether supplicant already stopped */
      if (property_get(SUPP_PROP_NAME, supp_status, NULL)
          && strcmp(supp_status, "stopped") == 0) {
 @@ -337,6 +381,7 @@
      char ifname[256];
      char supp_status[PROPERTY_VALUE_MAX] = {'\0'}; 
 
 +    LOGI("%s called",__func__);
      /* Make sure supplicant is running */
      if (!property_get(SUPP_PROP_NAME, supp_status, NULL)
              || strcmp(supp_status, "running") != 0) {
 @@ -344,7 +389,7 @@
          return -1;
      } 
 
 -    property_get("wifi.interface", iface, "sta");
 +    property_get("wifi.interface", iface, "wlan0"); 
 
      if (access(IFACE_DIR, F_OK) == 0) {      
          snprintf(ifname, sizeof(ifname), "%s/%s", IFACE_DIR, iface);
 @@ -352,6 +397,8 @@
          strlcpy(ifname, iface, sizeof(ifname));
      }
 
 +    LOGI("Interface directory = %s", IFACE_DIR);
 +    LOGI("Interface name = %s", ifname);
      ctrl_conn = wpa_ctrl_open(ifname);
      if (ctrl_conn == NULL) {
          LOGE("Unable to open connection to supplicant on \"%s\": %s",
 @@ -370,6 +417,7 @@
          ctrl_conn = monitor_conn = NULL;
          return -1;
      } 
 +    LOGI("Connect to Supplicant done\n");
      return 0;
  }
 
 @@ -377,20 +425,26 @@
  {
      int ret;
 
 +    LOGI("%s, cmd = %s\n", __FUNCTION__, cmd);
      if (ctrl_conn == NULL) {
          LOGV("Not connected to wpa_supplicant - \"%s\" command dropped.\n", cmd);
          return -1;
      }
 +
 +    memset(reply, 0, *reply_len);
      ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), reply, reply_len, NULL);
      if (ret == -2) {
          LOGD("'%s' command timed out.\n", cmd);
          return -2;
      } else if (ret < 0 || strncmp(reply, "FAIL", 4) == 0) {
 +        LOGI("reply:%s\n",reply);
          return -1;
      }
      if (strncmp(cmd, "PING", 4) == 0) {
          reply[*reply_len] = '\0';
      }
 +
 +    LOGI("returning reply %s for cmd %s\n", reply, cmd);
      return 0;
  }
 
 @@ -402,10 +456,13 @@
      int result;
     struct timeval tval;
     struct timeval *tptr;
 -    
 +
 +    LOGI("%s called",__func__);
 +    LOGI("monitor_conn checking \n");
      if (monitor_conn == NULL)
          return 0;
 
 +    LOGI("calling wpa_ctrl_recv\n");
      result = wpa_ctrl_recv(monitor_conn, buf, &nread);
      if (result < 0) {
          LOGD("wpa_ctrl_recv failed: %s\n", strerror(errno));
 @@ -413,6 +470,7 @@
      }
      buf[nread] = '\0';
      /* LOGD("wait_for_event: result=%d nread=%d string=\"%s\"\n", result, nread, buf); */
 +    LOGI("wait_for_event: result=%d nread=%d string=\"%s\"\n", result, nread, buf);
      /* Check for EOF on the socket */
      if (result == 0 && nread == 0) {
          /* Fabricate an event to pass up */
 @@ -437,11 +495,13 @@
              memmove(buf, match+1, nread+1);
          }
      }
 +    LOGI("returning nread\n");
      return nread;
  }
 
  void wifi_close_supplicant_connection()
  {
 +    LOGI("%s called",__func__);
      if (ctrl_conn != NULL) {
          wpa_ctrl_close(ctrl_conn);
          ctrl_conn = NULL;
 @@ -454,5 +514,6 @@
 
  int wifi_command(const char *command, char *reply, size_t *reply_len)
  {
 +    LOGI("%s called, cmd:%s",__func__,command);
      return wifi_send_command(ctrl_conn, command, reply, reply_len);
  }

>
In addition to this modification of '''wifi.c''', change '''tiwlan0''' to '''wlan0''' in the source code of android-1.5r3. Specifically, the files listed~
below are needed to be altered from '''tiwlan0''' to '''wlan0'''. 
- android-1.5r3/external/dhcpcd/android.conf
- frameworks/base/services/java/com/android/server/WiFiWatchdogService.java
- android-1.5r3/frameworks/base/wifi/java/android/net/wifi/WifiStateTracker.java

>
After changing all parts of the source code, execute '''build''' command.

** adjustment android userland [#jedf42be]
>
To turn on/off WiFi form GUI of android, the kernel module of '''rt73usb''' and '''rt73bin'''  are needed to  be placed in the userland of~
android. The locations are shown below.
 /system/lib/modules/rt2x00lib.ko
 /system/lib/modules/rt2x00usb.ko
 /system/lib/modules/rt73usb.ko
 /system/etc/firmware/rt73.bin
Configuring the name of wifi interface, the code is added to the file, which is located at/system/build.prop
 # WiFi settings
 wifi.interface = wlan0
Add few code to '''init.rc'''. This allows '''wlan0''' to start up automatically and '''dhcp'''to obtain the address, as running '''insmod''' from GUI.
   setprop wifi.interface wlan0
   setprop wlan.driver.status ok
 
   service ifcfg_ralink /system/bin/ifconfig wlan0 up
   #   disabled
   #   oneshot
 
   service wpa_supplicant /system/bin/logwrapper /system/bin/wpa_supplicant -Dwext -iwlan0 -c /system/etc/wifi/wpa_supplicant.conf -dd
       disabled
       group system
 
   service dhcpcd /system/bin/logwrapper /system/bin/dhcpcd -d wlan0
       disabled
       oneshot
       #group system dhcp
 
   on property:init.svc.wpa_supplicant=stopped
       stop dhcpcd

>
As the method described above is completed, WiFi is configured from GUI of android userland. Once WiFi is configured,~
Wireless LAN can be turned on/off from '''WiFI''', which can be accessed form '''Wireless configuration''', '''WiFi''', Wi-Fi, to WiFi.~
As turning On from Of, bc9 attempts to connect the priority access point. If bc9 failed to establish the connection, it~
scans access points  and displays the list of available access points at '''Wi-Fi network'''.

* Reference [#p9caeda4]
>
http://groups.google.co.jp/group/android-porting/browse_thread/thread/126310f20d406bd7/~
http://whitesc3.blog7.fc2.com/blog-entry-108.html (in Japanese)~
http://whitesc3.blog7.fc2.com/blog-entry-111.html (in Japanese)~

Front page   Edit Diff Backup Upload Copy Rename Reload   New List of pages Search Recent changes   RSS of recent changes