android: Add android_pipe virtual device.

WARNING: This is a basic version that doesn't use AndroidEmu.
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index 6db7837..2236e8f 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -14,6 +14,8 @@
 common-obj-$(CONFIG_A9SCU) += a9scu.o
 common-obj-$(CONFIG_ARM11SCU) += arm11scu.o
 
+obj-$(CONFIG_ANDROID_PIPE) += android_pipe.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
new file mode 100644
index 0000000..17a7a47
--- /dev/null
+++ b/hw/misc/android_pipe.c
@@ -0,0 +1,858 @@
+/* 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
+**
+** This device provides a virtual pipe device (originally called
+** goldfish_pipe and latterly qemu_pipe). This allows the android
+** running under the emulator to open a fast connection to the host
+** for various purposes including the adb debug bridge and
+** (eventually) the opengles pass-through. This file contains only the
+** basic pipe infrastructure and a couple of test pipes. Additional
+** pipes are registered with the android_pipe_add_type() call.
+**
+** Open Questions
+**
+** Since this was originally written there have been a number of other
+** virtual devices added to QEMU using the virtio infrastructure. We
+** should give some thought to if this needs re-writing to take
+** advantage of that infrastructure to create the pipes.
+*/
+
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+
+#include "hw/misc/android_pipe.h"
+#include "qemu-common.h"
+#include "qemu/timer.h"
+#include "qemu/error-report.h"
+
+/* Set to > 0 for debug output */
+#define PIPE_DEBUG 0
+
+/* Set to 1 to debug i/o register reads/writes */
+#define PIPE_DEBUG_REGS 0
+
+#if PIPE_DEBUG >= 1
+#define D(fmt, ...) \
+    do { fprintf(stdout, "android_pipe: " fmt "\n", ## __VA_ARGS__); } while (0)
+#else
+#define D(fmt, ...)  do { /* nothing */ } while (0)
+#endif
+
+#if PIPE_DEBUG >= 2
+#define DD(fmt, ...) \
+    do { fprintf(stdout, "android_pipe: " fmt "\n", ## __VA_ARGS__); } while (0)
+#else
+#define DD(fmt, ...)  do { /* nothing */ } while (0)
+#endif
+
+#if PIPE_DEBUG_REGS >= 1
+#  define DR(...)   D(__VA_ARGS__)
+#else
+#  define DR(...)   do { /* nothing */ } while (0)
+#endif
+
+#define E(fmt, ...)  \
+    do { fprintf(stdout, "ERROR:" fmt "\n", ## __VA_ARGS__); } while (0)
+
+#define APANIC(...)                     \
+    do {                                \
+        error_report(__VA_ARGS__);      \
+        exit(1);                        \
+    } while (0);
+
+/* Maximum length of pipe service name, in characters (excluding final 0) */
+#define MAX_PIPE_SERVICE_NAME_SIZE  255
+
+/* from AOSP version include/hw/android/goldfish/device.h
+ * FIXME?: needs to use proper qemu abstractions
+ */
+static inline void uint64_set_low(uint64_t *addr, uint32 value)
+{
+    *addr = (*addr & ~(0xFFFFFFFFULL)) | value;
+}
+
+static inline void uint64_set_high(uint64_t *addr, uint32 value)
+{
+    *addr = (*addr & 0xFFFFFFFFULL) | ((uint64_t)value << 32);
+}
+
+#define TYPE_ANDROID_PIPE "android_pipe"
+#define ANDROID_PIPE(obj) \
+    OBJECT_CHECK(AndroidPipeState, (obj), TYPE_ANDROID_PIPE)
+
+typedef struct PipeDevice  PipeDevice;
+
+typedef struct {
+    SysBusDevice parent;
+    MemoryRegion iomem;
+    qemu_irq irq;
+
+    /* TODO: roll into shared state */
+    PipeDevice *dev;
+} AndroidPipeState;
+
+
+/***********************************************************************
+ ***********************************************************************
+ *****
+ *****   P I P E   S E R V I C E   R E G I S T R A T I O N
+ *****
+ *****/
+
+#define MAX_PIPE_SERVICES  8
+typedef struct {
+    const char          *name;
+    void                *opaque;        /* pipe specific data */
+    AndroidPipeFuncs    funcs;
+} PipeService;
+
+typedef struct {
+    int          count;
+    PipeService  services[MAX_PIPE_SERVICES];
+} PipeServices;
+
+static PipeServices  _pipeServices[1];
+
+void
+android_pipe_add_type(const char *pipeName,
+                      void *pipeOpaque,
+                      const AndroidPipeFuncs *pipeFuncs)
+{
+    PipeServices *list = _pipeServices;
+    int          count = list->count;
+
+    if (count >= MAX_PIPE_SERVICES) {
+        APANIC("Too many goldfish pipe services (%d)", count);
+    }
+
+    if (strlen(pipeName) > MAX_PIPE_SERVICE_NAME_SIZE) {
+        APANIC("Pipe service name too long: '%s'", pipeName);
+    }
+
+    list->services[count].name   = pipeName;
+    list->services[count].opaque = pipeOpaque;
+    list->services[count].funcs  = pipeFuncs[0];
+
+    list->count++;
+}
+
+static const PipeService* android_pipe_find_type(const char *pipeName)
+{
+    PipeServices* list = _pipeServices;
+    int           count = list->count;
+    int           nn;
+
+    for (nn = 0; nn < count; nn++) {
+        if (!strcmp(list->services[nn].name, pipeName)) {
+            return &list->services[nn];
+        }
+    }
+    return NULL;
+}
+
+
+/***********************************************************************
+ ***********************************************************************
+ *****
+ *****    P I P E   C O N N E C T I O N S
+ *****
+ *****/
+
+typedef struct Pipe {
+    struct Pipe                 *next;
+    struct Pipe                 *next_waked;
+    PipeDevice                  *device;
+    uint64_t                    channel; /* opaque kernel handle */
+    void                        *opaque;
+    const AndroidPipeFuncs      *funcs;
+    const PipeService           *service;
+    char*                       args;
+    unsigned char               wanted;
+    char                        closed;
+} Pipe;
+
+/* Forward */
+static void*  pipeConnector_new(Pipe*  pipe);
+
+static Pipe*
+pipe_new0(PipeDevice* dev)
+{
+    Pipe*  pipe;
+    pipe = g_malloc0(sizeof(Pipe));
+    pipe->device = dev;
+    return pipe;
+}
+
+static Pipe*
+pipe_new(uint64_t channel, PipeDevice* dev)
+{
+    Pipe*  pipe = pipe_new0(dev);
+    pipe->channel = channel;
+    pipe->opaque  = pipeConnector_new(pipe);
+    return pipe;
+}
+
+static Pipe**
+pipe_list_findp_channel(Pipe **list, uint64_t channel)
+{
+    Pipe** pnode = list;
+    for (;;) {
+        Pipe* node = *pnode;
+        if (node == NULL || node->channel == channel) {
+            break;
+        }
+        pnode = &node->next;
+    }
+    return pnode;
+}
+
+static Pipe**
+pipe_list_findp_waked(Pipe **list, Pipe *pipe)
+{
+    Pipe** pnode = list;
+    for (;;) {
+        Pipe* node = *pnode;
+        if (node == NULL || node == pipe) {
+            break;
+        }
+        pnode = &node->next_waked;
+    }
+    return pnode;
+}
+
+
+static void pipe_list_remove_waked(Pipe **list, Pipe *pipe)
+{
+    Pipe** lookup = pipe_list_findp_waked(list, pipe);
+    Pipe*  node   = *lookup;
+
+    if (node != NULL) {
+        (*lookup) = node->next_waked;
+        node->next_waked = NULL;
+    }
+}
+
+static void pipe_free(Pipe* pipe)
+{
+    /* Call close callback */
+    if (pipe->funcs->close) {
+        pipe->funcs->close(pipe->opaque);
+    }
+    /* Free stuff */
+    g_free(pipe->args);
+    g_free(pipe);
+}
+
+/***********************************************************************
+ ***********************************************************************
+ *****
+ *****    P I P E   C O N N E C T O R S
+ *****
+ *****/
+
+/* These are used to handle the initial connection attempt, where the
+ * client is going to write the name of the pipe service it wants to
+ * connect to, followed by a terminating zero.
+ */
+typedef struct {
+    Pipe*  pipe;
+    char   buffer[128];
+    int    buffpos;
+} PipeConnector;
+
+static const AndroidPipeFuncs  pipeConnector_funcs;  // forward
+
+void*
+pipeConnector_new(Pipe*  pipe)
+{
+    PipeConnector*  pcon;
+
+    pcon = g_malloc0(sizeof(PipeConnector));
+    pcon->pipe  = pipe;
+    pipe->funcs = &pipeConnector_funcs;
+    return pcon;
+}
+
+static void
+pipeConnector_close( void* opaque )
+{
+    PipeConnector*  pcon = opaque;
+    g_free(pcon);
+}
+
+static int
+pipeConnector_sendBuffers( void* opaque, const AndroidPipeBuffer* buffers, int numBuffers )
+{
+    PipeConnector* pcon = opaque;
+    const AndroidPipeBuffer*  buffers_limit = buffers + numBuffers;
+    int ret = 0;
+
+    DD("%s: channel=0x%llx numBuffers=%d", __FUNCTION__,
+       (unsigned long long)pcon->pipe->channel,
+       numBuffers);
+
+    while (buffers < buffers_limit) {
+        int  avail;
+
+        DD("%s: buffer data (%3zd bytes): '%.*s'", __FUNCTION__,
+           buffers[0].size, (int) buffers[0].size, buffers[0].data);
+
+        if (buffers[0].size == 0) {
+            buffers++;
+            continue;
+        }
+
+        avail = sizeof(pcon->buffer) - pcon->buffpos;
+        if (avail > buffers[0].size)
+            avail = buffers[0].size;
+
+        if (avail > 0) {
+            memcpy(pcon->buffer + pcon->buffpos, buffers[0].data, avail);
+            pcon->buffpos += avail;
+            ret += avail;
+        }
+        buffers++;
+    }
+
+    /* Now check that our buffer contains a zero-terminated string */
+    if (memchr(pcon->buffer, '\0', pcon->buffpos) != NULL) {
+        /* Acceptable formats for the connection string are:
+         *
+         *   pipe:<name>
+         *   pipe:<name>:<arguments>
+         */
+        char* pipeName;
+        char* pipeArgs;
+
+        D("%s: connector: '%s'", __FUNCTION__, pcon->buffer);
+
+        if (memcmp(pcon->buffer, "pipe:", 5) != 0) {
+            /* Nope, we don't handle these for now. */
+            qemu_log_mask(LOG_UNIMP, "%s: Unknown pipe connection: '%s'\n",
+                          __func__, pcon->buffer);
+            return PIPE_ERROR_INVAL;
+        }
+
+        pipeName = pcon->buffer + 5;
+        pipeArgs = strchr(pipeName, ':');
+
+        /* Directly connect qemud:adb pipes to their adb backends without
+         * going through the qemud multiplexer.  All other uses of the ':'
+         * char than an initial "qemud:" will be parsed as arguments to the
+         * pipe name preceeding the colon.
+         */
+        if (pipeArgs && pipeArgs - pipeName == 5
+                && strncmp(pipeName, "qemud", 5) == 0) {
+            pipeArgs = strchr(pipeArgs + 1, ':');
+        }
+
+        if (pipeArgs != NULL) {
+            *pipeArgs++ = '\0';
+            if (!*pipeArgs)
+                pipeArgs = NULL;
+        }
+
+        Pipe* pipe = pcon->pipe;
+        const PipeService* svc = android_pipe_find_type(pipeName);
+        if (svc == NULL) {
+            qemu_log_mask(LOG_UNIMP, "%s: Couldn't find service: '%s'\n",
+                          __func__, pipeName);
+            return PIPE_ERROR_INVAL;
+        }
+
+        void*  peer = svc->funcs.init(pipe, svc->opaque, pipeArgs);
+        if (peer == NULL) {
+            fprintf(stderr,"%s: error initialising pipe:'%s' with args '%s'\n",
+                    __func__, pipeName, pipeArgs);
+            return PIPE_ERROR_INVAL;
+        }
+
+        /* Do the evil switch now */
+        pipe->opaque = peer;
+        pipe->service = svc;
+        pipe->funcs  = &svc->funcs;
+        pipe->args   = g_strdup(pipeArgs);
+        g_free(pcon);
+    }
+
+    return ret;
+}
+
+static int
+pipeConnector_recvBuffers( void* opaque, AndroidPipeBuffer* buffers, int numBuffers )
+{
+    return PIPE_ERROR_IO;
+}
+
+static unsigned
+pipeConnector_poll( void* opaque )
+{
+    return PIPE_POLL_OUT;
+}
+
+static void
+pipeConnector_wakeOn( void* opaque, int flags )
+{
+    /* nothing, really should never happen */
+}
+
+static void
+pipeConnector_save( void* pipe, QEMUFile* file )
+{
+    PipeConnector*  pcon = pipe;
+    qemu_put_sbe32(file, pcon->buffpos);
+    qemu_put_sbuffer(file, (const int8_t*)pcon->buffer, pcon->buffpos);
+}
+
+static void*
+pipeConnector_load( void* hwpipe, void* pipeOpaque, const char* args, QEMUFile* file )
+{
+    PipeConnector*  pcon;
+
+    int len = qemu_get_sbe32(file);
+    if (len < 0 || len > sizeof(pcon->buffer)) {
+        return NULL;
+    }
+    pcon = pipeConnector_new(hwpipe);
+    pcon->buffpos = len;
+    if (qemu_get_buffer(file, (uint8_t*)pcon->buffer, pcon->buffpos) != pcon->buffpos) {
+        g_free(pcon);
+        return NULL;
+    }
+    return pcon;
+}
+
+static const AndroidPipeFuncs  pipeConnector_funcs = {
+    NULL,  /* init */
+    pipeConnector_close,        /* should rarely happen */
+    pipeConnector_sendBuffers,  /* the interesting stuff */
+    pipeConnector_recvBuffers,  /* should not happen */
+    pipeConnector_poll,         /* should not happen */
+    pipeConnector_wakeOn,       /* should not happen */
+    pipeConnector_save,
+    pipeConnector_load,
+};
+
+
+/***********************************************************************
+ ***********************************************************************
+ *****
+ *****    G O L D F I S H   P I P E   D E V I C E
+ *****
+ *****/
+
+struct PipeDevice {
+    AndroidPipeState *ps;       /* FIXME: backlink to instance state */
+
+    /* the list of all pipes */
+    Pipe*  pipes;
+
+    /* the list of signalled pipes */
+    Pipe*  signaled_pipes;
+
+    /* i/o registers */
+    uint64_t  address;
+    uint32_t  size;
+    uint32_t  status;
+    uint64_t  channel;
+    uint32_t  wakes;
+    uint64_t  params_addr;
+};
+
+/* Map the guest buffer specified by the guest vaddr 'address'.
+ * Returns a host pointer which should be unmapped later via
+ * cpu_physical_memory_unmap(), or NULL if mapping failed (likely
+ * because the vaddr doesn't actually point at RAM).
+ * Note that for RAM the "mapping" process doesn't actually involve a
+ * data copy.
+ *
+ * TODO: using cpu_get_phys_page_debug() is a bit bogus, and we could
+ * avoid it if we fixed the driver to do the sane thing and pass us
+ * physical addresses rather than virtual ones.
+ */
+static void *map_guest_buffer(target_ulong address, size_t size, int is_write)
+{
+    hwaddr l = size;
+    void *ptr;
+
+    /* Convert virtual address to physical address */
+    hwaddr phys = cpu_get_phys_page_debug(current_cpu, address);
+
+    if (phys == -1) {
+        return NULL;
+    }
+
+    ptr = cpu_physical_memory_map(phys, &l, is_write);
+    if (!ptr) {
+        /* Can't happen for RAM */
+        return NULL;
+    }
+    if (l != size) {
+        /* This will only happen if the address pointed at non-RAM,
+         * or if the size means the buffer end is beyond the end of
+         * the RAM block.
+         */
+        cpu_physical_memory_unmap(ptr, l, 0, 0);
+        return NULL;
+    }
+
+    return ptr;
+}
+
+static void
+pipeDevice_doCommand( PipeDevice* dev, uint32_t command )
+{
+    Pipe** lookup = pipe_list_findp_channel(&dev->pipes, dev->channel);
+    Pipe*  pipe   = *lookup;
+
+    /* Check that we're referring a known pipe channel */
+    if (command != PIPE_CMD_OPEN && pipe == NULL) {
+        dev->status = PIPE_ERROR_INVAL;
+        return;
+    }
+
+    /* If the pipe is closed by the host, return an error */
+    if (pipe != NULL && pipe->closed && command != PIPE_CMD_CLOSE) {
+        dev->status = PIPE_ERROR_IO;
+        return;
+    }
+
+    switch (command) {
+    case PIPE_CMD_OPEN:
+        DD("%s: CMD_OPEN channel=0x%llx", __FUNCTION__, (unsigned long long)dev->channel);
+        if (pipe != NULL) {
+            dev->status = PIPE_ERROR_INVAL;
+            break;
+        }
+        pipe = pipe_new(dev->channel, dev);
+        pipe->next = dev->pipes;
+        dev->pipes = pipe;
+        dev->status = 0;
+        break;
+
+    case PIPE_CMD_CLOSE:
+        DD("%s: CMD_CLOSE channel=0x%llx", __FUNCTION__, (unsigned long long)dev->channel);
+        /* Remove from device's lists */
+        *lookup = pipe->next;
+        pipe->next = NULL;
+        pipe_list_remove_waked(&dev->signaled_pipes, pipe);
+        pipe_free(pipe);
+        break;
+
+    case PIPE_CMD_POLL:
+        dev->status = pipe->funcs->poll(pipe->opaque);
+        DD("%s: CMD_POLL > status=%d", __FUNCTION__, dev->status);
+        break;
+
+    case PIPE_CMD_READ_BUFFER: {
+        /* Translate virtual address into physical one, into emulator memory. */
+        AndroidPipeBuffer  buffer;
+        buffer.data = map_guest_buffer(dev->address, dev->size, 1);
+        if (!buffer.data) {
+            dev->status = PIPE_ERROR_INVAL;
+            break;
+        }
+        buffer.size = dev->size;
+        dev->status = pipe->funcs->recvBuffers(pipe->opaque, &buffer, 1);
+        DD("%s: CMD_READ_BUFFER channel=0x%llx address=0x%16llx size=%d > status=%d",
+           __FUNCTION__, (unsigned long long)dev->channel, (unsigned long long)dev->address,
+           dev->size, dev->status);
+        cpu_physical_memory_unmap(buffer.data, dev->size, 1, dev->size);
+        break;
+    }
+
+    case PIPE_CMD_WRITE_BUFFER: {
+        /* Translate virtual address into physical one, into emulator memory. */
+        AndroidPipeBuffer  buffer;
+        buffer.data = map_guest_buffer(dev->address, dev->size, 0);
+        if (!buffer.data) {
+            dev->status = PIPE_ERROR_INVAL;
+            break;
+        }
+        buffer.size = dev->size;
+        dev->status = pipe->funcs->sendBuffers(pipe->opaque, &buffer, 1);
+        DD("%s: CMD_WRITE_BUFFER channel=0x%llx address=0x%16llx size=%d > status=%d",
+           __FUNCTION__, (unsigned long long)dev->channel, (unsigned long long)dev->address,
+           dev->size, dev->status);
+        cpu_physical_memory_unmap(buffer.data, dev->size, 0, dev->size);
+        break;
+    }
+
+    case PIPE_CMD_WAKE_ON_READ:
+        DD("%s: CMD_WAKE_ON_READ channel=0x%llx", __FUNCTION__, (unsigned long long)dev->channel);
+        if ((pipe->wanted & PIPE_WAKE_READ) == 0) {
+            pipe->wanted |= PIPE_WAKE_READ;
+            pipe->funcs->wakeOn(pipe->opaque, pipe->wanted);
+        }
+        dev->status = 0;
+        break;
+
+    case PIPE_CMD_WAKE_ON_WRITE:
+        DD("%s: CMD_WAKE_ON_WRITE channel=0x%llx", __FUNCTION__, (unsigned long long)dev->channel);
+        if ((pipe->wanted & PIPE_WAKE_WRITE) == 0) {
+            pipe->wanted |= PIPE_WAKE_WRITE;
+            pipe->funcs->wakeOn(pipe->opaque, pipe->wanted);
+        }
+        dev->status = 0;
+        break;
+
+    default:
+        D("%s: command=%d (0x%x)\n", __FUNCTION__, command, command);
+    }
+}
+
+static void pipe_dev_write(void *opaque, hwaddr offset, uint64_t value, unsigned size)
+{
+    AndroidPipeState *state = (AndroidPipeState *) opaque;
+    PipeDevice *s = state->dev;
+
+    DR("%s: offset = 0x%" HWADDR_PRIx " value=%" PRIu64 "/0x%" PRIx64,
+       __func__, offset, value, value);
+    switch (offset) {
+    case PIPE_REG_COMMAND:
+        pipeDevice_doCommand(s, value);
+        break;
+
+    case PIPE_REG_SIZE:
+        s->size = value;
+        break;
+
+    case PIPE_REG_ADDRESS:
+        uint64_set_low(&s->address, value);
+        break;
+
+    case PIPE_REG_ADDRESS_HIGH:
+        uint64_set_high(&s->address, value);
+        break;
+
+    case PIPE_REG_CHANNEL:
+        uint64_set_low(&s->channel, value);
+        break;
+
+    case PIPE_REG_CHANNEL_HIGH:
+        uint64_set_high(&s->channel, value);
+        break;
+
+    case PIPE_REG_PARAMS_ADDR_HIGH:
+        uint64_set_high(&s->params_addr, value);
+        break;
+
+    case PIPE_REG_PARAMS_ADDR_LOW:
+        uint64_set_low(&s->params_addr, value);
+        break;
+
+    case PIPE_REG_ACCESS_PARAMS:
+    {
+        union access_params aps;
+        uint32_t cmd;
+        bool is_64bit = true;
+
+        /* Don't touch aps.result if anything wrong */
+        if (s->params_addr == 0)
+            break;
+
+        cpu_physical_memory_read(s->params_addr, (void*)&aps, sizeof(aps.aps32));
+
+        /* This auto-detection of 32bit/64bit ness relies on the
+         * currently unused flags parameter. As the 32 bit flags
+         * overlaps with the 64 bit cmd parameter. As cmd != 0 if we
+         * find it as 0 it's 32bit
+         */
+        if (aps.aps32.flags == 0) {
+            is_64bit = false;
+        } else {
+            cpu_physical_memory_read(s->params_addr, (void*)&aps, sizeof(aps.aps64));
+        }
+
+        if (is_64bit) {
+            s->channel = aps.aps64.channel;
+            s->size = aps.aps64.size;
+            s->address = aps.aps64.address;
+            cmd = aps.aps64.cmd;
+        } else {
+            s->channel = aps.aps32.channel;
+            s->size = aps.aps32.size;
+            s->address = aps.aps32.address;
+            cmd = aps.aps32.cmd;
+        }
+
+        if ((cmd != PIPE_CMD_READ_BUFFER) && (cmd != PIPE_CMD_WRITE_BUFFER))
+            break;
+
+        pipeDevice_doCommand(s, cmd);
+
+        if (is_64bit) {
+            aps.aps64.result = s->status;
+            cpu_physical_memory_write(s->params_addr, (void*)&aps, sizeof(aps.aps64));
+        } else {
+            aps.aps32.result = s->status;
+            cpu_physical_memory_write(s->params_addr, (void*)&aps, sizeof(aps.aps32));
+        }
+    }
+    break;
+
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: unknown register offset = 0x%"
+                      HWADDR_PRIx " value=%" PRIu64 "/0x%" PRIx64 "\n",
+                      __func__, offset, value, value);
+        break;
+    }
+}
+
+/* I/O read */
+static uint64_t pipe_dev_read(void *opaque, hwaddr offset, unsigned size)
+{
+    AndroidPipeState *s = (AndroidPipeState *)opaque;
+    PipeDevice *dev = s->dev;
+
+    switch (offset) {
+    case PIPE_REG_STATUS:
+        DR("%s: REG_STATUS status=%d (0x%x)", __FUNCTION__, dev->status, dev->status);
+        return dev->status;
+
+    case PIPE_REG_CHANNEL:
+        if (dev->signaled_pipes != NULL) {
+            Pipe* pipe = dev->signaled_pipes;
+            DR("%s: channel=0x%llx wanted=%d", __FUNCTION__,
+               (unsigned long long)pipe->channel, pipe->wanted);
+            dev->wakes = pipe->wanted;
+            pipe->wanted = 0;
+            dev->signaled_pipes = pipe->next_waked;
+            pipe->next_waked = NULL;
+            if (dev->signaled_pipes == NULL) {
+                /* android_device_set_irq(&dev->dev, 0, 0); */
+                qemu_set_irq(s->irq, 0);
+                DD("%s: lowering IRQ", __FUNCTION__);
+            }
+            return (uint32_t)(pipe->channel & 0xFFFFFFFFUL);
+        }
+        DR("%s: no signaled channels", __FUNCTION__);
+        return 0;
+
+    case PIPE_REG_CHANNEL_HIGH:
+        if (dev->signaled_pipes != NULL) {
+            Pipe* pipe = dev->signaled_pipes;
+            DR("%s: channel_high=0x%llx wanted=%d", __FUNCTION__,
+               (unsigned long long)pipe->channel, pipe->wanted);
+            return (uint32_t)(pipe->channel >> 32);
+        }
+        DR("%s: no signaled channels", __FUNCTION__);
+        return 0;
+
+    case PIPE_REG_WAKES:
+        DR("%s: wakes %d", __FUNCTION__, dev->wakes);
+        return dev->wakes;
+
+    case PIPE_REG_PARAMS_ADDR_HIGH:
+        return (uint32_t)(dev->params_addr >> 32);
+
+    case PIPE_REG_PARAMS_ADDR_LOW:
+        return (uint32_t)(dev->params_addr & 0xFFFFFFFFUL);
+
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: unknown register %" HWADDR_PRId
+                      " (0x%" HWADDR_PRIx ")\n", __FUNCTION__, offset, offset);
+    }
+    return 0;
+}
+
+static const MemoryRegionOps android_pipe_iomem_ops = {
+    .read = pipe_dev_read,
+    .write = pipe_dev_write,
+    .endianness = DEVICE_NATIVE_ENDIAN
+};
+
+static void android_pipe_realize(DeviceState *dev, Error **errp)
+{
+    SysBusDevice *sbdev = SYS_BUS_DEVICE(dev);
+    AndroidPipeState *s = ANDROID_PIPE(dev);
+
+    s->dev = (PipeDevice *) g_malloc0(sizeof(PipeDevice));
+    s->dev->ps = s; /* HACK: backlink */
+
+    memory_region_init_io(&s->iomem, OBJECT(s), &android_pipe_iomem_ops, s,
+                          "android_pipe", 0x1000 /*TODO: ?how big?*/);
+    sysbus_init_mmio(sbdev, &s->iomem);
+    sysbus_init_irq(sbdev, &s->irq);
+
+    android_zero_pipe_init();
+    android_pingpong_init();
+    android_throttle_init();
+    android_sensors_init();
+
+    /* TODO: This may be a complete hack and there may be beautiful QOM ways
+     * to accomplish this.
+     *
+     * Initialize android pipe backends
+     */
+    android_adb_dbg_backend_init();
+
+}
+
+void
+android_pipe_wake( void* hwpipe, unsigned flags )
+{
+    Pipe*  pipe = hwpipe;
+    Pipe** lookup;
+    PipeDevice*  dev = pipe->device;
+
+    DD("%s: channel=0x%llx flags=%d", __FUNCTION__, (unsigned long long)pipe->channel, flags);
+
+    /* If not already there, add to the list of signaled pipes */
+    lookup = pipe_list_findp_waked(&dev->signaled_pipes, pipe);
+    if (!*lookup) {
+        pipe->next_waked = dev->signaled_pipes;
+        dev->signaled_pipes = pipe;
+    }
+    pipe->wanted |= (unsigned)flags;
+
+    /* Raise IRQ to indicate there are items on our list ! */
+    /* android_device_set_irq(&dev->dev, 0, 1);*/
+    qemu_set_irq(dev->ps->irq, 1);
+    DD("%s: raising IRQ", __FUNCTION__);
+}
+
+void
+android_pipe_close( void* hwpipe )
+{
+    Pipe* pipe = hwpipe;
+
+    D("%s: channel=0x%llx (closed=%d)", __FUNCTION__, (unsigned long long)pipe->channel, pipe->closed);
+
+    if (!pipe->closed) {
+        pipe->closed = 1;
+        android_pipe_wake( hwpipe, PIPE_WAKE_CLOSED );
+    }
+}
+
+static void android_pipe_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    dc->realize = android_pipe_realize;
+    dc->desc = "android pipe";
+}
+
+static const TypeInfo android_pipe_info = {
+    .name          = TYPE_ANDROID_PIPE,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(AndroidPipeState),
+    .class_init    = android_pipe_class_init
+};
+
+static void android_pipe_register(void)
+{
+    type_register_static(&android_pipe_info);
+}
+
+type_init(android_pipe_register);
diff --git a/include/hw/misc/android_pipe.h b/include/hw/misc/android_pipe.h
new file mode 100644
index 0000000..9afabc8
--- /dev/null
+++ b/include/hw/misc/android_pipe.h
@@ -0,0 +1,31 @@
+/* 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 _HW_ANDROID_PIPE_H
+#define _HW_ANDROID_PIPE_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "hw/hw.h"
+
+extern bool qemu2_adb_server_init(int port);
+
+#include "android/emulation/android_pipe_device.h"
+#include "android/opengles-pipe.h"
+
+extern void android_zero_pipe_init(void);
+extern void android_pingpong_init(void);
+extern void android_throttle_init(void);
+extern void android_adb_dbg_backend_init(void);
+extern void android_adb_backend_init(void);
+extern void android_sensors_init(void);
+
+#endif /* _HW_ANDROID_PIPE_H */