Merge "Implements white balance and exposure compensation for emulated webcam"
diff --git a/android/hw-qemud.c b/android/hw-qemud.c
index df9ab21..e80abed 100644
--- a/android/hw-qemud.c
+++ b/android/hw-qemud.c
@@ -824,30 +824,47 @@
 /* disconnect a client. this automatically frees the QemudClient.
  * note that this also removes the client from the global list
  * and from its service's list, if any.
+ * Param:
+ *  opaque - QemuClient instance
+ *  guest_close - For pipe clients control whether or not the disconnect is
+ *      caused by guest closing the pipe handle (in which case 1 is passed in
+ *      this parameter). For serial clients this parameter is ignored.
  */
 static void
-qemud_client_disconnect( void*  opaque )
+qemud_client_disconnect( void*  opaque, int guest_close )
 {
     QemudClient*  c = opaque;
 
     if (c->closing) {  /* recursive call, exit immediately */
         return;
     }
+
+    if (_is_pipe_client(c) && !guest_close) {
+        /* This is emulator component (rather than the guest) closing a pipe
+         * client. Since pipe clients are controlled strictly by the guest, we
+         * don't actually close the client here, but notify the guest about the
+         * client being disconnected. Then we will do the real client close when
+         * the guest explicitly closes the pipe, in which case this routine will
+         * be called from the _qemudPipe_closeFromGuest callback with guest_close
+         * set to 1. */
+        char  tmp[128], *p=tmp, *end=p+sizeof(tmp);
+        p = bufprint(tmp, end, "disconnect:00");
+        _qemud_pipe_send(c, (uint8_t*)tmp, p-tmp);
+        return;
+    }
+
     c->closing = 1;
 
     /* remove from current list */
     qemud_client_remove(c);
 
-    /* send a disconnect command to the daemon */
     if (_is_pipe_client(c)) {
-        char  tmp[128], *p=tmp, *end=p+sizeof(tmp);
-        p = bufprint(tmp, end, "disconnect:00");
-        _qemud_pipe_send(c, (uint8_t*)tmp, p-tmp);
         /* We must NULL the client reference in the QemuPipe for this connection,
          * so if a sudden receive request comes after client has been closed, we
          * don't blow up. */
         c->ProtocolSelector.Pipe.qemud_pipe->client = NULL;
     } else if (c->ProtocolSelector.Serial.channel > 0) {
+        /* send a disconnect command to the daemon */
         char  tmp[128], *p=tmp, *end=p+sizeof(tmp);
         p = bufprint(tmp, end, "disconnect:%02x",
                      c->ProtocolSelector.Serial.channel);
@@ -1348,7 +1365,7 @@
              * m->clients automatically.
              */
             c->ProtocolSelector.Serial.channel = -1; /* no need to send disconnect:<id> */
-            qemud_client_disconnect(c);
+            qemud_client_disconnect(c, 0);
             return;
         }
     }
@@ -1378,7 +1395,7 @@
             D("%s: disconnecting client %d\n",
               __FUNCTION__, c->ProtocolSelector.Serial.channel);
             c->ProtocolSelector.Serial.channel = -1; /* do not send disconnect:<id> */
-            qemud_client_disconnect(c);
+            qemud_client_disconnect(c, 0);
         }
     }
 }
@@ -1695,7 +1712,7 @@
 void
 qemud_client_close( QemudClient*  client )
 {
-    qemud_client_disconnect(client);
+    qemud_client_disconnect(client, 0);
 }
 
 
@@ -1945,7 +1962,7 @@
     QemudClient*  client = pipe->client;
     D("%s", __FUNCTION__);
     if (client != NULL) {
-        qemud_client_disconnect(client);
+        qemud_client_disconnect(client, 1);
     } else {
         D("%s: Unexpected NULL client", __FUNCTION__);
     }
diff --git a/android/utils/list.h b/android/utils/list.h
new file mode 100644
index 0000000..a4171ae
--- /dev/null
+++ b/android/utils/list.h
@@ -0,0 +1,112 @@
+/* Copyright (C) 2011 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+*/
+#ifndef _ANDROID_UTILS_LIST_H
+#define _ANDROID_UTILS_LIST_H
+
+#include <inttypes.h>
+
+/* Encapsulates a double-linked, circular list.
+ * The list is organized in the following way:
+ * - List entries contain references to the next, and the previous entry in the
+ *   list.
+ * - The list is circular, i.e. the "last" list entry references the "list head"
+ *   in its 'next' reference, and the "list head" references the "last" entry in
+ *   its 'previous' reference.
+ * - The list is empty if its 'next' and 'previous' references are addressing the
+ *   head of the list.
+ */
+typedef struct ACList ACList;
+struct ACList {
+    /* Next entry in the list */
+    ACList*  next;
+    /* Previous entry in the list */
+    ACList*  prev;
+};
+
+/* Initializes the list. */
+AINLINED void
+alist_init(ACList* list)
+{
+    list->next = list->prev = list;
+}
+
+/* Checks if the list is empty. */
+AINLINED int
+alist_is_empty(const ACList* list)
+{
+    return list->next == list;
+}
+
+/* Inserts an entry to the head of the list */
+AINLINED void
+alist_insert_head(ACList* list, ACList* entry)
+{
+    ACList* const next = list->next;
+    entry->next = next;
+    entry->prev = list;
+    next->prev = entry;
+    list->next = entry;
+}
+/* Inserts an entry to the tail of the list */
+AINLINED void
+alist_insert_tail(ACList* list, ACList* entry)
+{
+    ACList* const prev = list->prev;
+    entry->next = list;
+    entry->prev = prev;
+    prev->next = entry;
+    list->prev = entry;
+}
+
+/* Removes an entry from the list. NOTE: Entry must be in the list when this
+ * routine is called. */
+AINLINED void
+alist_remove(ACList* entry)
+{
+    ACList* const next = entry->next;
+    ACList* const prev = entry->prev;
+    prev->next = next;
+    next->prev = prev;
+    entry->next = entry->prev = entry;
+}
+
+/* Returns an entry removed from the head of the list. If the list was empty,
+ * this routine returns NULL. */
+AINLINED ACList*
+alist_remove_head(ACList* list)
+{
+    ACList* entry = NULL;
+    if (!alist_is_empty(list)) {
+        entry = list->next;
+        list->next = entry->next;
+        entry->next->prev = list;
+        entry->next = entry->prev = entry;
+    }
+    return entry;
+}
+
+/* Returns an entry removed from the tail of the list. If the list was empty,
+ * this routine returns NULL. */
+AINLINED ACList*
+alist_remove_tail(ACList* list)
+{
+    ACList* entry = NULL;
+    if (!alist_is_empty(list)) {
+        entry = list->prev;
+        list->prev = entry->prev;
+        entry->prev->next = list;
+        entry->next = entry->prev = entry;
+    }
+    return entry;
+}
+
+#endif  /* _ANDROID_UTILS_LIST_H */