android_pipe: Factor out example/test pipes from android_pipe

The Android Pipe main implementation file should only contain the actual
implementation.  Keeping all that test backend implementation code in
there just makes it confusing to grep in the file and figure out what is
going on.

This could be made dependent on some sort of debug flag to avoid
compiling test code as part of shipped binaries in the future.

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index 315d128..54a1f65 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -15,6 +15,7 @@
 common-obj-$(CONFIG_ARM11SCU) += arm11scu.o
 
 obj-$(CONFIG_ANDROID_PIPE) += android_pipe.o
+obj-$(CONFIG_ANDROID_PIPE) += android_pipe_test.o
 
 # PKUnity SoC devices
 common-obj-$(CONFIG_PUV3) += puv3_pm.o
diff --git a/hw/misc/android_pipe.c b/hw/misc/android_pipe.c
index 90bce95..5b44f0c 100644
--- a/hw/misc/android_pipe.c
+++ b/hw/misc/android_pipe.c
@@ -71,15 +71,6 @@
         exit(1);                        \
     } while (0);
 
-/* Set to 1 to enable the 'zero' pipe type, useful for debugging */
-#define DEBUG_ZERO_PIPE  1
-
-/* Set to 1 to enable the 'pingpong' pipe type, useful for debugging */
-#define DEBUG_PINGPONG_PIPE 1
-
-/* Set to 1 to enable the 'throttle' pipe type, useful for debugging */
-#define DEBUG_THROTTLE_PIPE 1
-
 /* Maximum length of pipe service name, in characters (excluding final 0) */
 #define MAX_PIPE_SERVICE_NAME_SIZE  255
 
@@ -459,458 +450,6 @@
     pipeConnector_load,
 };
 
