// Copyright 2020 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _HW_GOLDFISH_PIPE_H
#define _HW_GOLDFISH_PIPE_H

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

typedef struct QEMUFile QEMUFile;

/* 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 */
    GOLDFISH_PIPE_WAKE_UNLOCK_DMA  = (1 << 3),/* unlock this pipe's DMA buffer */
} 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;

/* List of reasons why pipe is closed. */
typedef enum {
    GOLDFISH_PIPE_CLOSE_GRACEFUL = 0,
    GOLDFISH_PIPE_CLOSE_REBOOT = 1,
    GOLDFISH_PIPE_CLOSE_LOAD_SNAPSHOT = 2,
    GOLDFISH_PIPE_CLOSE_ERROR = 3,
} GoldfishPipeCloseReason;

/* 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 GoldfishPipeServiceOps {
    // 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);
    GoldfishHostPipe* (*guest_open_with_flags)(GoldfishHwPipe *hw_pipe, uint32_t flags);

    // 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(). |reason| is why the pipe was closed.
    void (*guest_close)(GoldfishHostPipe *host_pipe,
                        GoldfishPipeCloseReason reason);

    // A set of hooks to prepare and cleanup save/load operations. These are
    // called once per each snapshot operation, as opposed to the following
    // guest_load()/guest_save().
    void (*guest_pre_load)(QEMUFile *file);
    void (*guest_post_load)(QEMUFile *file);
    void (*guest_pre_save)(QEMUFile *file);
    void (*guest_post_save)(QEMUFile *file);

    // 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);

    // 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);

    // Blocking call that waits until guest is able to receive data through |host_pipe|.
    void (*wait_guest_recv)(GoldfishHostPipe* host_pipe);

    // 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);

    // Blocking call that waits until guest is able to send data through |host_pipe|.
    void (*wait_guest_send)(GoldfishHostPipe* host_pipe);

    // 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);

    // called to register a new DMA buffer that can be mapped in guest + host.
    void (*dma_add_buffer)(void* pipe, uint64_t guest_paddr, uint64_t);
    // called when the guest is done with a particular DMA buffer.
    void (*dma_remove_buffer)(uint64_t guest_paddr);
    // called when host mappings change, such
    // as on pipe save/load during snapshots.
    void (*dma_invalidate_host_mappings)(void);
    // called when device reboots and we need to reset pipe state completely.
    void (*dma_reset_host_mappings)(void);
    // For snapshot save/load of DMA buffer state.
    void (*dma_save_mappings)(QEMUFile* file);
    void (*dma_load_mappings)(QEMUFile* file);
} 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);

/* Query the service ops struct from other places. For use with
 * virtio. */
extern const GoldfishPipeServiceOps* goldfish_pipe_get_service_ops(void);

extern GoldfishHwPipe* goldfish_pipe_lookup_by_id(int id);

#endif /* _HW_GOLDFISH_PIPE_H */
