Announcing AsciiDocLIVE

I am very pround to announce the alpha launch of AsciiDocLIVE (https://asciidoclive.com/), a free online AsciiDoc editor with instant live preview, syntax highlighting, and more!

The Idea

The idea for AsciiDocLIVE struck me one day while writing a blog post. Being a fan of AsciiDoc, I use AsciiDoc for this blog, but the repetitive cycle of edit-compile-preview is pretty tedious. I realized that there wasn’t a good AsciiDoc editor that supported live previews (like Dillinger or Markable for Markdown). So, I hacked up a quick prototype in my spare time, and AsciiDocLIVE was born!

Features

Features included in this alpha launch:

  • Instant live preview: type in the left pane, see rendered result in the right pane.

  • Smart error messages: errors generated by the AsciiDoc compiler are displayed and linked to the offending line in the source text.

  • Syntax highlighting

To be available soon:

  • Saving documents

  • Importing from and exporting to Dropbox / Google Drive

Announcing JFBView

Around April this year I had heavily patched a PDF viewer for the Linux framebuffer called FBPDF, which was written by Ali Gholami Rudi in C. Over the past week I took up the project of completely rewriting a PDF / image viewer from scratch in C++ with advanced stuff like multi-threaded rendering and background caching and so on, and I am proud to announce the result - JFBView.

JFBView is a PDF and image viewer for the Linux framebuffer. Head over to the JFBView home page for links to source and documentation.

If your are an ArchLinux user, you can install JFBView from the AUR.

NITDroid userland update VII

I’ve been able to get wireless working - well, sort of. The problem in my last post about the DHCP client failing to start was solved by adding wifi.interface=wlan0 in default.prop (doesn’t really matter where though; could have used system.prop for instance) as suggested by this thread. After fixing some more permission problems, I was able to connect to the open WiFi networks at my school:

Wireless in Gingerbread (Android 2.3.7) on the Nokia N810

Wireless settings in Gingerbread on the Nokia N810 Browser showing welcome page from wireless network on the Nokia N810

However, at our school, internet is provided only through an EAP-encrypted network (Purple Air in the above image). The school provides in addition two open WiFi networks. One, Purple Help in the above image, redirects all traffic to a help page which provides instructions on how to connect to the main EAP-encrypted network. The other, Guest in the above image, is for visiting guests to the college and will only give internet access if you knew a guest user name and password privately assigned to each visitor. The N810 is now able to connect to both of the two open networks, but is unable to connect to the EAP network. I am not surprised by this because our EAP network is set up so badly that I have not been able to make my Thinkpad laptop connect to it under Linux either, nor is the N810 able to connect to the network even using the proprietary driver under stock Maemo. Therefore, I have not been able to get internet on the device, but that is hardly the fault of Android, the driver, or the device.

I next tried tethering my phone as an AP, but while my laptop and tablet can connect to the phone fine, the N810 is not showing it in the list of scan results in Android. Using the proprietary driver for the wireless chip in stock Maemo, the N810 is able to connect to my phone. This means that there are still problems with the open source driver for the wireless chip in the N810, but I do know now that at least open WiFi networks on standard routers do work fine. Since I do not have a wireless router of my own, I have not been able to test further.

NITDroid userland update VI

I have been working on getting wireless to work on the N810 under Gingerbread. So far I have not been successful, but I have made a lot of progress along the way.

I started out basically follwing this great article on porting WiFi drivers to Android. For some reason, if I compiled the driver for the wireless chip on the N810 (p54spi) directly into the kernel, the kernel refuses to boot. Therefore, I compiled it as a module, grabbed the firmware required from the official site of the p54 driver and add the corresponding changes to Android.mk and BoardConfig.mk as described in the aforementioned article.

But, as the same article explains, Android, rather than using the normal control functions in wpa_supplicant like a normal Linux system, expects wireless drivers to implement Android’s custom set of commands directly on top of SIOCSIWPRIV, and relies on those instead. I do not understand the rationale behind such a design decision; why reinvent the wheel when the wireless connectivity mechanism on modern Linux systems work just fine? But of course it is pointless arguing with Android, and I adapted the patch found in this article on porting WiFi drivers for the Nitrogen-E (which is a a Freescale i.MX51 / Cortex-A8 based board.

Unfortunately that was not enough either. As Android still thrashed around and refused to talk to the wireless chip, I discovered a line in my logcat output saying something like ioctl[SIOCSIWPRIV] (cscan): -1. Researching further lead me to this PDF (also archived here) which explained that Gingerbread added on top of Froyo yet another custom command over SIOCSIWPRIV, combo scan, that a driver needs to implement. In fact, Gingerbread will only use combo scanning to scan for APs when using WEXT. A patch for this is found here or, less elegantly, by removing combo scanning from the WEXT driver of wpa_supplicant as in this patch.

In addition, I had to patch libhardware_legacy to use wlan0 instead of sta (seriously, why is that hard-coded in?) which libhardware_legacy uses as the interface name to determine the state of the wpa_supplicant process. The patch is as follows:

diff --git a/wifi/wifi.c b/wifi/wifi.c
index 3f8708d..9d9d89c 100644
--- a/wifi/wifi.c
+++ b/wifi/wifi.c
@@ -60,7 +60,7 @@ static char iface[PROPERTY_VALUE_MAX];
 #ifndef WIFI_FIRMWARE_LOADER
 #define WIFI_FIRMWARE_LOADER           ""
 #endif
-#define WIFI_TEST_INTERFACE            "sta"
+#define WIFI_TEST_INTERFACE            "wlan0"

 #define WIFI_DRIVER_LOADER_DELAY       1000000

Otherwise, I get errors like

Unable to open connection to supplicant on "sta": No such file or directory

After all this effort, the device is able to scan correctly and does give a list of APs in Android GUI. From the logcat output I can see that it is also able to successfully associate with the AP:

I/wpa_supplicant( 1205): Trying to associate with 1c:17:d3:fc:db:79 (SSID='Purple Help' freq=2412 MHz)
D/wpa_supplicant( 1205): Cancelling scan request
D/wpa_supplicant( 1205): WPA: clearing own WPA/RSN IE
D/wpa_supplicant( 1205): Automatic auth_alg selection: 0x1
D/wpa_supplicant( 1205): WPA: clearing AP WPA IE
D/wpa_supplicant( 1205): WPA: clearing AP RSN IE
D/wpa_supplicant( 1205): WPA: clearing own WPA/RSN IE
D/wpa_supplicant( 1205): No keys have been configured - skip key clearing
D/wpa_supplicant( 1205): wpa_driver_wext_set_drop_unencrypted
D/wpa_supplicant( 1205): State: SCANNING -> ASSOCIATING
I/wpa_supplicant( 1205): CTRL-EVENT-STATE-CHANGE id=-1 state=3 BSSID=1c:17:d3:fc:db:79
D/wpa_supplicant( 1205): wpa_driver_wext_set_operstate: operstate 0->0 (DORMANT)
D/wpa_supplicant( 1205): WEXT: Operstate: linkmode=-1, operstate=5
D/wpa_supplicant( 1205): wpa_driver_wext_associate
D/wpa_supplicant( 1205): wpa_driver_wext_set_psk
D/wpa_supplicant( 1205): Setting authentication timeout: 10 sec 0 usec
D/wpa_supplicant( 1205): EAPOL: External notification - EAP success=0
D/wpa_supplicant( 1205): EAPOL: External notification - EAP fail=0
D/wpa_supplicant( 1205): EAPOL: External notification - portControl=ForceAuthorized
D/wpa_supplicant( 1205): RTM_NEWLINK: operstate=0 ifi_flags=0x1003 ([UP])
D/wpa_supplicant( 1205): RTM_NEWLINK, IFLA_IFNAME: Interface 'wlan0' added
D/wpa_supplicant( 1205): Wireless event: cmd=0x8b06 len=8
D/wpa_supplicant( 1205): RTM_NEWLINK: operstate=0 ifi_flags=0x1003 ([UP])
D/wpa_supplicant( 1205): RTM_NEWLINK, IFLA_IFNAME: Interface 'wlan0' added
D/wpa_supplicant( 1205): Wireless event: cmd=0x8b04 len=12
D/wpa_supplicant( 1205): RTM_NEWLINK: operstate=0 ifi_flags=0x1003 ([UP])
D/wpa_supplicant( 1205): RTM_NEWLINK, IFLA_IFNAME: Interface 'wlan0' added
D/wpa_supplicant( 1205): Wireless event: cmd=0x8b1a len=19
D/wpa_supplicant( 1205): CMD: AP_SCAN 1
D/wpa_supplicant( 1205): ap_scan = 1
V/WifiMonitor(  925): Event [Trying to associate with 1c:17:d3:fc:db:79 (SSID='Purple Help' freq=2412 MHz)]
V/WifiMonitor(  925): Event [CTRL-EVENT-STATE-CHANGE id=-1 state=3 BSSID=1c:17:d3:fc:db:79]
D/wpa_supplicant( 1205): CMD: DRIVER SCAN-PASSIVE
D/wpa_supplicant( 1205): wpa_driver_priv_driver_cmd SCAN-PASSIVE len = 4096
D/wpa_supplicant( 1205): SCAN-PASSIVE not yet supported
V/WifiStateTracker(  925): Changing supplicant state: SCANNING ==> ASSOCIATING
D/wpa_supplicant( 1205): CMD: STATUS
D/wpa_supplicant( 1205): CMD: DRIVER RSSI-APPROX
D/wpa_supplicant( 1205): wpa_driver_priv_driver_cmd RSSI-APPROX len = 4096
D/wpa_supplicant( 1205): >>>. DRIVER EMULATE RSSI
E/wpa_supplicant( 1205): wpa_driver_priv_driver_cmd failed (-1): RSSI
D/wpa_supplicant( 1205): CMD: DRIVER LINKSPEED
D/wpa_supplicant( 1205): wpa_driver_priv_driver_cmd LINKSPEED len = 4096
D/wpa_supplicant( 1205): Link Speed command
E/wpa_supplicant( 1205): wpa_driver_priv_driver_cmd failed (-1): LINKSPEED
D/wpa_supplicant( 1205): EAPOL: disable timer tick
D/wpa_supplicant( 1205): RTM_NEWLINK: operstate=0 ifi_flags=0x11003 ([UP][LOWER_UP])
D/wpa_supplicant( 1205): RTM_NEWLINK, IFLA_IFNAME: Interface 'wlan0' added
D/wpa_supplicant( 1205): RTM_NEWLINK: operstate=0 ifi_flags=0x11003 ([UP][LOWER_UP])
D/wpa_supplicant( 1205): RTM_NEWLINK, IFLA_IFNAME: Interface 'wlan0' added
D/wpa_supplicant( 1205): Wireless event: cmd=0x8c08 len=50
D/wpa_supplicant( 1205): RTM_NEWLINK: operstate=0 ifi_flags=0x11003 ([UP][LOWER_UP])
D/wpa_supplicant( 1205): RTM_NEWLINK, IFLA_IFNAME: Interface 'wlan0' added
D/wpa_supplicant( 1205): Wireless event: cmd=0x8b15 len=20
D/wpa_supplicant( 1205): Wireless event: new AP: 1c:17:d3:fc:db:79
D/wpa_supplicant( 1205): Association info event
D/wpa_supplicant( 1205): WPA: clearing AP WPA IE
D/wpa_supplicant( 1205): WPA: clearing AP RSN IE
D/wpa_supplicant( 1205): State: ASSOCIATING -> ASSOCIATED
I/wpa_supplicant( 1205): CTRL-EVENT-STATE-CHANGE id=0 state=4 BSSID=1c:17:d3:fc:db:79
D/wpa_supplicant( 1205): wpa_driver_wext_set_operstate: operstate 0->0 (DORMANT)
D/wpa_supplicant( 1205): WEXT: Operstate: linkmode=-1, operstate=5
V/WifiMonitor(  925): Event [CTRL-EVENT-STATE-CHANGE id=0 state=4 BSSID=1c:17:d3:fc:db:79]
V/WifiStateTracker(  925): Changing supplicant state: ASSOCIATING ==> ASSOCIATED
D/wpa_supplicant( 1205): Associated to a new BSS: BSSID=1c:17:d3:fc:db:79
I/wpa_supplicant( 1205): Associated with 1c:17:d3:fc:db:79
D/wpa_supplicant( 1205): WPA: Association event - clear replay counter
D/wpa_supplicant( 1205): WPA: Clear old PTK
D/wpa_supplicant( 1205): EAPOL: External notification - portEnabled=0
D/wpa_supplicant( 1205): EAPOL: External notification - portValid=0
D/wpa_supplicant( 1205): EAPOL: External notification - portEnabled=1
D/wpa_supplicant( 1205): EAPOL: SUPP_PAE entering state S_FORCE_AUTH
D/wpa_supplicant( 1205): EAPOL: SUPP_BE entering state IDLE
D/wpa_supplicant( 1205): Cancelling authentication timeout
D/wpa_supplicant( 1205): State: ASSOCIATED -> COMPLETED
I/wpa_supplicant( 1205): CTRL-EVENT-STATE-CHANGE id=0 state=7 BSSID=00:00:00:00:00:00
I/wpa_supplicant( 1205): CTRL-EVENT-CONNECTED - Connection to 1c:17:d3:fc:db:79 completed (auth) [id=0 id_str=]
D/wpa_supplicant( 1205): wpa_driver_wext_set_operstate: operstate 0->1 (UP)
D/wpa_supplicant( 1205): WEXT: Operstate: linkmode=-1, operstate=6
D/wpa_supplicant( 1205): Cancelling scan request
D/wpa_supplicant( 1205): RTM_NEWLINK: operstate=1 ifi_flags=0x11043 ([UP][RUNNING][LOWER_UP])
D/wpa_supplicant( 1205): RTM_NEWLINK, IFLA_IFNAME: Interface 'wlan0' added
V/WifiMonitor(  925): Event [Associated with 1c:17:d3:fc:db:79]
V/WifiMonitor(  925): Event [CTRL-EVENT-STATE-CHANGE id=0 state=7 BSSID=00:00:00:00:00:00]
V/WifiMonitor(  925): Event [CTRL-EVENT-CONNECTED - Connection to 1c:17:d3:fc:db:79 completed (auth) [id=0 id_str=]]
V/WifiStateTracker(  925): Changing supplicant state: ASSOCIATED ==> COMPLETED
V/WifiStateTracker(  925): New network state is CONNECTED
D/wpa_supplicant( 1205): CMD: STATUS
D/wpa_supplicant( 1205): CMD: STATUS
D/wpa_supplicant( 1205): CMD: DRIVER RSSI-APPROX
D/wpa_supplicant( 1205): wpa_driver_priv_driver_cmd RSSI-APPROX len = 4096
D/wpa_supplicant( 1205): >>>. DRIVER EMULATE RSSI
D/wpa_supplicant( 1205): CMD: DRIVER LINKSPEED
D/wpa_supplicant( 1205): wpa_driver_priv_driver_cmd LINKSPEED len = 4096
D/wpa_supplicant( 1205): Link Speed command
D/wpa_supplicant( 1205): CMD: DRIVER BTCOEXMODE 1
D/wpa_supplicant( 1205): wpa_driver_priv_driver_cmd BTCOEXMODE 1 len = 4096
D/wpa_supplicant( 1205): BTCOEXMODE not yet supported
D/wpa_supplicant( 1205): CMD: DRIVER GETPOWER
D/wpa_supplicant( 1205): wpa_driver_priv_driver_cmd GETPOWER len = 4096
D/wpa_supplicant( 1205): GETPOWER not yet supported
D/wpa_supplicant( 1205): CMD: DRIVER POWERMODE 1
D/wpa_supplicant( 1205): wpa_driver_priv_driver_cmd POWERMODE 1 len = 4096
D/wpa_supplicant( 1205): POWERMODE not yet supported
D/WifiStateTracker(  925): DHCP request started

However, DHCP appears not to function and Android unloads the driver and reloads it only to restart the scan → associate → DHCP query cycle. The error message is

E/WifiStateTracker(  925): DHCP request failed: Timed out waiting for dhcpcd to start
D/wpa_supplicant( 1205): CMD: DRIVER POWERMODE 0
D/wpa_supplicant( 1205): wpa_driver_priv_driver_cmd POWERMODE 0 len = 4096
D/wpa_supplicant( 1205): POWERMODE not yet supported
D/wpa_supplicant( 1205): CMD: DRIVER BTCOEXMODE 2
D/wpa_supplicant( 1205): wpa_driver_priv_driver_cmd BTCOEXMODE 2 len = 4096
D/wpa_supplicant( 1205): BTCOEXMODE not yet supported
D/wpa_supplicant( 1205): CMD: DISCONNECT
D/wpa_supplicant( 1205): wpa_driver_wext_disassociate
D/wpa_supplicant( 1205): No keys have been configured - skip key clearing
D/wpa_supplicant( 1205): State: COMPLETED -> DISCONNECTED
I/wpa_supplicant( 1205): CTRL-EVENT-STATE-CHANGE id=0 state=8 BSSID=00:00:00:00:00:00
D/wpa_supplicant( 1205): wpa_driver_wext_set_operstate: operstate 1->0 (DORMANT)
D/wpa_supplicant( 1205): WEXT: Operstate: linkmode=-1, operstate=5
D/wpa_supplicant( 1205): EAPOL: External notification - portEnabled=0
D/wpa_supplicant( 1205): EAPOL: SUPP_PAE entering state DISCONNECTED

Given that it is 7AM, that I have class and homework due, and that I have been working on this for the past 10 hours I will have to figure this out next time…

My full patch for wpa_supplicant 0.6.x, as found in the external/wpa_supplicant_6 directory in the Android source tree, is as follows:

diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index d3ab3dd..eb23985 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -32,6 +32,11 @@ ifeq ($(TARGET_ARCH),arm)
 L_CFLAGS += -mabi=aapcs-linux
 endif

+# Disable combo scan
+ifeq ($(BOARD_WEXT_NO_COMBO_SCAN),true)
+L_CFLAGS += -DWEXT_NO_COMBO_SCAN
+endif
+
 # To ignore possible wrong network configurations
 L_CFLAGS += -DWPA_IGNORE_CONFIG_ERRORS

diff --git a/wpa_supplicant/src/drivers/driver_wext.c b/wpa_supplicant/src/drivers/driver_wext.c
index bc5efff..36f28b5 100644
--- a/wpa_supplicant/src/drivers/driver_wext.c
+++ b/wpa_supplicant/src/drivers/driver_wext.c
@@ -253,7 +253,8 @@ int wpa_driver_wext_set_ssid(void *priv, const u8 *ssid, size_t ssid_len)
                if (ssid_len)
                        ssid_len++;
        }
-       iwr.u.essid.length = ssid_len;
+       drv->ssid_len = iwr.u.essid.length = ssid_len;
+        os_strlcpy(drv->ssid, buf, sizeof(drv->ssid));

        if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) {
                wpa_printf(MSG_ERROR, "ioctl[SIOCSIWESSID]");
@@ -969,6 +970,8 @@ void * wpa_driver_wext_init(void *ctx, const char *ifname)
        drv->errors = 0;
        drv->driver_is_started = TRUE;
        drv->skip_disconnect = 0;
+        drv->ssid_len = 0;
+        os_memset(drv->ssid, 0, sizeof(drv->ssid));
 #endif
        wpa_driver_wext_finish_drv_init(drv);

@@ -2559,12 +2562,207 @@ static int wpa_driver_priv_driver_cmd( void *priv, char *cmd, char *buf, size_t
        ret = ioctl(drv->ioctl_sock, SIOCSIWPRIV, &iwr);

        if (ret < 0) {
+#ifdef ANDROID
+            if (os_strcasecmp(cmd, "RSSI") == 0) {
+                struct iwreq wrq;
+                struct iw_statistics stats;
+                signed int rssi;
+                wpa_printf(MSG_DEBUG, ">>>. DRIVER EMULATE RSSI ");
+                wrq.u.data.pointer = (caddr_t) &stats;
+                wrq.u.data.length = sizeof(stats);
+                /* Clear updated flag */
+                wrq.u.data.flags = 1;
+                strncpy(wrq.ifr_name, drv->ifname, IFNAMSIZ);
+
+                if (ioctl(drv->ioctl_sock, SIOCGIWSTATS, &wrq) < 0) {
+                    perror("ioctl[SIOCGIWSTATS]");
+                    ret = -1;
+                } else {
+                    if (stats.qual.updated & IW_QUAL_DBM) {
+                        /* Values in dBm, stored in u8 with range 63 : -192 */
+                        rssi = ( stats.qual.level > 63 ) ?
+                            stats.qual.level - 0x100 :
+                            stats.qual.level;
+                    } else
+                        rssi = stats.qual.level;
+
+                    if (drv->ssid_len != 0 &&
+                        drv->ssid_len < buf_len) {
+                        os_memcpy((void *) buf, (void *)
+                              (drv->ssid), drv->ssid_len);
+                        ret = drv->ssid_len;
+                        ret += snprintf(&buf[ret], buf_len-ret,
+                                " rssi %dn", rssi);
+                        if (ret < (int)buf_len)
+                            return ret;
+                        ret = -1;
+                    }
+                }
+            } else if (os_strncasecmp(cmd, "START", 5) == 0) {
+                os_sleep(0, WPA_DRIVER_WEXT_WAIT_US);
+                wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STARTED");
+            } else if (os_strncasecmp(cmd, "STOP", 4) == 0) {
+                wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STOPPED");
+            } else if (os_strncasecmp(cmd, "LINKSPEED", 9) == 0) {
+                struct iwreq wrq;
+                unsigned int linkspeed;
+                os_strncpy(wrq.ifr_name, drv->ifname, IFNAMSIZ);
+                wpa_printf(MSG_DEBUG,"Link Speed command");
+                if (ioctl(drv->ioctl_sock, SIOCGIWRATE, &wrq) < 0) {
+                    perror("ioctl[SIOCGIWRATE]");
+                    ret = -1;
+                } else {
+                    linkspeed = wrq.u.bitrate.value / 1000000;
+                    ret = snprintf(buf, buf_len, "LinkSpeed %dn",
+                            linkspeed);
+                }
+            } else if (os_strncasecmp(cmd, "SNR", 3) == 0) {
+                struct iwreq wrq;
+                struct iw_statistics stats;
+                int snr, rssi, noise;
+
+                wrq.u.data.pointer = (caddr_t) &stats;
+                wrq.u.data.length = sizeof(stats);
+                wrq.u.data.flags = 1; /* Clear updated flag */
+                strncpy(wrq.ifr_name, drv->ifname, IFNAMSIZ);
+
+                if (ioctl(drv->ioctl_sock, SIOCGIWSTATS, &wrq) < 0) {
+                    perror("ioctl[SIOCGIWSTATS]");
+                    ret = -1;
+                } else {
+                    if (stats.qual.updated & IW_QUAL_DBM) {
+                        /* Values in dBm, stored in u8 with
+                         * range 63 : -192 */
+                        rssi = ( stats.qual.level > 63 ) ?
+                            stats.qual.level - 0x100 :
+                            stats.qual.level;
+                        noise = ( stats.qual.noise > 63 ) ?
+                            stats.qual.noise - 0x100 :
+                            stats.qual.noise;
+                    } else {
+                        rssi = stats.qual.level;
+                        noise = stats.qual.noise;
+                    }
+
+                    snr = rssi - noise;
+
+                    ret = snprintf(buf, buf_len, "snr = %un",
+                            (unsigned int)snr);
+                    if (ret < (int)buf_len)
+                        return ret;
+                }
+            } else if (os_strncasecmp(cmd, "SET-RTS-THRESHOLD", 17) == 0) {
+                struct iwreq wrq;
+                unsigned int rtsThreshold;
+                char *cp = cmd + 17;
+                char *endp;
+
+                strncpy(wrq.ifr_name, drv->ifname, IFNAMSIZ);
+
+                if (*cp != '\0') {
+                    rtsThreshold = (unsigned int)strtol(cp, &endp, 0);
+                    if (endp != cp) {
+                        wrq.u.rts.value = rtsThreshold;
+                        wrq.u.rts.fixed = 1;
+                        wrq.u.rts.disabled = 0;
+
+                        if (ioctl(drv->ioctl_sock, SIOCSIWRTS,
+                              &wrq) < 0) {
+                            perror("ioctl[SIOCGIWRTS]");
+                            ret = -1;
+                        } else {
+                            rtsThreshold = wrq.u.rts.value;
+                            wpa_printf(MSG_DEBUG,"Set RTS Threshold command = %d", rtsThreshold);
+                            ret = 0;
+                        }
+                    }
+                }
+            } else if (os_strncasecmp(cmd, "GET-RTS-THRESHOLD", 17) == 0) {
+                struct iwreq wrq;
+                unsigned int rtsThreshold;
+
+                strncpy(wrq.ifr_name, drv->ifname, IFNAMSIZ);
+
+                if (ioctl(drv->ioctl_sock, SIOCGIWRTS, &wrq) < 0) {
+                    perror("ioctl[SIOCGIWRTS]");
+                    ret = -1;
+                } else {
+                    rtsThreshold = wrq.u.rts.value;
+                    wpa_printf(MSG_DEBUG,"Get RTS Threshold command = %d",
+                           rtsThreshold);
+                    ret = snprintf(buf, buf_len, "rts-threshold = %un",
+                            rtsThreshold);
+                    if (ret < (int)buf_len)
+                        return ret;
+                }
+            } else if (os_strncasecmp(cmd, "SCAN-ACTIVE", 11) == 0) {
+                wpa_printf(MSG_DEBUG,"SCAN-ACTIVE not yet supportedn");
+                ret = 0 ;
+            } else if (os_strncasecmp(cmd, "SCAN-PASSIVE", 12) == 0) {
+                wpa_printf(MSG_DEBUG,"SCAN-PASSIVE not yet supportedn");
+                ret = 0 ;
+            } else if (os_strncasecmp(cmd, "SCAN-CHANNELS", 13) == 0) {
+                wpa_printf(MSG_DEBUG,"SCAN-CHANNELS not yet supportedn");
+                ret = 0 ;
+            } else if (os_strncasecmp(cmd, "BTCOEXSCAN-START", 16) == 0) {
+                wpa_printf(MSG_DEBUG,"BTCOEXSCAN-START not yet supportedn");
+                ret = 0 ;
+            } else if (os_strncasecmp(cmd, "BTCOEXSCAN-STOP", 15) == 0) {
+                wpa_printf(MSG_DEBUG,"BTCOEXSCAN-STOP not yet supportedn");
+                ret = 0 ;
+            } else if (os_strncasecmp(cmd, "RXFILTER-START", 14) == 0) {
+                wpa_printf(MSG_DEBUG,"RXFILTER-START not yet supportedn");
+                ret = 0 ;
+            } else if (os_strncasecmp(cmd, "RXFILTER-STOP", 13) == 0) {
+                wpa_printf(MSG_DEBUG,"RXFILTER-STOP not yet supportedn");
+                ret = 0 ;
+            } else if (os_strncasecmp(cmd, "RXFILTER-STATISTICS", 19) == 0) {
+                wpa_printf(MSG_DEBUG,"RXFILTER-STATISTICS not yet supportedn");
+                ret = 0 ;
+            } else if (os_strncasecmp(cmd, "RXFILTER-ADD", 12) == 0) {
+                wpa_printf(MSG_DEBUG,"RXFILTER-ADD not yet supportedn");
+                ret = 0 ;
+            } else if (os_strncasecmp(cmd, "RXFILTER-REMOVE", 15) == 0) {
+                wpa_printf(MSG_DEBUG,"RXFILTER-REMOVE not yet supportedn");
+                ret = 0 ;
+            } else if (os_strncasecmp(cmd, "BTCOEXMODE", 10) == 0) {
+                wpa_printf(MSG_DEBUG,"BTCOEXMODE not yet supportedn");
+                ret = 0 ;
+            } else if (os_strncasecmp(cmd, "BTCOEXSTAT", 10) == 0) {
+                wpa_printf(MSG_DEBUG,"BTCOEXSTAT not yet supportedn");
+                ret = 0 ;
+            } else if (os_strncasecmp(cmd, "POWERMODE", 9) == 0) {
+                wpa_printf(MSG_DEBUG,"POWERMODE not yet supportedn");
+                ret = 0 ;
+            } else if (os_strncasecmp(cmd, "GETPOWER", 8 ) == 0) {
+                wpa_printf(MSG_DEBUG,"GETPOWER not yet supportedn");
+                ret = 0 ;
+            } else if (os_strncasecmp(cmd, "MACADDR", 7) == 0) {
+                /* MACADDR */
+                struct ifreq ifr;
+                os_memset(&ifr, 0, sizeof(ifr));
+                os_strncpy(ifr.ifr_name, drv->ifname, IFNAMSIZ);
+
+                if (ioctl(drv->ioctl_sock, SIOCGIFHWADDR, &ifr) < 0) {
+                    perror("ioctl[SIOCGIFHWADDR]");
+                    ret = -1;
+                } else {
+                    u8 *macaddr = (u8 *) ifr.ifr_hwaddr.sa_data;
+                    ret = snprintf(buf, buf_len, "Macaddr = " MACSTR "n",
+                            MAC2STR(macaddr));
+                }
+            }
+            if (ret < 0) {
+#endif
                wpa_printf(MSG_ERROR, "%s failed (%d): %s", __func__, ret, cmd);
                drv->errors++;
                if (drv->errors > WEXT_NUMBER_SEQUENTIAL_ERRORS) {
                        drv->errors = 0;
                        wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
                }
+#ifdef ANDROID
+            }
+#endif
        } else {
                drv->errors = 0;
                ret = 0;
diff --git a/wpa_supplicant/src/drivers/driver_wext.h b/wpa_supplicant/src/drivers/driver_wext.h
index 29ef44b..a7cde94 100644
--- a/wpa_supplicant/src/drivers/driver_wext.h
+++ b/wpa_supplicant/src/drivers/driver_wext.h
@@ -47,6 +47,9 @@ struct wpa_driver_wext_data {
        int errors;
        int driver_is_started;
        int skip_disconnect;
+        /* SIOCSIWPRIV support in WEXT for non-Android WiFi drivers. */
+        char ssid[33];
+        unsigned int ssid_len;
 #endif
 };

diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index beec16e..ed40642 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -1490,6 +1490,9 @@ int wpa_drv_scan(struct wpa_supplicant *wpa_s, struct wpa_ssid **ssid_ptr)
        size_t ssid_len = 0;
        int ret = -1;

+#ifdef WEXT_NO_COMBO_SCAN
+       if (wpa_s->driver->scan) {
+#else
        if (wpa_s->driver->combo_scan) {
                ret = wpa_s->driver->combo_scan(wpa_s->drv_priv, ssid_ptr,
                                                wpa_s->conf->ssid);
@@ -1499,6 +1502,7 @@ int wpa_drv_scan(struct wpa_supplicant *wpa_s, struct wpa_ssid **ssid_ptr)
                }
        }
        else if (wpa_s->driver->scan) {
+#endif
                if (*ssid_ptr) {
                        ssid_nm = (*ssid_ptr)->ssid;
                        ssid_len = (*ssid_ptr)->ssid_len;

Credit goes to Michael Trimarchi as the changes are totally adapted from his patch.

I have added a repository for userland patches which can be accessed here.

NITDroid userland update V

In short - I compiled Gingerbread (2.3.7_r1) without modification and it boots on the N810 out of the box. That was SO much easier than with Froyo…

Gingerbread (2.3.7 r1) on the Nokia N810:

Gingerbread (2.3.7 r1) on the Nokia N810

I uploaded my device configuration files for Android to this Git repository. To build, the files should be kept in a folder with any name, say nitdroid_device, under $ANDROID_SOURCE/device. To build, run make PRODUCT-nitdroid-eng or a variant from the root of the source tree.

I also calibrated the TSC2005 touchscreen. The code I pulled off this thread back in May resulted in weird coordinates on my touchscreen since when I was running Froyo, and I took the time to correct the numeric values by trial and error on my touchscreen. The final diff from the tsc2005.c created by the OpenWRT patches is:

--- a/drivers/input/touchscreen/tsc2005.c
+++ b/drivers/input/touchscreen/tsc2005.c
@@ -304,8 +304,8 @@ static void tsc2005_ts_update_pen_state(struct tsc2005 *ts,
                                        int x, int y, int pressure)
 {
        if (pressure) {
+                x = abs((x - 260) * 800 / 3550);
+                y = abs((3600 - y) * 480 / 3750);
                input_report_abs(ts->idev, ABS_X, x);
                input_report_abs(ts->idev, ABS_Y, y);
                input_report_abs(ts->idev, ABS_PRESSURE, pressure);

I have committed it to my kernel patches repository.

There are still a million issues though…sound and wireless don’t work yet, and most importantly the system panics after about a minute of inaction, complaining (untruthfully) that the SD card had been removed. But it’s a start.