-/***********************************************************************
- ***********************************************************************
- *****
- *****    Z E R O   P I P E S
- *****
- *****/
-
-/* A simple pipe service that mimics /dev/zero, you can write anything to
- * it, and you can always read any number of zeros from it. Useful for debugging
- * the kernel driver.
- */
-#if DEBUG_ZERO_PIPE
-
-typedef struct {
-    void* hwpipe;
-} ZeroPipe;
-
-static void*
-zeroPipe_init( void* hwpipe, void* svcOpaque, const char* args )
-{
-    ZeroPipe*  zpipe;
-
-    D("%s: hwpipe=%p", __FUNCTION__, hwpipe);
-    zpipe = g_malloc0(sizeof(ZeroPipe));
-    zpipe->hwpipe = hwpipe;
-    return zpipe;
-}
-
-static void
-zeroPipe_close( void* opaque )
-{
-    ZeroPipe*  zpipe = opaque;
-
-    D("%s: hwpipe=%p", __FUNCTION__, zpipe->hwpipe);
-    g_free(zpipe);
-}
-
-static int
-zeroPipe_sendBuffers( void* opaque, const AndroidPipeBuffer* buffers, int numBuffers )
-{
-    int  ret = 0;
-    while (numBuffers > 0) {
-        ret += buffers[0].size;
-        buffers++;
-        numBuffers--;
-    }
-    return ret;
-}
-
-static int
-zeroPipe_recvBuffers( void* opaque, AndroidPipeBuffer* buffers, int numBuffers )
-{
-    int  ret = 0;
-    while (numBuffers > 0) {
-        ret += buffers[0].size;
-        memset(buffers[0].data, 0, buffers[0].size);
-        buffers++;
-        numBuffers--;
-    }
-    return ret;
-}
-
-static unsigned
-zeroPipe_poll( void* opaque )
-{
-    return PIPE_POLL_IN | PIPE_POLL_OUT;
-}
-
-static void
-zeroPipe_wakeOn( void* opaque, int flags )
-{
-    /* nothing to do here */
-}
-
-static const AndroidPipeFuncs  zeroPipe_funcs = {
-    zeroPipe_init,
-    zeroPipe_close,
-    zeroPipe_sendBuffers,
-    zeroPipe_recvBuffers,
-    zeroPipe_poll,
-    zeroPipe_wakeOn,
-};
-
-#endif /* DEBUG_ZERO */
-
-/***********************************************************************
- ***********************************************************************
- *****
- *****    P I N G   P O N G   P I P E S
- *****
- *****/
-
-/* Similar debug service that sends back anything it receives */
-/* All data is kept in a circular dynamic buffer */
-
-#if DEBUG_PINGPONG_PIPE
-
-/* Initial buffer size */
-#define PINGPONG_SIZE  1024
-
-typedef struct {
-    void*     hwpipe;
-    uint8_t*  buffer;
-    size_t    size;
-    size_t    pos;
-    size_t    count;
-    unsigned  flags;
-} PingPongPipe;
-
-static void
-pingPongPipe_init0( PingPongPipe* pipe, void* hwpipe, void* svcOpaque )
-{
-    pipe->hwpipe = hwpipe;
-    pipe->size = PINGPONG_SIZE;
-    pipe->buffer = malloc(pipe->size);
-    pipe->pos = 0;
-    pipe->count = 0;
-}
-
-static void*
-pingPongPipe_init( void* hwpipe, void* svcOpaque, const char* args )
-{
-    PingPongPipe*  ppipe;
-
-    D("%s: hwpipe=%p", __FUNCTION__, hwpipe);
-    ppipe = g_malloc0(sizeof(PingPongPipe));
-    pingPongPipe_init0(ppipe, hwpipe, svcOpaque);
-    return ppipe;
-}
-
-static void
-pingPongPipe_close( void* opaque )
-{
-    PingPongPipe*  ppipe = opaque;
-
-    D("%s: hwpipe=%p (pos=%zd count=%zd size=%zd)", __FUNCTION__,
-      ppipe->hwpipe, ppipe->pos, ppipe->count, ppipe->size);
-    free(ppipe->buffer);
-    g_free(ppipe);
-}
-
-static int
-pingPongPipe_sendBuffers( void* opaque, const AndroidPipeBuffer* buffers, int numBuffers )
-{
-    PingPongPipe*  pipe = opaque;
-    int  ret = 0;
-    int  count;
-    const AndroidPipeBuffer* buff = buffers;
-    const AndroidPipeBuffer* buffEnd = buff + numBuffers;
-
-    count = 0;
-    for ( ; buff < buffEnd; buff++ )
-        count += buff->size;
-
-    /* Do we need to grow the pingpong buffer? */
-    while (count > pipe->size - pipe->count) {
-        size_t    newsize = pipe->size*2;
-        uint8_t*  newbuff = realloc(pipe->buffer, newsize);
-        int       wpos    = pipe->pos + pipe->count;
-        if (newbuff == NULL) {
-            break;
-        }
-        if (wpos > pipe->size) {
-            wpos -= pipe->size;
-            memcpy(newbuff + pipe->size, newbuff, wpos);
-        }
-        pipe->buffer = newbuff;
-        pipe->size   = newsize;
-        D("pingpong buffer is now %zd bytes", newsize);
-    }
-
-    for ( buff = buffers; buff < buffEnd; buff++ ) {
-        int avail = pipe->size - pipe->count;
-        if (avail <= 0) {
-            if (ret == 0)
-                ret = PIPE_ERROR_AGAIN;
-            break;
-        }
-        if (avail > buff->size) {
-            avail = buff->size;
-        }
-
-        int wpos = pipe->pos + pipe->count;
-        if (wpos >= pipe->size) {
-            wpos -= pipe->size;
-        }
-        if (wpos + avail <= pipe->size) {
-            memcpy(pipe->buffer + wpos, buff->data, avail);
-        } else {
-            int  avail2 = pipe->size - wpos;
-            memcpy(pipe->buffer + wpos, buff->data, avail2);
-            memcpy(pipe->buffer, buff->data + avail2, avail - avail2);
-        }
-        pipe->count += avail;
-        ret += avail;
-    }
-
-    /* Wake up any waiting readers if we wrote something */
-    if (pipe->count > 0 && (pipe->flags & PIPE_WAKE_READ)) {
-        android_pipe_wake(pipe->hwpipe, PIPE_WAKE_READ);
-    }
-
-    return ret;
-}
-
-static int
-pingPongPipe_recvBuffers( void* opaque, AndroidPipeBuffer* buffers, int numBuffers )
-{
-    PingPongPipe*  pipe = opaque;
-    int  ret = 0;
-
-    while (numBuffers > 0) {
-        int avail = pipe->count;
-        if (avail <= 0) {
-            if (ret == 0)
-                ret = PIPE_ERROR_AGAIN;
-            break;
-        }
-        if (avail > buffers[0].size) {
-            avail = buffers[0].size;
-        }
-
-        int rpos = pipe->pos;
-
-        if (rpos + avail <= pipe->size) {
-            memcpy(buffers[0].data, pipe->buffer + rpos, avail);
-        } else {
-            int  avail2 = pipe->size - rpos;
-            memcpy(buffers[0].data, pipe->buffer + rpos, avail2);
-            memcpy(buffers[0].data + avail2, pipe->buffer, avail - avail2);
-        }
-        pipe->count -= avail;
-        pipe->pos   += avail;
-        if (pipe->pos >= pipe->size) {
-            pipe->pos -= pipe->size;
-        }
-        ret += avail;
-        numBuffers--;
-        buffers++;
-    }
-
-    /* Wake up any waiting readers if we wrote something */
-    if (pipe->count < PINGPONG_SIZE && (pipe->flags & PIPE_WAKE_WRITE)) {
-        android_pipe_wake(pipe->hwpipe, PIPE_WAKE_WRITE);
-    }
-
-    return ret;
-}
-
-static unsigned
-pingPongPipe_poll( void* opaque )
-{
-    PingPongPipe*  pipe = opaque;
-    unsigned       ret = 0;
-
-    if (pipe->count < pipe->size)
-        ret |= PIPE_POLL_OUT;
-
-    if (pipe->count > 0)
-        ret |= PIPE_POLL_IN;
-
-    return ret;
-}
-
-static void
-pingPongPipe_wakeOn( void* opaque, int flags )
-{
-    PingPongPipe* pipe = opaque;
-    pipe->flags |= (unsigned)flags;
-}
-
-static const AndroidPipeFuncs  pingPongPipe_funcs = {
-    pingPongPipe_init,
-    pingPongPipe_close,
-    pingPongPipe_sendBuffers,
-    pingPongPipe_recvBuffers,
-    pingPongPipe_poll,
-    pingPongPipe_wakeOn,
-};
-
-#endif /* DEBUG_PINGPONG_PIPE */
-
-/***********************************************************************
- ***********************************************************************
- *****
- *****    T H R O T T L E   P I P E S
- *****
- *****/
-
-/* Similar to PingPongPipe, but will throttle the bandwidth to test
- * blocking I/O.
- */
-
-#ifdef DEBUG_THROTTLE_PIPE
-
-typedef struct {
-    PingPongPipe  pingpong;
-    double        sendRate;
-    int64_t       sendExpiration;
-    double        recvRate;
-    int64_t       recvExpiration;
-    QEMUTimer*    timer;
-} ThrottlePipe;
-
-/* forward declaration */
-static void throttlePipe_timerFunc( void* opaque );
-
-static void*
-throttlePipe_init( void* hwpipe, void* svcOpaque, const char* args )
-{
-    ThrottlePipe* pipe;
-
-    pipe = g_malloc0(sizeof(ThrottlePipe));
-    pingPongPipe_init0(&pipe->pingpong, hwpipe, svcOpaque);
-    pipe->timer = timer_new(QEMU_CLOCK_VIRTUAL, SCALE_NS, throttlePipe_timerFunc, pipe);
-    /* For now, limit to 500 KB/s in both directions */
-    pipe->sendRate = 1e9 / (500*1024*8);
-    pipe->recvRate = pipe->sendRate;
-    return pipe;
-}
-
-static void
-throttlePipe_close( void* opaque )
-{
-    ThrottlePipe* pipe = opaque;
-
-    timer_del(pipe->timer);
-    timer_free(pipe->timer);
-    pingPongPipe_close(&pipe->pingpong);
-}
-
-static void
-throttlePipe_rearm( ThrottlePipe* pipe )
-{
-    int64_t  minExpiration = 0;
-
-    DD("%s: sendExpiration=%" PRId64 " recvExpiration=%" PRId64"\n", __FUNCTION__, pipe->sendExpiration, pipe->recvExpiration);
-
-    if (pipe->sendExpiration) {
-        if (minExpiration == 0 || pipe->sendExpiration < minExpiration)
-            minExpiration = pipe->sendExpiration;
-    }
-
-    if (pipe->recvExpiration) {
-        if (minExpiration == 0 || pipe->recvExpiration < minExpiration)
-            minExpiration = pipe->recvExpiration;
-    }
-
-    if (minExpiration != 0) {
-        DD("%s: Arming for %" PRId64 "\n", __FUNCTION__, minExpiration);
-        timer_mod(pipe->timer, minExpiration);
-    }
-}
-
-static void
-throttlePipe_timerFunc( void* opaque )
-{
-    ThrottlePipe* pipe = opaque;
-    int64_t  now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-
-    DD("%s: TICK! now=%" PRId64 " sendExpiration=%" PRId64 " recvExpiration=%" PRId64 "\n",
-       __FUNCTION__, now, pipe->sendExpiration, pipe->recvExpiration);
-
-    /* Timer has expired, signal wake up if needed */
-    int      flags = 0;
-
-    if (pipe->sendExpiration && now > pipe->sendExpiration) {
-        flags |= PIPE_WAKE_WRITE;
-        pipe->sendExpiration = 0;
-    }
-    if (pipe->recvExpiration && now > pipe->recvExpiration) {
-        flags |= PIPE_WAKE_READ;
-        pipe->recvExpiration = 0;
-    }
-    flags &= pipe->pingpong.flags;
-    if (flags != 0) {
-        DD("%s: WAKE %d\n", __FUNCTION__, flags);
-        android_pipe_wake(pipe->pingpong.hwpipe, flags);
-    }
-
-    throttlePipe_rearm(pipe);
-}
-
-static int
-throttlePipe_sendBuffers( void* opaque, const AndroidPipeBuffer* buffers, int numBuffers )
-{
-    ThrottlePipe*  pipe = opaque;
-    int            ret;
-
-    if (pipe->sendExpiration > 0) {
-        return PIPE_ERROR_AGAIN;
-    }
-
-    ret = pingPongPipe_sendBuffers(&pipe->pingpong, buffers, numBuffers);
-    if (ret > 0) {
-        /* Compute next send expiration time */
-        pipe->sendExpiration = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ret*pipe->sendRate;
-        throttlePipe_rearm(pipe);
-    }
-    return ret;
-}
-
-static int
-throttlePipe_recvBuffers( void* opaque, AndroidPipeBuffer* buffers, int numBuffers )
-{
-    ThrottlePipe* pipe = opaque;
-    int           ret;
-
-    if (pipe->recvExpiration > 0) {
-        return PIPE_ERROR_AGAIN;
-    }
-
-    ret = pingPongPipe_recvBuffers(&pipe->pingpong, buffers, numBuffers);
-    if (ret > 0) {
-        pipe->recvExpiration = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ret*pipe->recvRate;
-        throttlePipe_rearm(pipe);
-    }
-    return ret;
-}
-
-static unsigned
-throttlePipe_poll( void* opaque )
-{
-    ThrottlePipe*  pipe = opaque;
-    unsigned       ret  = pingPongPipe_poll(&pipe->pingpong);
-
-    if (pipe->sendExpiration > 0)
-        ret &= ~PIPE_POLL_OUT;
-
-    if (pipe->recvExpiration > 0)
-        ret &= ~PIPE_POLL_IN;
-
-    return ret;
-}
-
-static void
-throttlePipe_wakeOn( void* opaque, int flags )
-{
-    ThrottlePipe* pipe = opaque;
-    pingPongPipe_wakeOn(&pipe->pingpong, flags);
-}
-
-static const AndroidPipeFuncs  throttlePipe_funcs = {
-    throttlePipe_init,
-    throttlePipe_close,
-    throttlePipe_sendBuffers,
-    throttlePipe_recvBuffers,
-    throttlePipe_poll,
-    throttlePipe_wakeOn,
-};
-
-#endif /* DEBUG_THROTTLE_PIPE */
 
 /***********************************************************************
  ***********************************************************************
@@ -1246,15 +785,9 @@
     sysbus_init_mmio(sbdev, &s->iomem);
     sysbus_init_irq(sbdev, &s->irq);
 
-#if DEBUG_ZERO_PIPE
-    android_pipe_add_type("zero", NULL, &zeroPipe_funcs);
-#endif
-#if DEBUG_PINGPONG_PIPE
-    android_pipe_add_type("pingpong", NULL, &pingPongPipe_funcs);
-#endif
-#if DEBUG_THROTTLE_PIPE
-    android_pipe_add_type("throttle", NULL, &throttlePipe_funcs);
-#endif
+    android_zero_pipe_init();
+    android_pingpong_init();
+    android_throttle_init();
 }
 
 void
diff --git a/hw/misc/android_pipe_test.c b/hw/misc/android_pipe_test.c
new file mode 100644
index 0000000..dc4a6e5
--- /dev/null
+++ b/hw/misc/android_pipe_test.c
@@ -0,0 +1,521 @@
+/* Copyright (C) 2011 The Android Open Source Project
+** Copyright (C) 2014 Linaro Limited
+**
+** 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.
+**
+** Description
+**
+** Example uses of Android Pipes.
+*/
+#include "hw/misc/android_pipe.h"
+
+#define  DEBUG 0
+
+/* Set to 1 to debug i/o register reads/writes */
+#define DEBUG_REGS  0
+
+#if DEBUG >= 1
+#  define D(...)  fprintf(stderr, __VA_ARGS__), fprintf(stderr, "\n")
+#else
+#  define D(...)  (void)0
+#endif
+
+#if DEBUG >= 2
+#  define DD(...)  fprintf(stderr, __VA_ARGS__), fprintf(stderr, "\n")
+#else
+#  define DD(...)  (void)0
+#endif
+
+#if DEBUG_REGS >= 1
+#  define DR(...)   D(__VA_ARGS__)
+#else
+#  define DR(...)   (void)0
+#endif
+
+#define E(...)  fprintf(stderr, "ERROR:" __VA_ARGS__), fprintf(stderr, "\n")
+
+/* Set to 1 to enable the 'zero' pipe type, useful for debugging */
+#define DEBUG_ZERO_PIPE  1
+
+/* Set to 1 to enable the 'pingpong' pipe type, useful for debugging */
+#define DEBUG_PINGPONG_PIPE 1
+
+/* Set to 1 to enable the 'throttle' pipe type, useful for debugging */
+#define DEBUG_THROTTLE_PIPE 1
+
+
+/***********************************************************************
+ ***********************************************************************
+ *****
+ *****    Z E R O   P I P E S
+ *****
+ *****/
+
+/* A simple pipe service that mimics /dev/zero, you can write anything to
+ * it, and you can always read any number of zeros from it. Useful for debugging
+ * the kernel driver.
+ */
+
+typedef struct {
+    void* hwpipe;
+} ZeroPipe;
+
+static void*
+zeroPipe_init( void* hwpipe, void* svcOpaque, const char* args )
+{
+    ZeroPipe*  zpipe;
+
+    D("%s: hwpipe=%p", __FUNCTION__, hwpipe);
+    zpipe = g_malloc0(sizeof(ZeroPipe));
+    zpipe->hwpipe = hwpipe;
+    return zpipe;
+}
+
+static void
+zeroPipe_close( void* opaque )
+{
+    ZeroPipe*  zpipe = opaque;
+
+    D("%s: hwpipe=%p", __FUNCTION__, zpipe->hwpipe);
+    g_free(zpipe);
+}
+
+static int
+zeroPipe_sendBuffers( void* opaque, const AndroidPipeBuffer* buffers, int numBuffers )
+{
+    int  ret = 0;
+    while (numBuffers > 0) {
+        ret += buffers[0].size;
+        buffers++;
+        numBuffers--;
+    }
+    return ret;
+}
+
+static int
+zeroPipe_recvBuffers( void* opaque, AndroidPipeBuffer* buffers, int numBuffers )
+{
+    int  ret = 0;
+    while (numBuffers > 0) {
+        ret += buffers[0].size;
+        memset(buffers[0].data, 0, buffers[0].size);
+        buffers++;
+        numBuffers--;
+    }
+    return ret;
+}
+
+static unsigned
+zeroPipe_poll( void* opaque )
+{
+    return PIPE_POLL_IN | PIPE_POLL_OUT;
+}
+
+static void
+zeroPipe_wakeOn( void* opaque, int flags )
+{
+    /* nothing to do here */
+}
+
+static const AndroidPipeFuncs  zeroPipe_funcs = {
+    zeroPipe_init,
+    zeroPipe_close,
+    zeroPipe_sendBuffers,
+    zeroPipe_recvBuffers,
+    zeroPipe_poll,
+    zeroPipe_wakeOn,
+};
+
+#if DEBUG_ZERO_PIPE
+void android_zero_pipe_init(void)
+{
+    android_pipe_add_type("zero", NULL, &zeroPipe_funcs);
+}
+#else
+void android_zero_pipe_init(void) { }
+#endif /* DEBUG_ZERO */
+
+/***********************************************************************
+ ***********************************************************************
+ *****
+ *****    P I N G   P O N G   P I P E S
+ *****
+ *****/
+
+/* Similar debug service that sends back anything it receives */
+/* All data is kept in a circular dynamic buffer */
+
+/* Initial buffer size */
+#define PINGPONG_SIZE  1024
+
+typedef struct {
+    void*     hwpipe;
+    uint8_t*  buffer;
+    size_t    size;
+    size_t    pos;
+    size_t    count;
+    unsigned  flags;
+} PingPongPipe;
+
+static void
+pingPongPipe_init0( PingPongPipe* pipe, void* hwpipe, void* svcOpaque )
+{
+    pipe->hwpipe = hwpipe;
+    pipe->size = PINGPONG_SIZE;
+    pipe->buffer = malloc(pipe->size);
+    pipe->pos = 0;
+    pipe->count = 0;
+}
+
+static void*
+pingPongPipe_init( void* hwpipe, void* svcOpaque, const char* args )
+{
+    PingPongPipe*  ppipe;
+
+    D("%s: hwpipe=%p", __FUNCTION__, hwpipe);
+    ppipe = g_malloc0(sizeof(PingPongPipe));
+    pingPongPipe_init0(ppipe, hwpipe, svcOpaque);
+    return ppipe;
+}
+
+static void
+pingPongPipe_close( void* opaque )
+{
+    PingPongPipe*  ppipe = opaque;
+
+    D("%s: hwpipe=%p (pos=%zd count=%zd size=%zd)", __FUNCTION__,
+      ppipe->hwpipe, ppipe->pos, ppipe->count, ppipe->size);
+    free(ppipe->buffer);
+    g_free(ppipe);
+}
+
+static int
+pingPongPipe_sendBuffers( void* opaque, const AndroidPipeBuffer* buffers, int numBuffers )
+{
+    PingPongPipe*  pipe = opaque;
+    int  ret = 0;
+    int  count;
+    const AndroidPipeBuffer* buff = buffers;
+    const AndroidPipeBuffer* buffEnd = buff + numBuffers;
+
+    count = 0;
+    for ( ; buff < buffEnd; buff++ )
+        count += buff->size;
+
+    /* Do we need to grow the pingpong buffer? */
+    while (count > pipe->size - pipe->count) {
+        size_t    newsize = pipe->size*2;
+        uint8_t*  newbuff = realloc(pipe->buffer, newsize);
+        int       wpos    = pipe->pos + pipe->count;
+        if (newbuff == NULL) {
+            break;
+        }
+        if (wpos > pipe->size) {
+            wpos -= pipe->size;
+            memcpy(newbuff + pipe->size, newbuff, wpos);
+        }
+        pipe->buffer = newbuff;
+        pipe->size   = newsize;
+        D("pingpong buffer is now %zd bytes", newsize);
+    }
+
+    for ( buff = buffers; buff < buffEnd; buff++ ) {
+        int avail = pipe->size - pipe->count;
+        if (avail <= 0) {
+            if (ret == 0)
+                ret = PIPE_ERROR_AGAIN;
+            break;
+        }
+        if (avail > buff->size) {
+            avail = buff->size;
+        }
+
+        int wpos = pipe->pos + pipe->count;
+        if (wpos >= pipe->size) {
+            wpos -= pipe->size;
+        }
+        if (wpos + avail <= pipe->size) {
+            memcpy(pipe->buffer + wpos, buff->data, avail);
+        } else {
+            int  avail2 = pipe->size - wpos;
+            memcpy(pipe->buffer + wpos, buff->data, avail2);
+            memcpy(pipe->buffer, buff->data + avail2, avail - avail2);
+        }
+        pipe->count += avail;
+        ret += avail;
+    }
+
+    /* Wake up any waiting readers if we wrote something */
+    if (pipe->count > 0 && (pipe->flags & PIPE_WAKE_READ)) {
+        android_pipe_wake(pipe->hwpipe, PIPE_WAKE_READ);
+    }
+
+    return ret;
+}
+
+static int
+pingPongPipe_recvBuffers( void* opaque, AndroidPipeBuffer* buffers, int numBuffers )
+{
+    PingPongPipe*  pipe = opaque;
+    int  ret = 0;
+
+    while (numBuffers > 0) {
+        int avail = pipe->count;
+        if (avail <= 0) {
+            if (ret == 0)
+                ret = PIPE_ERROR_AGAIN;
+            break;
+        }
+        if (avail > buffers[0].size) {
+            avail = buffers[0].size;
+        }
+
+        int rpos = pipe->pos;
+
+        if (rpos + avail <= pipe->size) {
+            memcpy(buffers[0].data, pipe->buffer + rpos, avail);
+        } else {
+            int  avail2 = pipe->size - rpos;
+            memcpy(buffers[0].data, pipe->buffer + rpos, avail2);
+            memcpy(buffers[0].data + avail2, pipe->buffer, avail - avail2);
+        }
+        pipe->count -= avail;
+        pipe->pos   += avail;
+        if (pipe->pos >= pipe->size) {
+            pipe->pos -= pipe->size;
+        }
+        ret += avail;
+        numBuffers--;
+        buffers++;
+    }
+
+    /* Wake up any waiting readers if we wrote something */
+    if (pipe->count < PINGPONG_SIZE && (pipe->flags & PIPE_WAKE_WRITE)) {
+        android_pipe_wake(pipe->hwpipe, PIPE_WAKE_WRITE);
+    }
+
+    return ret;
+}
+
+static unsigned
+pingPongPipe_poll( void* opaque )
+{
+    PingPongPipe*  pipe = opaque;
+    unsigned       ret = 0;
+
+    if (pipe->count < pipe->size)
+        ret |= PIPE_POLL_OUT;
+
+    if (pipe->count > 0)
+        ret |= PIPE_POLL_IN;
+
+    return ret;
+}
+
+static void
+pingPongPipe_wakeOn( void* opaque, int flags )
+{
+    PingPongPipe* pipe = opaque;
+    pipe->flags |= (unsigned)flags;
+}
+
+static const AndroidPipeFuncs  pingPongPipe_funcs = {
+    pingPongPipe_init,
+    pingPongPipe_close,
+    pingPongPipe_sendBuffers,
+    pingPongPipe_recvBuffers,
+    pingPongPipe_poll,
+    pingPongPipe_wakeOn,
+};
+
+#if DEBUG_PINGPONG_PIPE
+void android_pingpong_init(void)
+{
+    android_pipe_add_type("pingpong", NULL, &pingPongPipe_funcs);
+}
+#else
+void android_pingpong_init(void) { }
+#endif /* DEBUG_PINGPONG_PIPE */
+
+/***********************************************************************
+ ***********************************************************************
+ *****
+ *****    T H R O T T L E   P I P E S
+ *****
+ *****/
+
+/* Similar to PingPongPipe, but will throttle the bandwidth to test
+ * blocking I/O.
+ */
+
+typedef struct {
+    PingPongPipe  pingpong;
+    double        sendRate;
+    int64_t       sendExpiration;
+    double        recvRate;
+    int64_t       recvExpiration;
+    QEMUTimer*    timer;
+} ThrottlePipe;
+
+/* forward declaration */
+static void throttlePipe_timerFunc( void* opaque );
+
+static void*
+throttlePipe_init( void* hwpipe, void* svcOpaque, const char* args )
+{
+    ThrottlePipe* pipe;
+
+    pipe = g_malloc0(sizeof(ThrottlePipe));
+    pingPongPipe_init0(&pipe->pingpong, hwpipe, svcOpaque);
+    pipe->timer = timer_new(QEMU_CLOCK_VIRTUAL, SCALE_NS, throttlePipe_timerFunc, pipe);
+    /* For now, limit to 500 KB/s in both directions */
+    pipe->sendRate = 1e9 / (500*1024*8);
+    pipe->recvRate = pipe->sendRate;
+    return pipe;
+}
+
+static void
+throttlePipe_close( void* opaque )
+{
+    ThrottlePipe* pipe = opaque;
+
+    timer_del(pipe->timer);
+    timer_free(pipe->timer);
+    pingPongPipe_close(&pipe->pingpong);
+}
+
+static void
+throttlePipe_rearm( ThrottlePipe* pipe )
+{
+    int64_t  minExpiration = 0;
+
+    DD("%s: sendExpiration=%" PRId64 " recvExpiration=%" PRId64"\n", __FUNCTION__, pipe->sendExpiration, pipe->recvExpiration);
+
+    if (pipe->sendExpiration) {
+        if (minExpiration == 0 || pipe->sendExpiration < minExpiration)
+            minExpiration = pipe->sendExpiration;
+    }
+
+    if (pipe->recvExpiration) {
+        if (minExpiration == 0 || pipe->recvExpiration < minExpiration)
+            minExpiration = pipe->recvExpiration;
+    }
+
+    if (minExpiration != 0) {
+        DD("%s: Arming for %" PRId64 "\n", __FUNCTION__, minExpiration);
+        timer_mod(pipe->timer, minExpiration);
+    }
+}
+
+static void
+throttlePipe_timerFunc( void* opaque )
+{
+    ThrottlePipe* pipe = opaque;
+    int64_t  now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+
+    DD("%s: TICK! now=%" PRId64 " sendExpiration=%" PRId64 " recvExpiration=%" PRId64 "\n",
+       __FUNCTION__, now, pipe->sendExpiration, pipe->recvExpiration);
+
+    /* Timer has expired, signal wake up if needed */
+    int      flags = 0;
+
+    if (pipe->sendExpiration && now > pipe->sendExpiration) {
+        flags |= PIPE_WAKE_WRITE;
+        pipe->sendExpiration = 0;
+    }
+    if (pipe->recvExpiration && now > pipe->recvExpiration) {
+        flags |= PIPE_WAKE_READ;
+        pipe->recvExpiration = 0;
+    }
+    flags &= pipe->pingpong.flags;
+    if (flags != 0) {
+        DD("%s: WAKE %d\n", __FUNCTION__, flags);
+        android_pipe_wake(pipe->pingpong.hwpipe, flags);
+    }
+
+    throttlePipe_rearm(pipe);
+}
+
+static int
+throttlePipe_sendBuffers( void* opaque, const AndroidPipeBuffer* buffers, int numBuffers )
+{
+    ThrottlePipe*  pipe = opaque;
+    int            ret;
+
+    if (pipe->sendExpiration > 0) {
+        return PIPE_ERROR_AGAIN;
+    }
+
+    ret = pingPongPipe_sendBuffers(&pipe->pingpong, buffers, numBuffers);
+    if (ret > 0) {
+        /* Compute next send expiration time */
+        pipe->sendExpiration = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ret*pipe->sendRate;
+        throttlePipe_rearm(pipe);
+    }
+    return ret;
+}
+
+static int
+throttlePipe_recvBuffers( void* opaque, AndroidPipeBuffer* buffers, int numBuffers )
+{
+    ThrottlePipe* pipe = opaque;
+    int           ret;
+
+    if (pipe->recvExpiration > 0) {
+        return PIPE_ERROR_AGAIN;
+    }
+
+    ret = pingPongPipe_recvBuffers(&pipe->pingpong, buffers, numBuffers);
+    if (ret > 0) {
+        pipe->recvExpiration = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ret*pipe->recvRate;
+        throttlePipe_rearm(pipe);
+    }
+    return ret;
+}
+
+static unsigned
+throttlePipe_poll( void* opaque )
+{
+    ThrottlePipe*  pipe = opaque;
+    unsigned       ret  = pingPongPipe_poll(&pipe->pingpong);
+
+    if (pipe->sendExpiration > 0)
+        ret &= ~PIPE_POLL_OUT;
+
+    if (pipe->recvExpiration > 0)
+        ret &= ~PIPE_POLL_IN;
+
+    return ret;
+}
+
+static void
+throttlePipe_wakeOn( void* opaque, int flags )
+{
+    ThrottlePipe* pipe = opaque;
+    pingPongPipe_wakeOn(&pipe->pingpong, flags);
+}
+
+static const AndroidPipeFuncs  throttlePipe_funcs = {
+    throttlePipe_init,
+    throttlePipe_close,
+    throttlePipe_sendBuffers,
+    throttlePipe_recvBuffers,
+    throttlePipe_poll,
+    throttlePipe_wakeOn,
+};
+
+#ifdef DEBUG_THROTTLE_PIPE
+void android_throttle_init(void)
+{
+    android_pipe_add_type("throttle", NULL, &throttlePipe_funcs);
+}
+#else
+void android_throttle_init(void) { }
+#endif /* DEBUG_THROTTLE_PIPE */
diff --git a/include/hw/misc/android_pipe.h b/include/hw/misc/android_pipe.h
index 3fa7e18..4db3731 100644
--- a/include/hw/misc/android_pipe.h
+++ b/include/hw/misc/android_pipe.h
@@ -217,4 +217,8 @@
     uint32_t flags;
 };
 
+extern void android_zero_pipe_init(void);
+extern void android_pingpong_init(void);
+extern void android_throttle_init(void);
+
 #endif /* _HW_ANDROID_PIPE_H */