android: goldfish_pipe: Remove dependency on AndroidEmu.
This patch refactors the virtual device used to implement the
Android pipe channels in the following ways:
- Rename the source files from "android_pipe.c" to
"goldfish_pipe.c". It is consistent with the naming of
other Android-specific devices, and makes it more
explicit that this is a virtual device, not a service
implementation (e.g. like android_adb.c in the same
directory that was used in the past).
- Remove any includes to AndroidEmu from the virtual device
(e.g. "android/emulation/android_pipe_device.h"). Instead
provide a callback-based interface to be implemented by
the host service (GoldfishPipeServiceOps), and injected
into the device through goldfish_pipe_set_service_ops().
This makes the virtual device much easier to rebase in
the future, as well as makes it upstreamable.
- Provide a new header "include/hw/misc/goldfish_pipe.h"
that contains the declaration for the new interface.
Note that this also defines types with the GoldfishPipe
prefix. This increases type-safety and better documents
usage, compared to the liberal use of void* for what
is now GoldfishHwPipe and GoldfishHostPipe.
- Provide glue code (android_pipe_device.cpp) that connects
the implementation of the generic AndroidEmu pipe service
and the QEMU2-specific virtual device, through the new
qemu_android_pipe_init() function.
- Ensure that qemu_android_pipe_init() is properly called
at emulation setup time.
+ Fixed a minor mis-type (uint32 --> uint32_t) to avoid
future compiler warnings (after the 2.7 rebase).
+ Rename pipe_free() to hwpipe_free() for consistency.
NOTE: This should not change the virtual device's
implementation in any way: no bug fix, no new features.
Change-Id: I1caae14330e036b4076abd3883891885e49e1fe6
diff --git a/android-qemu2-glue/build/Makefile.qemu2-glue.mk b/android-qemu2-glue/build/Makefile.qemu2-glue.mk
index e692c27..330fb92 100644
--- a/android-qemu2-glue/build/Makefile.qemu2-glue.mk
+++ b/android-qemu2-glue/build/Makefile.qemu2-glue.mk
@@ -30,6 +30,7 @@
utils/stream.cpp \
base/async/Looper.cpp \
base/files/QemuFileStream.cpp \
+ emulation/android_pipe_device.cpp \
emulation/charpipe.c \
emulation/CharSerialLine.cpp \
emulation/goldfish_sync.cpp \
diff --git a/android-qemu2-glue/build/Makefile.qemu2-target.mk b/android-qemu2-glue/build/Makefile.qemu2-target.mk
index 26e76d0..621c87c 100644
--- a/android-qemu2-glue/build/Makefile.qemu2-target.mk
+++ b/android-qemu2-glue/build/Makefile.qemu2-target.mk
@@ -70,7 +70,7 @@
hw/display/goldfish_fb.c \
hw/input/goldfish_events.c \
hw/intc/goldfish_pic.c \
- hw/misc/android_pipe.c \
+ hw/misc/goldfish_pipe.c \
hw/misc/goldfish_battery.c \
hw/misc/goldfish_sync.c \
hw/timer/goldfish_timer.c \
diff --git a/android-qemu2-glue/emulation/android_pipe_device.cpp b/android-qemu2-glue/emulation/android_pipe_device.cpp
new file mode 100644
index 0000000..744501c
--- /dev/null
+++ b/android-qemu2-glue/emulation/android_pipe_device.cpp
@@ -0,0 +1,174 @@
+/* Copyright 2015 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.
+*/
+#include "android-qemu2-glue/emulation/android_pipe_device.h"
+
+#include "android/base/Compiler.h"
+#include "android/base/Log.h"
+#include "android/emulation/AndroidPipe.h"
+#include "android/emulation/android_pipe_common.h"
+#include "android/emulation/android_pipe_device.h"
+#include "android/emulation/VmLock.h"
+#include "android/utils/stream.h"
+#include "android-qemu2-glue/utils/stream.h"
+
+#include <assert.h>
+#include <memory>
+
+extern "C" {
+#include "hw/misc/goldfish_pipe.h"
+} // extern "C"
+
+// Technical note: This file contains the glue code used between the
+// generic AndroidPipe service implementation, and the QEMU2-specific
+// goldfish_pipe virtual device. More specifically:
+//
+// The host service pipe expects a device implementation that will
+// implement the callbacks in AndroidHwPipeFuncs. These are injected
+// into the service by calling android_pipe_set_hw_funcs().
+//
+// The virtual device expects a service implementation that will
+// implement the callbacks in GoldfishPIpeServiceOps. These are injected
+// into the device through goldfish_pipe_set_service_ops().
+//
+// qemu_android_pipe_init() is used to inject all callbacks at setup time
+// and initialize the threading mode of AndroidPipe (see below).
+//
+namespace {
+
+// Convenience class used to wrap a QEMUFile inside a ::Stream instance
+// which will be usable by the generic AndroidPipe service.
+class ScopedStream {
+public:
+ explicit ScopedStream(QEMUFile* file)
+ : mStream(stream_from_qemufile(file)) {}
+
+ ~ScopedStream() { close(); }
+
+ void close() {
+ if (mStream) {
+ stream_free(mStream);
+ mStream = nullptr;
+ }
+ }
+
+ ::Stream* get() const { return mStream; }
+
+ DISALLOW_COPY_ASSIGN_AND_MOVE(ScopedStream);
+
+private:
+ ::Stream* mStream;
+};
+
+} // namespace
+
+// These callbacks are called from the virtual device into the pipe service.
+static const GoldfishPipeServiceOps goldfish_pipe_service_ops = {
+ // guest_open()
+ [](GoldfishHwPipe* hwPipe) -> GoldfishHostPipe* {
+ return static_cast<GoldfishHostPipe*>(
+ android_pipe_guest_open(hwPipe));
+ },
+ // guest_load()
+ [](QEMUFile* file,
+ GoldfishHwPipe* hwPipe,
+ char* force_close) -> GoldfishHostPipe* {
+ ScopedStream stream(file);
+ return static_cast<GoldfishHostPipe*>(
+ android_pipe_guest_load(stream.get(), hwPipe, force_close));
+
+ },
+ // guest_close()
+ [](GoldfishHostPipe* hostPipe) { android_pipe_guest_close(hostPipe); },
+ // guest_save()
+ [](GoldfishHostPipe* hostPipe, QEMUFile* file) {
+ ScopedStream stream(file);
+ android_pipe_guest_save(hostPipe, stream.get());
+ },
+ // guest_poll()
+ [](GoldfishHostPipe* hostPipe) {
+ static_assert((int)GOLDFISH_PIPE_POLL_IN == (int)PIPE_POLL_IN,
+ "invalid POLL_IN values");
+ static_assert((int)GOLDFISH_PIPE_POLL_OUT == (int)PIPE_POLL_OUT,
+ "invalid POLL_OUT values");
+ static_assert((int)GOLDFISH_PIPE_POLL_HUP == (int)PIPE_POLL_HUP,
+ "invalid POLL_HUP values");
+
+ return static_cast<GoldfishPipePollFlags>(
+ android_pipe_guest_poll(hostPipe));
+ },
+ // guest_recv()
+ [](GoldfishHostPipe* hostPipe,
+ GoldfishPipeBuffer* buffers,
+ int numBuffers) -> int {
+ // NOTE: Assumes that AndroidPipeBuffer and GoldfishPipeBuffer
+ // have exactly the same layout.
+ static_assert(
+ sizeof(AndroidPipeBuffer) == sizeof(GoldfishPipeBuffer),
+ "Invalid PipeBuffer sizes");
+ static_assert(offsetof(AndroidPipeBuffer, data) ==
+ offsetof(GoldfishPipeBuffer, data),
+ "Invalid PipeBuffer::data offsets");
+ static_assert(offsetof(AndroidPipeBuffer, size) ==
+ offsetof(GoldfishPipeBuffer, size),
+ "Invalid PipeBuffer::size offsets");
+ return android_pipe_guest_recv(
+ hostPipe, reinterpret_cast<AndroidPipeBuffer*>(buffers),
+ numBuffers);
+ },
+ // guest_send()
+ [](GoldfishHostPipe* hostPipe,
+ const GoldfishPipeBuffer* buffers,
+ int numBuffers) -> int {
+ return android_pipe_guest_send(
+ hostPipe,
+ reinterpret_cast<const AndroidPipeBuffer*>(buffers),
+ numBuffers);
+ },
+ // guest_wake_on()
+ [](GoldfishHostPipe* hostPipe, GoldfishPipeWakeFlags wakeFlags) {
+ android_pipe_guest_wake_on(hostPipe, static_cast<int>(wakeFlags));
+ },
+};
+
+// These callbacks are called from the pipe service into the virtual device.
+static const AndroidPipeHwFuncs android_pipe_hw_funcs = {
+ // resetPipe()
+ [](void* hwPipe, void* hostPipe) {
+ goldfish_pipe_reset(static_cast<GoldfishHwPipe*>(hwPipe),
+ static_cast<GoldfishHostPipe*>(hostPipe));
+ },
+ // closeFromHost()
+ [](void* hwPipe) {
+ goldfish_pipe_close_from_host(static_cast<GoldfishHwPipe*>(hwPipe));
+ },
+ // signalWake()
+ [](void* hwPipe, unsigned flags) {
+ static_assert(
+ (int)GOLDFISH_PIPE_WAKE_CLOSED == (int)PIPE_WAKE_CLOSED,
+ "Invalid PIPE_WAKE_CLOSED values");
+ static_assert((int)GOLDFISH_PIPE_WAKE_READ == (int)PIPE_WAKE_READ,
+ "Invalid PIPE_WAKE_READ values");
+ static_assert((int)GOLDFISH_PIPE_WAKE_WRITE == (int)PIPE_WAKE_WRITE,
+ "Invalid PIPE_WAKE_WRITE values");
+
+ goldfish_pipe_signal_wake(
+ static_cast<GoldfishHwPipe*>(hwPipe),
+ static_cast<GoldfishPipeWakeFlags>(flags));
+ },
+};
+
+bool qemu_android_pipe_init(android::VmLock* vmLock) {
+ goldfish_pipe_set_service_ops(&goldfish_pipe_service_ops);
+ android_pipe_set_hw_funcs(&android_pipe_hw_funcs);
+ android::AndroidPipe::initThreading(vmLock);
+ return true;
+}
diff --git a/android-qemu2-glue/emulation/android_pipe_device.h b/android-qemu2-glue/emulation/android_pipe_device.h
new file mode 100644
index 0000000..efe0266
--- /dev/null
+++ b/android-qemu2-glue/emulation/android_pipe_device.h
@@ -0,0 +1,18 @@
+/* Copyright 2015 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.
+*/
+#pragma once
+
+#include "android/emulation/VmLock.h"
+
+/* Initialize Android pipe device support. Return true on success, false
+ * otherwise. */
+bool qemu_android_pipe_init(android::VmLock* vmLock);
diff --git a/android-qemu2-glue/qemu-setup.cpp b/android-qemu2-glue/qemu-setup.cpp
index 1130592..0bbdb77 100644
--- a/android-qemu2-glue/qemu-setup.cpp
+++ b/android-qemu2-glue/qemu-setup.cpp
@@ -17,10 +17,10 @@
#include "android/android.h"
#include "android/base/Log.h"
#include "android/console.h"
-#include "android/emulation/AndroidPipe.h"
+#include "android-qemu2-glue/emulation/android_pipe_device.h"
+#include "android-qemu2-glue/emulation/VmLock.h"
#include "android-qemu2-glue/qemu-control-impl.h"
#include "android-qemu2-glue/emulation/goldfish_sync.h"
-#include "android-qemu2-glue/emulation/VmLock.h"
extern "C" {
#include "qemu/main-loop.h"
@@ -43,7 +43,10 @@
VmLock* prevVmLock = VmLock::set(vmLock);
CHECK(prevVmLock == nullptr) << "Another VmLock was already installed!";
- android::AndroidPipe::initThreading(vmLock);
+ // Initialize host pipe service.
+ if (!qemu_android_pipe_init(vmLock)) {
+ return false;
+ }
if (!qemu_android_sync_init(vmLock)) {
return false;
diff --git a/hw/misc/android_pipe.c b/hw/misc/goldfish_pipe.c
similarity index 77%
rename from hw/misc/android_pipe.c
rename to hw/misc/goldfish_pipe.c
index 6be9b73..a1d1bd8 100755
--- a/hw/misc/android_pipe.c
+++ b/hw/misc/goldfish_pipe.c
@@ -19,7 +19,7 @@
** 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.
+** pipes are registered with the goldfish_pipe_add_type() call.
**
** Open Questions
**
@@ -28,8 +28,9 @@
** should give some thought to if this needs re-writing to take
** advantage of that infrastructure to create the pipes.
*/
+#include "hw/misc/goldfish_pipe.h"
+
#include "android-qemu2-glue/utils/stream.h"
-#include "android/emulation/android_pipe_device.h"
#include "hw/hw.h"
#include "hw/sysbus.h"
#include "qemu/error-report.h"
@@ -138,18 +139,55 @@
PIPE_DRIVER_VERSION_v1 = 0, // used to not report its version at all
};
+/* These default callbacks are provided to detect when emulation setup
+ * didn't register a pipe service implementation correctly! There is no
+ * need to provide other GoldfishPipeServiceOps callbacks, since they
+ * cannot be called if one could not open or create a host pipe.
+ *
+ * NOTE: Returning NULL will force-close the pipe as soon as it is
+ * opened by the guest. */
+static GoldfishHostPipe *null_guest_open(GoldfishHwPipe *hw_pipe)
+{
+ E("Android guest tried to open a pipe before service registration!\n"
+ "Please call goldfish_pipe_set_service_ops() at setup time!");
+ (void)hw_pipe;
+ return NULL;
+}
+
+static GoldfishHostPipe *null_guest_load(QEMUFile *file,
+ GoldfishHwPipe *hw_pipe,
+ char *force_close)
+{
+ E("Trying to load a pipe before service registration!\n"
+ "Please call goldfish_pipe_set_service_ops() at setup time!");
+ (void)file;
+ (void)hw_pipe;
+ (void)force_close;
+ return NULL;
+}
+
+static const GoldfishPipeServiceOps s_null_service_ops = {
+ .guest_open = null_guest_open,
+ .guest_load = null_guest_load,
+};
+
+static const GoldfishPipeServiceOps* service_ops = &s_null_service_ops;
+
+void goldfish_pipe_set_service_ops(const GoldfishPipeServiceOps* ops) {
+ service_ops = ops;
+}
+
/* 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) {
+static inline void uint64_set_low(uint64_t* addr, uint32_t value) {
*addr = (*addr & ~(0xFFFFFFFFULL)) | value;
}
-static inline void uint64_set_high(uint64_t* addr, uint32 value) {
+static inline void uint64_set_high(uint64_t* addr, uint32_t value) {
*addr = (*addr & 0xFFFFFFFFULL) | ((uint64_t)value << 32);
}
-typedef struct HwPipe HwPipe;
typedef struct PipeDevice PipeDevice;
struct access_params_32 {
@@ -179,9 +217,9 @@
/* A set of version-specific pipe operations */
typedef struct {
- void (*wanted_list_add)(PipeDevice* dev, HwPipe* pipe);
+ void (*wanted_list_add)(PipeDevice* dev, GoldfishHwPipe* pipe);
void (*close_all)(PipeDevice* dev);
- void (*save)(Stream* stream, PipeDevice* dev);
+ void (*save)(QEMUFile* file, PipeDevice* dev);
void (*dev_write)(PipeDevice* dev, hwaddr offset, uint64_t value);
uint64_t (*dev_read)(PipeDevice* dev, hwaddr offset);
@@ -214,21 +252,24 @@
};
} PipeCommand;
-typedef struct HwPipe {
- struct HwPipe* wanted_next;
- struct HwPipe* wanted_prev;
+struct GoldfishHwPipe {
+ struct GoldfishHwPipe *wanted_next;
+ struct GoldfishHwPipe *wanted_prev;
PipeDevice* dev;
uint32_t id; // pipe ID is its index into the PipeDevice::pipes array
unsigned char wanted;
char closed;
- void* pipe_impl_by_user;
+ GoldfishHostPipe *host_pipe;
uint64_t command_buffer_addr;
PipeCommand* command_buffer;
// v1-specific fields
- struct HwPipe* next;
+ struct GoldfishHwPipe* next;
uint64_t channel; /* opaque kernel handle */
-} HwPipe;
+};
+
+typedef GoldfishHwPipe HwPipe;
+typedef GoldfishHostPipe HostPipe;
typedef struct GuestSignalledPipe {
uint32_t id;
@@ -336,33 +377,35 @@
}
#endif
-static unsigned char get_and_clear_pipe_wanted(HwPipe* pipe) {
+static unsigned char hwpipe_get_and_clear_wanted(HwPipe* pipe) {
unsigned char val = pipe->wanted;
pipe->wanted = 0;
return val;
}
-static void set_pipe_wanted_bits(HwPipe* pipe, unsigned char val) {
+static void hwpipe_set_wanted(HwPipe* pipe, unsigned char val) {
pipe->wanted |= val;
}
-static HwPipe* pipe_new0(PipeDevice* dev) {
+static HwPipe* hwpipe_new0(PipeDevice* dev) {
HwPipe* pipe;
pipe = g_malloc0(sizeof(HwPipe));
pipe->dev = dev;
return pipe;
}
-static HwPipe* pipe_new(uint32_t id, uint64_t channel, PipeDevice* dev) {
- HwPipe* pipe = pipe_new0(dev);
+static HwPipe* hwpipe_new(uint32_t id, uint64_t channel, PipeDevice* dev) {
+ HwPipe* pipe = hwpipe_new0(dev);
pipe->id = id;
pipe->channel = channel;
- pipe->pipe_impl_by_user = android_pipe_guest_open(pipe);
+ pipe->host_pipe = service_ops->guest_open(pipe);
return pipe;
}
-static void pipe_free(HwPipe* pipe) {
- android_pipe_guest_close(pipe->pipe_impl_by_user);
+static void hwpipe_free(HwPipe* pipe) {
+ if (pipe->host_pipe)
+ service_ops->guest_close(pipe->host_pipe);
+
g_free(pipe);
}
@@ -489,7 +532,7 @@
HwPipe* pipe = dev->pipes_list;
while (pipe) {
HwPipe* next = pipe->next;
- pipe_free(pipe);
+ hwpipe_free(pipe);
pipe = next;
}
dev->pipes_list = NULL;
@@ -501,7 +544,7 @@
HwPipe* pipe = dev->pipes[i];
if (pipe) {
unmap_command_buffer(pipe->command_buffer);
- pipe_free(pipe);
+ hwpipe_free(pipe);
dev->pipes[i] = NULL;
}
}
@@ -520,24 +563,30 @@
/* Check that we're referring a known pipe channel */
if (command != PIPE_CMD_OPEN && pipe == NULL) {
- dev->status = PIPE_ERROR_INVAL;
+ dev->status = GOLDFISH_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;
+ dev->status = GOLDFISH_PIPE_ERROR_IO;
return;
}
switch (command) {
case PIPE_CMD_OPEN:
- DD("%s: CMD_OPEN channel=0x%llx", __FUNCTION__, (unsigned long long)dev->channel);
+ DD("%s: CMD_OPEN channel=0x%llx", __func__,
+ (unsigned long long)dev->channel);
if (pipe != NULL) {
- dev->status = PIPE_ERROR_INVAL;
+ dev->status = GOLDFISH_PIPE_ERROR_INVAL;
break;
}
- pipe = pipe_new(0, dev->channel, dev);
+ pipe = hwpipe_new(0, dev->channel, dev);
+ if (!pipe->host_pipe) {
+ hwpipe_free(pipe);
+ dev->status = GOLDFISH_PIPE_ERROR_INVAL;
+ break;
+ }
pipe->next = dev->pipes_list;
dev->pipes_list = pipe;
dev->status = 0;
@@ -546,7 +595,8 @@
break;
case PIPE_CMD_CLOSE: {
- DD("%s: CMD_CLOSE channel=0x%llx", __FUNCTION__, (unsigned long long)dev->channel);
+ DD("%s: CMD_CLOSE channel=0x%llx", __func__,
+ (unsigned long long)dev->channel);
// Remove from device's lists.
// This linear lookup is potentially slow, but we don't delete pipes
// often enough for it to become noticable.
@@ -555,7 +605,7 @@
pnode = &(*pnode)->next;
}
if (!*pnode) {
- dev->status = PIPE_ERROR_INVAL;
+ dev->status = GOLDFISH_PIPE_ERROR_INVAL;
break;
}
*pnode = pipe->next;
@@ -564,27 +614,28 @@
hash_cast_key_from_channel(&pipe->channel));
wanted_pipes_remove_v1(dev, pipe);
- pipe_free(pipe);
+ hwpipe_free(pipe);
break;
}
case PIPE_CMD_POLL:
- dev->status = android_pipe_guest_poll(pipe->pipe_impl_by_user);
- DD("%s: CMD_POLL > status=%d", __FUNCTION__, dev->status);
+ dev->status = service_ops->guest_poll(pipe->host_pipe);
+ DD("%s: CMD_POLL > status=%d", __func__, dev->status);
break;
case PIPE_CMD_READ: {
/* Translate guest physical address into emulator memory. */
- AndroidPipeBuffer buffer;
+ GoldfishPipeBuffer buffer;
buffer.data = map_guest_buffer(dev->address, dev->size, /*is_write*/1);
if (!buffer.data) {
- dev->status = PIPE_ERROR_INVAL;
+ dev->status = GOLDFISH_PIPE_ERROR_INVAL;
break;
}
buffer.size = dev->size;
- dev->status = android_pipe_guest_recv(pipe->pipe_impl_by_user, &buffer, 1);
+ dev->status = service_ops->guest_recv(pipe->host_pipe, &buffer, 1);
DD("%s: CMD_READ channel=0x%llx address=0x%16llx size=%d > status=%d",
- __FUNCTION__, (unsigned long long)dev->channel, (unsigned long long)dev->address,
+ __func__, (unsigned long long)dev->channel,
+ (unsigned long long)dev->address,
dev->size, dev->status);
cpu_physical_memory_unmap(buffer.data, dev->size,
/*is_write*/1, dev->size);
@@ -593,42 +644,44 @@
case PIPE_CMD_WRITE: {
/* Translate guest physical address into emulator memory. */
- AndroidPipeBuffer buffer;
+ GoldfishPipeBuffer buffer;
buffer.data = map_guest_buffer(dev->address, dev->size, /*is_write*/0);
if (!buffer.data) {
- dev->status = PIPE_ERROR_INVAL;
+ dev->status = GOLDFISH_PIPE_ERROR_INVAL;
break;
}
buffer.size = dev->size;
- dev->status = android_pipe_guest_send(pipe->pipe_impl_by_user, &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);
+ dev->status = service_ops->guest_send(pipe->host_pipe, &buffer, 1);
+ DD("%s: CMD_WRITE_BUFFER channel=0x%llx address=0x%16llx size=%d > "
+ "status=%d", __func__, (unsigned long long)dev->channel,
+ (unsigned long long)dev->address, dev->size, dev->status);
cpu_physical_memory_unmap(buffer.data, dev->size,
/*is_write*/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;
- android_pipe_guest_wake_on(pipe->pipe_impl_by_user, pipe->wanted);
+ DD("%s: CMD_WAKE_ON_READ channel=0x%llx", __func__,
+ (unsigned long long)dev->channel);
+ if ((pipe->wanted & GOLDFISH_PIPE_WAKE_READ) == 0) {
+ pipe->wanted |= GOLDFISH_PIPE_WAKE_READ;
+ service_ops->guest_wake_on(pipe->host_pipe, 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;
- android_pipe_guest_wake_on(pipe->pipe_impl_by_user, pipe->wanted);
+ DD("%s: CMD_WAKE_ON_WRITE channel=0x%llx", __func__,
+ (unsigned long long)dev->channel);
+ if ((pipe->wanted & GOLDFISH_PIPE_WAKE_WRITE) == 0) {
+ pipe->wanted |= GOLDFISH_PIPE_WAKE_WRITE;
+ service_ops->guest_wake_on(pipe->host_pipe, pipe->wanted);
}
dev->status = 0;
break;
default:
- D("%s: command=%d (0x%x)\n", __FUNCTION__, command, command);
+ D("%s: command=%d (0x%x)\n", __func__, command, command);
}
}
@@ -641,7 +694,7 @@
return;
}
if (commandBuffer->id != id) {
- commandBuffer->status = PIPE_ERROR_INVAL;
+ commandBuffer->status = GOLDFISH_PIPE_ERROR_INVAL;
unmap_command_buffer(commandBuffer);
return;
}
@@ -652,7 +705,7 @@
return;
}
if (commandBuffer->cmd != PIPE_CMD_OPEN) {
- commandBuffer->status = PIPE_ERROR_INVAL;
+ commandBuffer->status = GOLDFISH_PIPE_ERROR_INVAL;
unmap_command_buffer(commandBuffer);
return;
}
@@ -662,7 +715,7 @@
: 2 * dev->pipes_capacity;
HwPipe** pipes = calloc(newCapacity, sizeof(HwPipe*));
if (!pipes) {
- commandBuffer->status = PIPE_ERROR_NOMEM;
+ commandBuffer->status = GOLDFISH_PIPE_ERROR_NOMEM;
unmap_command_buffer(commandBuffer);
return;
}
@@ -671,10 +724,10 @@
dev->pipes_capacity = newCapacity;
}
- HwPipe* pipe = pipe_new(id, 0, dev);
- if (!pipe || !pipe->pipe_impl_by_user) {
- free(pipe);
- commandBuffer->status = PIPE_ERROR_NOMEM;
+ HwPipe* pipe = hwpipe_new(id, 0, dev);
+ if (!pipe || !pipe->host_pipe) {
+ hwpipe_free(pipe);
+ commandBuffer->status = GOLDFISH_PIPE_ERROR_NOMEM;
unmap_command_buffer(commandBuffer);
return;
}
@@ -694,7 +747,7 @@
/* If the pipe is closed by the host, return an error */
if (pipe->closed && command != PIPE_CMD_CLOSE) {
- pipe->command_buffer->status = PIPE_ERROR_IO;
+ pipe->command_buffer->status = GOLDFISH_PIPE_ERROR_IO;
return;
}
@@ -706,12 +759,13 @@
wanted_pipes_remove_v2(dev, pipe);
pipe->command_buffer->status = 0;
unmap_command_buffer(pipe->command_buffer);
- pipe_free(pipe);
+ hwpipe_free(pipe);
break;
}
case PIPE_CMD_POLL:
- pipe->command_buffer->status = android_pipe_guest_poll(pipe->pipe_impl_by_user);
+ pipe->command_buffer->status =
+ service_ops->guest_poll(pipe->host_pipe);
DD("%s: CMD_POLL > status=%d", __func__,
pipe->command_buffer->status);
break;
@@ -726,7 +780,7 @@
buffers_count = MAX_BUFFERS_COUNT;
}
- AndroidPipeBuffer buffers[MAX_BUFFERS_COUNT];
+ GoldfishPipeBuffer buffers[MAX_BUFFERS_COUNT];
unsigned i;
for (i = 0; i < buffers_count; ++i) {
buffers[i].size = pipe->command_buffer->rw_params.sizes[i];
@@ -735,17 +789,19 @@
pipe->command_buffer->rw_params.sizes[i],
willModifyData);
if (!buffers[i].data) {
- pipe->command_buffer->status = PIPE_ERROR_INVAL;
+ pipe->command_buffer->status = GOLDFISH_PIPE_ERROR_INVAL;
goto done;
}
}
pipe->command_buffer->status =
willModifyData
- ? android_pipe_guest_recv(pipe->pipe_impl_by_user, buffers,
- buffers_count)
- : android_pipe_guest_send(pipe->pipe_impl_by_user, buffers,
- buffers_count);
+ ? service_ops->guest_recv(pipe->host_pipe,
+ buffers,
+ buffers_count)
+ : service_ops->guest_send(pipe->host_pipe,
+ buffers,
+ buffers_count);
// TODO(zyy): create an extended version of send()/recv() functions
// to
// return both transferred size and resulting status in single
@@ -772,12 +828,13 @@
case PIPE_CMD_WAKE_ON_READ:
case PIPE_CMD_WAKE_ON_WRITE: {
bool read = (command == PIPE_CMD_WAKE_ON_READ);
+ int wake_flags = read
+ ? GOLDFISH_PIPE_WAKE_READ : GOLDFISH_PIPE_WAKE_WRITE;
DD("%s: CMD_WAKE_ON_%s id=%d", __func__, (read ? "READ" : "WRITE"),
(int)pipe->id);
- if ((pipe->wanted & (read ? PIPE_WAKE_READ : PIPE_WAKE_WRITE)) ==
- 0) {
- pipe->wanted |= (read ? PIPE_WAKE_READ : PIPE_WAKE_WRITE);
- android_pipe_guest_wake_on(pipe->pipe_impl_by_user, pipe->wanted);
+ if ((pipe->wanted & wake_flags) == 0) {
+ pipe->wanted |= wake_flags;
+ service_ops->guest_wake_on(pipe->host_pipe, pipe->wanted);
}
pipe->command_buffer->status = 0;
break;
@@ -974,19 +1031,19 @@
{
switch (offset) {
case PIPE_REG_STATUS:
- DR("%s: REG_STATUS status=%d (0x%x)", __FUNCTION__, dev->status, dev->status);
+ DR("%s: REG_STATUS status=%d (0x%x)", __func__, dev->status, dev->status);
return dev->status;
case PIPE_REG_CHANNEL: {
HwPipe* wanted_pipe = wanted_pipes_pop_first_v1(dev);
if (wanted_pipe != NULL) {
- dev->wakes = get_and_clear_pipe_wanted(wanted_pipe);
- DR("%s: channel=0x%llx wanted=%d", __FUNCTION__,
+ dev->wakes = hwpipe_get_and_clear_wanted(wanted_pipe);
+ DR("%s: channel=0x%llx wanted=%d", __func__,
(unsigned long long)wanted_pipe->channel, dev->wakes);
return (uint32_t)(wanted_pipe->channel & 0xFFFFFFFFUL);
} else {
qemu_set_irq(dev->ps->irq, 0);
- DD("%s: no signaled channels, lowering IRQ", __FUNCTION__);
+ DD("%s: no signaled channels, lowering IRQ", __func__);
return 0;
}
}
@@ -1000,7 +1057,7 @@
HwPipe* wanted_pipe = wanted_pipes_pop_first_v1(dev);
if (wanted_pipe != NULL) {
dev->wanted_pipe_after_channel_high = wanted_pipe;
- DR("%s: channel_high=0x%llx wanted=%d", __FUNCTION__,
+ DR("%s: channel_high=0x%llx wanted=%d", __func__,
(unsigned long long)wanted_pipe->channel, wanted_pipe->wanted);
assert((uint32_t)(wanted_pipe->channel >> 32) != 0);
return (uint32_t)(wanted_pipe->channel >> 32);
@@ -1012,7 +1069,7 @@
}
case PIPE_REG_WAKES:
- DR("%s: wakes %d", __FUNCTION__, dev->wakes);
+ DR("%s: wakes %d", __func__, dev->wakes);
return dev->wakes;
case PIPE_REG_PARAMS_ADDR_HIGH:
@@ -1023,7 +1080,7 @@
default:
qemu_log_mask(LOG_GUEST_ERROR, "%s: unknown register %" HWADDR_PRId
- " (0x%" HWADDR_PRIx ")\n", __FUNCTION__, offset, offset);
+ " (0x%" HWADDR_PRIx ")\n", __func__, offset, offset);
}
return 0;
}
@@ -1037,7 +1094,7 @@
(pipe = wanted_pipes_pop_first_v2(dev)) != NULL) {
dev->signalled_pipe_buffer[count].id = pipe->id;
dev->signalled_pipe_buffer[count].flags =
- get_and_clear_pipe_wanted(pipe);
+ hwpipe_get_and_clear_wanted(pipe);
++count;
}
if (!dev->wanted_pipes_first) {
@@ -1053,48 +1110,36 @@
return 0;
}
-static const MemoryRegionOps android_pipe_iomem_ops = {
+static const MemoryRegionOps goldfish_pipe_iomem_ops = {
.read = pipe_dev_read,
.write = pipe_dev_write,
.endianness = DEVICE_NATIVE_ENDIAN
};
-static void qemu2_android_pipe_reset(void* hwpipe, void* internal_pipe);
-static void qemu2_android_pipe_host_signal_wake(void* hwpipe, unsigned flags);
-static void qemu2_android_pipe_host_close(void* hwpipe);
-
-static const AndroidPipeHwFuncs qemu2_android_pipe_hw_funcs = {
- .resetPipe = qemu2_android_pipe_reset,
- .closeFromHost = qemu2_android_pipe_host_close,
- .signalWake = qemu2_android_pipe_host_signal_wake,
-};
-
// Don't change this version unless you want to break forward compatibility.
// Instead, use the different device version as a first saved field.
enum {
- ANDROID_PIPE_SAVE_VERSION = 1,
+ GOLDFISH_PIPE_SAVE_VERSION = 1,
};
-static void android_pipe_save(QEMUFile* f, void* opaque) {
+static void goldfish_pipe_save(QEMUFile* f, void* opaque) {
AndroidPipeState* s = opaque;
PipeDevice* dev = s->dev;
- Stream* stream = stream_from_qemufile(f);
- dev->ops->save(stream, dev);
- stream_free(stream);
+ dev->ops->save(f, dev);
}
-static void android_pipe_save_v1(Stream* stream, PipeDevice* dev) {
+static void goldfish_pipe_save_v1(QEMUFile* file, PipeDevice* dev) {
assert(dev->device_version == PIPE_DEVICE_VERSION_v1);
- stream_put_be32(stream, dev->device_version);
+ qemu_put_be32(file, dev->device_version);
/* Save the device version */
/* Save i/o registers. */
- stream_put_be64(stream, dev->address);
- stream_put_be32(stream, dev->size);
- stream_put_be32(stream, dev->status);
- stream_put_be64(stream, dev->channel);
- stream_put_be32(stream, dev->wakes);
- stream_put_be64(stream, dev->params_addr);
+ qemu_put_be64(file, dev->address);
+ qemu_put_be32(file, dev->size);
+ qemu_put_be32(file, dev->status);
+ qemu_put_be64(file, dev->channel);
+ qemu_put_be32(file, dev->wakes);
+ qemu_put_be64(file, dev->params_addr);
/* Save the pipe count and state of the pipes. */
int pipe_count = 0;
@@ -1102,12 +1147,12 @@
for (pipe = dev->pipes_list; pipe; pipe = pipe->next) {
++pipe_count;
}
- stream_put_be32(stream, pipe_count);
+ qemu_put_be32(file, pipe_count);
for (pipe = dev->pipes_list; pipe; pipe = pipe->next) {
- stream_put_be64(stream, pipe->channel);
- stream_put_byte(stream, pipe->closed);
- stream_put_byte(stream, pipe->wanted);
- android_pipe_guest_save(pipe->pipe_impl_by_user, stream);
+ qemu_put_be64(file, pipe->channel);
+ qemu_put_byte(file, pipe->closed);
+ qemu_put_byte(file, pipe->wanted);
+ service_ops->guest_save(pipe->host_pipe, file);
}
/* Save wanted pipes list. */
@@ -1115,28 +1160,28 @@
for (pipe = dev->wanted_pipes_first; pipe; pipe = pipe->wanted_next) {
wanted_pipes_count++;
}
- stream_put_be32(stream, wanted_pipes_count);
+ qemu_put_be32(file, wanted_pipes_count);
for (pipe = dev->wanted_pipes_first; pipe; pipe = pipe->wanted_next) {
- stream_put_be64(stream, pipe->channel);
+ qemu_put_be64(file, pipe->channel);
}
if (dev->wanted_pipe_after_channel_high) {
- stream_put_byte(stream, 1);
- stream_put_be64(stream, dev->wanted_pipe_after_channel_high->channel);
+ qemu_put_byte(file, 1);
+ qemu_put_be64(file, dev->wanted_pipe_after_channel_high->channel);
} else {
- stream_put_byte(stream, 0);
+ qemu_put_byte(file, 0);
}
}
-static void android_pipe_save_v2(Stream* stream, PipeDevice* dev) {
+static void goldfish_pipe_save_v2(QEMUFile* file, PipeDevice* dev) {
assert(dev->device_version == PIPE_DEVICE_VERSION);
- stream_put_be32(stream, dev->device_version);
+ qemu_put_be32(file, dev->device_version);
/* Save the device data. */
- stream_put_be32(stream, dev->driver_version);
- stream_put_be32(stream, dev->signalled_pipe_buffer_size);
- stream_put_be64(stream, dev->signalled_pipe_buffer_addr);
- stream_put_be64(stream, dev->open_command_addr);
- stream_put_be32(stream, dev->pipes_capacity);
+ qemu_put_be32(file, dev->driver_version);
+ qemu_put_be32(file, dev->signalled_pipe_buffer_size);
+ qemu_put_be64(file, dev->signalled_pipe_buffer_addr);
+ qemu_put_be64(file, dev->open_command_addr);
+ qemu_put_be32(file, dev->pipes_capacity);
/* Save the pipes. */
int i;
@@ -1146,18 +1191,18 @@
++pipe_count;
}
}
- stream_put_be32(stream, pipe_count);
+ qemu_put_be32(file, pipe_count);
for (i = 0; i < dev->pipes_capacity; ++i) {
HwPipe* pipe = dev->pipes[i];
if (!pipe) {
continue;
}
- stream_put_be32(stream, pipe->id);
- stream_put_be64(stream, pipe->command_buffer_addr);
- stream_put_byte(stream, pipe->closed);
- stream_put_byte(stream, pipe->wanted);
- android_pipe_guest_save(pipe->pipe_impl_by_user, stream);
+ qemu_put_be32(file, pipe->id);
+ qemu_put_be64(file, pipe->command_buffer_addr);
+ qemu_put_byte(file, pipe->closed);
+ qemu_put_byte(file, pipe->wanted);
+ service_ops->guest_save(pipe->host_pipe, file);
}
/* Save wanted pipes list. */
@@ -1166,55 +1211,55 @@
for (pipe = dev->wanted_pipes_first; pipe; pipe = pipe->wanted_next) {
wanted_pipes_count++;
}
- stream_put_be32(stream, wanted_pipes_count);
+ qemu_put_be32(file, wanted_pipes_count);
for (pipe = dev->wanted_pipes_first; pipe; pipe = pipe->wanted_next) {
- stream_put_be32(stream, pipe->id);
+ qemu_put_be32(file, pipe->id);
}
}
-static int android_pipe_load_v1(Stream* stream, PipeDevice* dev) {
+static int goldfish_pipe_load_v1(QEMUFile* file, PipeDevice* dev) {
HwPipe* pipe;
assert(dev->device_version == PIPE_DEVICE_VERSION_v1);
dev->driver_version = PIPE_DRIVER_VERSION_v1;
/* Load i/o registers. */
- dev->address = stream_get_be64(stream);
- dev->size = stream_get_be32(stream);
- dev->status = stream_get_be32(stream);
- dev->channel = stream_get_be64(stream);
- dev->wakes = stream_get_be32(stream);
- dev->params_addr = stream_get_be64(stream);
+ dev->address = qemu_get_be64(file);
+ dev->size = qemu_get_be32(file);
+ dev->status = qemu_get_be32(file);
+ dev->channel = qemu_get_be64(file);
+ dev->wakes = qemu_get_be32(file);
+ dev->params_addr = qemu_get_be64(file);
/* Clean up old pipe objects. */
dev->ops->close_all(dev);
dev->ops = &pipe_ops_v1;
/* Restore pipes. */
- int pipe_count = stream_get_be32(stream);
+ int pipe_count = qemu_get_be32(file);
int pipe_n;
HwPipe** pipe_list_end = &dev->pipes_list;
*pipe_list_end = NULL;
uint64_t* force_closed_pipes = malloc(sizeof(uint64_t) * pipe_count);
int force_closed_pipes_count = 0;
for (pipe_n = 0; pipe_n < pipe_count; pipe_n++) {
- HwPipe* pipe = pipe_new0(dev);
+ HwPipe* pipe = hwpipe_new0(dev);
char force_close = 0;
- pipe->channel = stream_get_be64(stream);
- pipe->closed = stream_get_byte(stream);
- pipe->wanted = stream_get_byte(stream);
- pipe->pipe_impl_by_user = android_pipe_guest_load(stream, pipe, &force_close);
+ pipe->channel = qemu_get_be64(file);
+ pipe->closed = qemu_get_byte(file);
+ pipe->wanted = qemu_get_byte(file);
+ pipe->host_pipe = service_ops->guest_load(file, pipe, &force_close);
pipe->wanted_next = pipe->wanted_prev = NULL;
// |pipe| might be NULL in case it couldn't be saved. However,
- // in that case |force_close| will be set by android_pipe_guest_load,
+ // in that case |force_close| will be set by goldfish_pipe_guest_load,
// so |force_close| should be checked first so that the function
// can continue.
if (force_close) {
pipe->closed = 1;
force_closed_pipes[force_closed_pipes_count++] = pipe->channel;
- } else if (!pipe->pipe_impl_by_user) {
- pipe_free(pipe);
+ } else if (!pipe->host_pipe) {
+ hwpipe_free(pipe);
free(force_closed_pipes);
return -EIO;
}
@@ -1235,10 +1280,10 @@
/* Reconstruct wanted pipes list. */
HwPipe** wanted_pipe_list_end = &dev->wanted_pipes_first;
*wanted_pipe_list_end = NULL;
- int wanted_pipes_count = stream_get_be32(stream);
+ int wanted_pipes_count = qemu_get_be32(file);
uint64_t channel;
for (pipe_n = 0; pipe_n < wanted_pipes_count; ++pipe_n) {
- channel = stream_get_be64(stream);
+ channel = qemu_get_be64(file);
HwPipe* pipe = g_hash_table_lookup(dev->pipes_by_channel,
hash_cast_key_from_channel(&channel));
if (pipe) {
@@ -1251,8 +1296,8 @@
return -EIO;
}
}
- if (stream_get_byte(stream)) {
- channel = stream_get_be64(stream);
+ if (qemu_get_byte(file)) {
+ channel = qemu_get_be64(file);
dev->wanted_pipe_after_channel_high =
g_hash_table_lookup(dev->pipes_by_channel,
hash_cast_key_from_channel(&channel));
@@ -1270,7 +1315,7 @@
g_hash_table_lookup(dev->pipes_by_channel,
hash_cast_key_from_channel(
&force_closed_pipes[pipe_n]));
- set_pipe_wanted_bits(pipe, PIPE_WAKE_CLOSED);
+ hwpipe_set_wanted(pipe, GOLDFISH_PIPE_WAKE_CLOSED);
pipe->closed = 1;
if (!pipe->wanted_next &&
!pipe->wanted_prev &&
@@ -1285,26 +1330,26 @@
return 0;
}
-static int android_pipe_load_v2(Stream* stream, PipeDevice* dev) {
+static int goldfish_pipe_load_v2(QEMUFile* file, PipeDevice* dev) {
int res = -EIO;
uint32_t* force_closed_pipes = NULL;
/* Load the device. */
- dev->device_version = stream_get_be32(stream);
+ dev->device_version = qemu_get_be32(file);
if (dev->device_version > PIPE_DEVICE_VERSION) {
goto done;
} else if (dev->device_version == PIPE_DEVICE_VERSION_v1) {
// redirect to the v1 loader if this is an old pipe.
- return android_pipe_load_v1(stream, dev);
+ return goldfish_pipe_load_v1(file, dev);
}
- dev->driver_version = stream_get_be32(stream);
+ dev->driver_version = qemu_get_be32(file);
if (dev->driver_version > MAX_SUPPORTED_DRIVER_VERSION) {
goto done;
}
- dev->signalled_pipe_buffer_size = stream_get_be32(stream);
- dev->signalled_pipe_buffer_addr = stream_get_be64(stream);
+ dev->signalled_pipe_buffer_size = qemu_get_be32(file);
+ dev->signalled_pipe_buffer_addr = qemu_get_be64(file);
dev->signalled_pipe_buffer = (GuestSignalledPipe*)map_guest_buffer(
dev->signalled_pipe_buffer_addr,
sizeof(*dev->signalled_pipe_buffer) *
@@ -1313,7 +1358,7 @@
if (!dev->signalled_pipe_buffer) {
goto done;
}
- dev->open_command_addr = stream_get_be64(stream);
+ dev->open_command_addr = qemu_get_be64(file);
dev->open_command = (OpenCommandParams*)map_guest_buffer(
dev->open_command_addr, sizeof(*dev->open_command), /*is_write*/0);
if (!dev->open_command) {
@@ -1325,7 +1370,7 @@
dev->ops->close_all(dev);
dev->ops = &pipe_ops_v2;
- int pipes_capacity = stream_get_be32(stream);
+ int pipes_capacity = qemu_get_be32(file);
if (dev->pipes_capacity < pipes_capacity) {
void* pipes = calloc(pipes_capacity, sizeof(*dev->pipes));
if (!pipes) {
@@ -1337,7 +1382,7 @@
}
dev->pipes_capacity = pipes_capacity;
- int pipe_count = stream_get_be32(stream);
+ int pipe_count = qemu_get_be32(file);
force_closed_pipes = malloc(sizeof(*force_closed_pipes) * pipe_count);
if (!force_closed_pipes) {
goto done;
@@ -1345,46 +1390,46 @@
int i;
int force_closed_pipes_count = 0;
for (i = 0; i < pipe_count; ++i) {
- HwPipe* pipe = pipe_new0(dev);
- pipe->id = stream_get_be32(stream);
- pipe->command_buffer_addr = stream_get_be64(stream);
+ HwPipe* pipe = hwpipe_new0(dev);
+ pipe->id = qemu_get_be32(file);
+ pipe->command_buffer_addr = qemu_get_be64(file);
pipe->command_buffer = (PipeCommand*)map_guest_buffer(
pipe->command_buffer_addr, COMMAND_BUFFER_SIZE, /*is_write*/1);
if (!pipe->command_buffer) {
- pipe_free(pipe);
+ hwpipe_free(pipe);
goto done;
}
- pipe->closed = stream_get_byte(stream);
- pipe->wanted = stream_get_byte(stream);
+ pipe->closed = qemu_get_byte(file);
+ pipe->wanted = qemu_get_byte(file);
char force_close = 0;
- pipe->pipe_impl_by_user = android_pipe_guest_load(stream, pipe, &force_close);
+ pipe->host_pipe = service_ops->guest_load(file, pipe, &force_close);
// |pipe| might be NULL in case it couldn't be saved. However,
- // in that case |force_close| will be set by android_pipe_guest_load,
+ // in that case |force_close| will be set by goldfish_pipe_guest_load,
// so |force_close| should be checked first so that the function
// can continue.
if (force_close) {
pipe->closed = 1;
force_closed_pipes[force_closed_pipes_count++] = pipe->id;
- } else if (!pipe->pipe_impl_by_user) {
+ } else if (!pipe->host_pipe) {
unmap_command_buffer(pipe->command_buffer);
- pipe_free(pipe);
+ hwpipe_free(pipe);
goto done;
}
if (dev->pipes[pipe->id]) {
unmap_command_buffer(pipe->command_buffer);
- pipe_free(pipe);
+ hwpipe_free(pipe);
goto done;
}
dev->pipes[pipe->id] = pipe;
}
/* Reconstruct wanted pipes list. */
- int wanted_pipes_count = stream_get_be32(stream);
+ int wanted_pipes_count = qemu_get_be32(file);
for (i = 0; i < wanted_pipes_count; ++i) {
- int id = stream_get_be32(stream);
+ int id = qemu_get_be32(file);
HwPipe* pipe = dev->pipes[id];
if (!pipe) {
goto done;
@@ -1395,7 +1440,7 @@
/* Add forcibly closed pipes to wanted pipes list */
for (i = 0; i < force_closed_pipes_count; ++i) {
HwPipe* pipe = dev->pipes[force_closed_pipes[i]];
- set_pipe_wanted_bits(pipe, PIPE_WAKE_CLOSED);
+ hwpipe_set_wanted(pipe, GOLDFISH_PIPE_WAKE_CLOSED);
pipe->closed = 1;
wanted_pipes_add_v2(dev, pipe);
}
@@ -1407,16 +1452,14 @@
return res;
}
-static int android_pipe_load(QEMUFile* f, void* opaque, int version_id) {
+static int goldfish_pipe_load(QEMUFile* f, void* opaque, int version_id) {
AndroidPipeState* s = opaque;
PipeDevice* dev = s->dev;
- Stream* stream = stream_from_qemufile(f);
- int res = android_pipe_load_v2(stream, dev);
- stream_free(stream);
+ int res = goldfish_pipe_load_v2(f, dev);
return res;
}
-static void android_pipe_post_load(void* opaque) {
+static void goldfish_pipe_post_load(void* opaque) {
/* This function gets invoked after all VM state has
* been loaded. Raising IRQ in the load handler causes
* problems.
@@ -1429,7 +1472,7 @@
}
}
-static void android_pipe_realize(DeviceState* dev, Error** errp) {
+static void goldfish_pipe_realize(DeviceState* dev, Error** errp) {
SysBusDevice* sbdev = SYS_BUS_DEVICE(dev);
AndroidPipeState* s = ANDROID_PIPE(dev);
@@ -1452,31 +1495,29 @@
APANIC("%s: failed to initialize pipes hash\n", __func__);
}
- memory_region_init_io(&s->iomem, OBJECT(s), &android_pipe_iomem_ops, s,
- "android_pipe", 0x2000 /*TODO: ?how big?*/);
+ memory_region_init_io(&s->iomem, OBJECT(s), &goldfish_pipe_iomem_ops, s,
+ "goldfish_pipe", 0x2000 /*TODO: ?how big?*/);
sysbus_init_mmio(sbdev, &s->iomem);
sysbus_init_irq(sbdev, &s->irq);
- android_pipe_set_hw_funcs(&qemu2_android_pipe_hw_funcs);
-
+ /* NOTE: "android_pipe" is the legacy name used in snapshots. */
register_savevm_with_post_load(
- dev, "android_pipe", 0, ANDROID_PIPE_SAVE_VERSION,
- android_pipe_save, android_pipe_load, android_pipe_post_load, s);
+ dev, "android_pipe", 0, GOLDFISH_PIPE_SAVE_VERSION,
+ goldfish_pipe_save, goldfish_pipe_load, goldfish_pipe_post_load, s);
}
-static void qemu2_android_pipe_reset(void* hwpipe, void* internal_pipe) {
- HwPipe* pipe = hwpipe;
- pipe->pipe_impl_by_user = internal_pipe;
+void goldfish_pipe_reset(GoldfishHwPipe *pipe, GoldfishHostPipe *host_pipe) {
+ pipe->host_pipe = host_pipe;
}
-static void qemu2_android_pipe_host_signal_wake(void* hwpipe, unsigned flags) {
- HwPipe* pipe = hwpipe;
- PipeDevice* dev = pipe->dev;
+void goldfish_pipe_signal_wake(GoldfishHwPipe *pipe,
+ GoldfishPipeWakeFlags flags) {
+ PipeDevice *dev = pipe->dev;
- DD("%s: id=%d channel=0x%llx flags=%d", __func__,
- (int)pipe->id, pipe->channel, flags);
+ DD("%s: id=%d channel=0x%llx flags=%d", __func__, (int)pipe->id,
+ pipe->channel, flags);
- set_pipe_wanted_bits(pipe, (unsigned char)flags);
+ hwpipe_set_wanted(pipe, (unsigned char)flags);
dev->ops->wanted_list_add(dev, pipe);
/* Raise IRQ to indicate there are items on our list ! */
@@ -1484,40 +1525,39 @@
DD("%s: raising IRQ", __func__);
}
-static void qemu2_android_pipe_host_close(void* hwpipe) {
- HwPipe* pipe = hwpipe;
-
+void goldfish_pipe_close_from_host(GoldfishHwPipe *pipe)
+{
D("%s: id=%d channel=0x%llx (closed=%d)", __func__, (int)pipe->id,
pipe->channel, pipe->closed);
if (!pipe->closed) {
pipe->closed = 1;
- qemu2_android_pipe_host_signal_wake(hwpipe, PIPE_WAKE_CLOSED);
+ goldfish_pipe_signal_wake(pipe, GOLDFISH_PIPE_WAKE_CLOSED);
}
}
-static void android_pipe_class_init(ObjectClass* klass, void* data) {
+static void goldfish_pipe_class_init(ObjectClass* klass, void* data) {
DeviceClass* dc = DEVICE_CLASS(klass);
- dc->realize = android_pipe_realize;
+ dc->realize = goldfish_pipe_realize;
dc->desc = "android pipe";
}
-static const TypeInfo android_pipe_info = {
+static const TypeInfo goldfish_pipe_info = {
.name = TYPE_ANDROID_PIPE,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(AndroidPipeState),
- .class_init = android_pipe_class_init};
+ .class_init = goldfish_pipe_class_init};
-static void android_pipe_register(void) {
- type_register_static(&android_pipe_info);
+static void goldfish_pipe_register(void) {
+ type_register_static(&goldfish_pipe_info);
}
-type_init(android_pipe_register);
+type_init(goldfish_pipe_register);
static const PipeOperations pipe_ops_v2 = {
.wanted_list_add = &wanted_pipes_add_v2,
.close_all = &close_all_pipes_v2,
- .save = &android_pipe_save_v2,
+ .save = &goldfish_pipe_save_v2,
.dev_read = &pipe_dev_read_v2,
.dev_write = &pipe_dev_write_v2
};
@@ -1525,7 +1565,7 @@
static const PipeOperations pipe_ops_v1 = {
.wanted_list_add = &wanted_pipes_add_v1,
.close_all = &close_all_pipes_v1,
- .save = &android_pipe_save_v1,
+ .save = &goldfish_pipe_save_v1,
.dev_read = &pipe_dev_read_v1,
.dev_write = &pipe_dev_write_v1
};
diff --git a/include/hw/misc/goldfish_pipe.h b/include/hw/misc/goldfish_pipe.h
new file mode 100644
index 0000000..219ddd6
--- /dev/null
+++ b/include/hw/misc/goldfish_pipe.h
@@ -0,0 +1,147 @@
+/* Copyright (C) 2016 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_GOLDFISH_PIPE_H
+#define _HW_GOLDFISH_PIPE_H
+
+#include "qemu/typedefs.h"
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+/* The Android pipe virtual device expects an implementation of
+ * pipe services to be provided according to the following interface
+ */
+typedef struct GoldfishPipeBuffer {
+ void* data;
+ size_t size;
+} GoldfishPipeBuffer;
+
+/* List of bitflags returned by guest_poll() */
+typedef enum {
+ GOLDFISH_PIPE_POLL_IN = (1 << 0), /* means guest can read */
+ GOLDFISH_PIPE_POLL_OUT = (1 << 1), /* means guest can write */
+ GOLDFISH_PIPE_POLL_HUP = (1 << 2), /* means closed by host */
+} GoldfishPipePollFlags;
+
+/* List of bitflags used to call goldfish_pipe_signal_wake() and
+ * guest_wake_on() */
+typedef enum {
+ GOLDFISH_PIPE_WAKE_CLOSED = (1 << 0), /* emulator closed the pipe */
+ GOLDFISH_PIPE_WAKE_READ = (1 << 1), /* pipe can now be read from */
+ GOLDFISH_PIPE_WAKE_WRITE = (1 << 2), /* pipe can now be written to */
+} GoldfishPipeWakeFlags;
+
+/* List of error values possibly returned by guest_recv() and
+ * guest_send(). */
+typedef enum {
+ GOLDFISH_PIPE_ERROR_INVAL = -1,
+ GOLDFISH_PIPE_ERROR_AGAIN = -2,
+ GOLDFISH_PIPE_ERROR_NOMEM = -3,
+ GOLDFISH_PIPE_ERROR_IO = -4,
+} GoldfishPipeError;
+
+/* Opaque type of the hardware-side view of a pipe connection. This structure
+ * is implemented by the virtual device and is hidden from the host service
+ * implementation. */
+typedef struct GoldfishHwPipe GoldfishHwPipe;
+
+/* Opaque type of the host-side view of a pipe connection. This structure is
+ * implemented by the host pipe service implementation, and is hidden from
+ * the virtual device. */
+typedef struct GoldfishHostPipe GoldfishHostPipe;
+
+typedef struct {
+ // Open a new pipe. |hw_pipe| is a unique pointer value identifying the
+ // hardware-side view of the pipe, and will be passed to the
+ // goldfish_pipe_xxx() functions below. This returns a new host-specific
+ // pipe value that is only used by the virtual device to call other
+ // callbacks here. There is a one-to-one association between a |hw_pipe|
+ // and its |host_pipe| value, which can be reset by calling
+ // goldfish_pipe_reset().
+ GoldfishHostPipe* (*guest_open)(GoldfishHwPipe *hw_pipe);
+
+ // Load the state of a pipe from a stream. |file| is the input stream,
+ // |hw_pipe| is the hardware-side pipe descriptor. On success, return a new
+ // internal pipe instance (similar to one returned by guest_open()), and
+ // sets |*force_close| to 1 to indicate that the pipe must be force-closed
+ // just after its load/creation (only useful for certain services that can't
+ // preserve state into streams). Return NULL on faillure.
+ GoldfishHostPipe* (*guest_load)(QEMUFile *file, GoldfishHwPipe *hw_pipe,
+ char *force_close);
+
+ // Close and free a pipe. |host_pipe| must be the result of a previous
+ // guest_open() or guest_load() call, or the second parameter to
+ // goldfish_pipe_reset().
+ void (*guest_close)(GoldfishHostPipe *host_pipe);
+
+ // Save the state of a pipe to a stream. |host_pipe| is the pipe
+ // instance from guest_open() or guest_load(). and |file| is the
+ // output stream.
+ void (*guest_save)(GoldfishHostPipe *host_pipe, QEMUFile *file);
+
+ // Poll the state of the pipe associated with |host_pipe|.
+ // This returns a combination of GoldfishPipePollFlags.
+ GoldfishPipePollFlags (*guest_poll)(GoldfishHostPipe *host_pipe);
+
+ // Called when the guest tries to receive data from the host through
+ // |host_pipe|. This will try to copy data to the memory ranges
+ // decribed by the array |buffers| or |num_buffers| items.
+ // Return number of bytes transferred, or a (negative) GoldfishPipeError
+ // value otherwise.
+ int (*guest_recv)(GoldfishHostPipe *host_pipe,
+ GoldfishPipeBuffer *buffers,
+ int num_buffers);
+
+ // Called when the guest tries to send data to the host through
+ // |host_pipe|. This will try to copy data from the memory ranges
+ // decribed by the array |buffers| or |num_buffers| items.
+ // Return number of bytes transferred, or a (negative) GoldfishPipeError
+ // value otherwise.
+ int (*guest_send)(GoldfishHostPipe *host_pipe,
+ const GoldfishPipeBuffer *buffers,
+ int num_buffers);
+
+ // Called when the guest wants to be waked on specific events.
+ // identified by the |wake_flags| bitmask. The host should call
+ // goldfish_pipe_signal_wake() with the appropriate bitmask when
+ // any of these events occur.
+ void (*guest_wake_on)(GoldfishHostPipe *host_pipe,
+ GoldfishPipeWakeFlags wake_flags);
+} GoldfishPipeServiceOps;
+
+/* Called by the service implementation to register its callbacks.
+ * The default implementation doesn't do anything except returning
+ * an error when |guest_open| or |guest_load| are called. */
+extern void goldfish_pipe_set_service_ops(
+ const GoldfishPipeServiceOps* ops);
+
+/* Implemented by the virtual device, always called from the service in
+ * a thread that owns the BQL. */
+
+/* Reset the association of |hw_pipe| with a new |host_pipe|
+ * value. This is called once the guest has written the service name
+ * to the initial pipe connection, and the host decided of the right
+ * implementation for it. */
+extern void goldfish_pipe_reset(GoldfishHwPipe *hw_pipe,
+ GoldfishHostPipe *host_pipe);
+
+/* Called by the host to notify the virtual device that it has
+ * closed its side of the pipe. */
+extern void goldfish_pipe_close_from_host(GoldfishHwPipe *hw_pipe);
+
+/* Called by the host to notify that one or more conditions identified
+ * by |flags| has been met for a given pipe identified by |hw_pipe|. */
+extern void goldfish_pipe_signal_wake(GoldfishHwPipe *hw_pipe,
+ GoldfishPipeWakeFlags flags);
+
+#endif /* _HW_GOLDFISH_PIPE_H */