nexus: Add TiwlanEventListener for reading driver events directly

Signed-off-by: San Mehat <san@google.com>
diff --git a/nexus/TiwlanEventListener.cpp b/nexus/TiwlanEventListener.cpp
new file mode 100644
index 0000000..76e6ec1
--- /dev/null
+++ b/nexus/TiwlanEventListener.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#define LOG_TAG "TiwlanEventListener"
+#include <cutils/log.h>
+
+#include "TiwlanEventListener.h"
+
+TiwlanEventListener::TiwlanEventListener(int socket) :
+                     SocketListener(socket, false) {
+}
+
+bool TiwlanEventListener::onDataAvailable(SocketClient *cli) {
+    struct ipc_ev_data *data;
+
+    if (!(data = (struct ipc_ev_data *) malloc(sizeof(struct ipc_ev_data)))) {
+        LOGE("Failed to allocate packet (out of memory)");
+        return true;
+    }
+
+    if (recv(cli->getSocket(), data, sizeof(struct ipc_ev_data), 0) < 0) {
+       LOGE("recv failed (%s)", strerror(errno));
+       goto out;
+    }
+
+    if (data->event_type == IPC_EVENT_LINK_SPEED) {
+        uint32_t *spd = (uint32_t *) data->buffer;
+        *spd /= 2;
+        LOGD("Link speed = %u MB/s", *spd);
+    } else if (data->event_type == IPC_EVENT_LOW_SNR) {
+        LOGD("Low signal/noise ratio");
+    } else if (data->event_type == IPC_EVENT_LOW_RSSI) {
+        LOGD("Low RSSI");
+    } else {
+        LOGD("Dropping unhandled driver event %d", data->event_type);
+    }
+
+    // TODO: Tell WifiController about the event
+out:
+    free(data);
+    return true;
+}
diff --git a/nexus/TiwlanEventListener.h b/nexus/TiwlanEventListener.h
new file mode 100644
index 0000000..052d6b1
--- /dev/null
+++ b/nexus/TiwlanEventListener.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _TIWLAN_EVENT_LISTENER_H__
+#define _TIWLAN_EVENT_LISTENER_H__
+
+#include <sysutils/SocketListener.h>
+
+struct wpa_ctrl;
+class SocketClient;
+class ITiwlanEventHandler;
+class TiwlanEventFactory;
+
+class TiwlanEventListener: public SocketListener {
+    
+public:
+    TiwlanEventListener(int sock);
+    virtual ~TiwlanEventListener() {}
+
+protected:
+    virtual bool onDataAvailable(SocketClient *c);
+};
+
+// TODO: Move all this crap into a factory
+#define TI_DRIVER_MSG_PORT 9001
+
+#define IPC_EVENT_LINK_SPEED  2
+#define IPC_EVENT_LOW_SNR     13
+#define IPC_EVENT_LOW_RSSI    14
+
+struct ipc_ev_data {
+    uint32_t event_type;
+    void     *event_id;
+    uint32_t process_id;
+    uint32_t delivery_type;
+    uint32_t user_param;
+    void     *event_callback;
+    uint32_t bufferSize;
+    uint8_t  buffer[2048];
+};
+
+#endif
diff --git a/nexus/TiwlanWifiController.cpp b/nexus/TiwlanWifiController.cpp
index 6945e3e..61535c3 100644
--- a/nexus/TiwlanWifiController.cpp
+++ b/nexus/TiwlanWifiController.cpp
@@ -18,6 +18,9 @@
 #include <fcntl.h>
 #include <errno.h>
 #include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
 
 #include <cutils/properties.h>
 #define LOG_TAG "TiwlanWifiController"
@@ -25,6 +28,7 @@
 
 #include "PropertyManager.h"
 #include "TiwlanWifiController.h"
+#include "TiwlanEventListener.h"
 
 #define DRIVER_PROP_NAME "wlan.driver.status"
 
@@ -36,6 +40,8 @@
                                            char *modargs) :
                       WifiController(propmngr, handlers, modpath, modname,
                                      modargs) {
+    mEventListener = NULL;
+    mListenerSock = -1;
 }
 
 int TiwlanWifiController::powerUp() {
@@ -43,6 +49,13 @@
 }
 
 int TiwlanWifiController::powerDown() {
+    if (mEventListener) {
+        delete mEventListener;
+        close(mListenerSock);
+        mListenerSock = -1;
+        mEventListener = NULL;
+    }
+   
     return 0; // Powerdown is currently done when the driver is unloaded
 }
 
@@ -60,17 +73,56 @@
     // Wait for driver to be ready
     while (count-- > 0) {
         if (property_get(DRIVER_PROP_NAME, driver_status, NULL)) {
-            if (strcmp(driver_status, "ok") == 0)
+            if (!strcmp(driver_status, "ok")) {
+                LOGD("Firmware loaded OK");
+
+                if (startDriverEventListener()) {
+                    LOGW("Failed to start driver event listener");
+                }
+
                 return 0;
-            else if (strcmp(DRIVER_PROP_NAME, "failed") == 0)
+            } else if (!strcmp(DRIVER_PROP_NAME, "failed")) {
+                LOGE("Firmware load failed");
                 return -1;
+            }
         }
         usleep(200000);
     }
     property_set(DRIVER_PROP_NAME, "timeout");
+    LOGE("Firmware load timed out");
     return -1;
 }
 
+int TiwlanWifiController::startDriverEventListener() {
+    struct sockaddr_in addr;
+    int s;
+
+    if ((s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
+        return -1;
+
+    memset(&addr, 0, sizeof(addr));
+    addr.sin_family = AF_INET;
+    addr.sin_addr.s_addr = htonl(INADDR_ANY);
+    addr.sin_port = htons(TI_DRIVER_MSG_PORT);
+
+    if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+        close(s);
+        return -1;
+    }
+
+    mEventListener = new TiwlanEventListener(s);
+
+    if (mEventListener->startListener()) {
+        LOGE("Error starting driver listener (%s)", strerror(errno));
+        delete mEventListener;
+        mEventListener = NULL;
+        close(s);
+        return -1;
+    }
+    mListenerSock = s;
+    return 0;
+}
+
 bool TiwlanWifiController::isFirmwareLoaded() {
     // Always load the firmware
     return false;
diff --git a/nexus/TiwlanWifiController.h b/nexus/TiwlanWifiController.h
index 852a288..583be71 100644
--- a/nexus/TiwlanWifiController.h
+++ b/nexus/TiwlanWifiController.h
@@ -21,8 +21,12 @@
 #include "WifiController.h"
 
 class IControllerHandler;
+class TiwlanEventListener;
 
 class TiwlanWifiController : public WifiController {
+    int                 mListenerSock;
+    TiwlanEventListener *mEventListener;
+
 public:
     TiwlanWifiController(PropertyManager *propmngr, IControllerHandler *handlers, char *modpath, char *modname, char *modargs);
     virtual ~TiwlanWifiController() {}
@@ -32,5 +36,8 @@
     virtual bool isPoweredUp();
     virtual int loadFirmware();
     virtual bool isFirmwareLoaded();
+
+private:
+    int startDriverEventListener();
 };
 #endif