/*
 * Copyright 2007 The Android Open Source Project
 *
 * Fake device support.
 */
#ifndef _WRAPSIM_FAKEDEV_H
#define _WRAPSIM_FAKEDEV_H

#include <sys/types.h>
#include <sys/uio.h>
#include <errno.h>

typedef struct FakeDev FakeDev;

typedef int     (*Fake_close)(FakeDev* dev, int);
typedef ssize_t (*Fake_read)(FakeDev* dev, int, void*, size_t);
typedef ssize_t (*Fake_readv)(FakeDev* dev, int, const struct iovec*, int);
typedef ssize_t (*Fake_write)(FakeDev* dev, int, const void*, size_t);
typedef ssize_t (*Fake_writev)(FakeDev* dev, int, const struct iovec*, int);
typedef void*   (*Fake_mmap)(FakeDev* dev, void*, size_t, int, int, int, __off_t);
typedef int     (*Fake_ioctl)(FakeDev* dev, int, int, void*);

/*
 * An open fake device entry.
 */
struct FakeDev {
    /* string, for debugging; usually orig. device name */
    char*   debugName;

    /* state bucket */
    void*   state;

    /* the file descriptor we're associated with */
    int     fd;

    /* in some cases we use a pair; this is the other one */
    int     otherFd;

    /*
     * Device functions we provide.
     *
     * All other file descriptor operations should fail, usually with EBADF.
     */
    Fake_close  close;
    Fake_read   read;
    Fake_readv  readv;
    Fake_write  write;
    Fake_writev writev;
    Fake_mmap   mmap;       // handles both mmap() and mmap64()
    Fake_ioctl  ioctl;
};

/*
 * If a handler isn't defined for a syscall, we return EMLINK so that it's
 * obvious when the error is generated by us.
 */ 
#define kNoHandlerError EMLINK

/*
 * Fake file descriptors begin here.  This should be chosen such that no
 * real descriptor is ever at or above this value.
 */
#define kFakeFdBase     512
#define kMaxFakeFdCount 256

/*
 * Create a new, completely fake device entry.
 */
FakeDev* wsCreateFakeDev(const char* debugName);

/*
 * Create a new, mostly fake device entry.
 */
FakeDev* wsCreateRealFakeDev(const char* debugName);

/*
 * Free a fake device entry.
 */
void wsFreeFakeDev(FakeDev* dev);

/*
 * Given a file descriptor, find the corresponding fake device.  Returns
 * NULL if the fd doesn't correspond to one of our entries.
 */
FakeDev* wsFakeDevFromFd(int fd);

/*
 * Check to see if this open() call is on a device we want to spoof.
 *
 * Returns a "fake" file descriptor on success, <0 on error.
 */
int wsInterceptDeviceOpen(const char* pathName, int flags);

/*
 * Check to see if this access() call is on a device we want to spoof.
 *
 * Returns 0 if the device can be fake-accessed, -1 if it can't, -2
 * if it can't and we don't want to allow fallback to the host-device.
 */
int wsInterceptDeviceAccess(const char* pathName, int flags);

/*
 * Devices.
 */
FakeDev* wsOpenDevAudio(const char* pathName, int flags);
FakeDev* wsOpenDevConsoleTty(const char* pathName, int flags);
FakeDev* wsOpenDevEvent(const char* pathName, int flags);
FakeDev* wsOpenDevFb(const char* pathName, int flags);
FakeDev* wsOpenDevLog(const char* pathName, int flags);
FakeDev* wsOpenDevPower(const char* pathName, int flags);
FakeDev* wsOpenSysPower(const char* pathName, int flags);
FakeDev* wsOpenDevVibrator(const char* pathName, int flags);

/*
 * Performs key remapping and sends the event to the global input event device.
 */
void wsSendSimKeyEvent(int key, int isDown);

/*
 * Send a touch event to the global input event device.
 */
void wsSendSimTouchEvent(int action, int x, int y);

#endif /*_WRAPSIM_FAKEDEV_H*/
