blob: 06d69b2bb179d19ba308c233fec9b1b80a4ffa6f [file] [log] [blame]
/* 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/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"
namespace {
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; }
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;
}