public interface ILibc {
    // file descriptor operations

    /**
     * Manipulate file descriptor
     * @param fd File descriptor to operate upon.
     * @param cmd Command code, see manpages for details.
     * @param arg Command argument, command-speciic. See manpages for details.
     * @return Depends on the command. On failure, -1 is returned.
     * @see <a href="https://man7.org/linux/man-pages/man2/fcntl.2.html">man 2 fcntl</a>
     * @throws LastErrorException If errno is set during the operation. Use Native#getLastError to query the error code.
     */
    int fcntl(int fd, int cmd, int arg) throws LastErrorException;

    // ioctls

    /**
     * Invoke an I/O control request
     * @param fd Opened file descriptor to act upon.
     * @param cmd IO command code; this is device-specific (see manpages and/or kernel sources for details).
     * @param arg IOCTL integer argument, this is device-specific (see manpages and/or kernel sources for details).
     * @return -1 on failure, 0 otherwise (usually).
     * @see <a href="https://man7.org/linux/man-pages/man2/ioctl.2.html">man 2 ioctl</a>
     * @throws LastErrorException If errno is set during the operation. Use Native#getLastError to query the error code.
     */
    int ioctl(int fd, int cmd, int arg) throws LastErrorException;

    /**
     * Invoke an I/O control request
     * @param fd Opened file descriptor to act upon.
     * @param cmd IO command code; this is device-specific (see manpages and/or kernel sources for details).
     * @param arg IOCTL integer argument, this is device-specific (see manpages and/or kernel sources for details).
     * @return -1 on failure, 0 otherwise (usually).
     * @see <a href="https://man7.org/linux/man-pages/man2/ioctl.2.html">man 2 ioctl</a>
     * @throws LastErrorException If errno is set during the operation. Use Native#getLastError to query the error code.
     */
    int ioctl(int fd, int cmd, Pointer arg) throws LastErrorException;

    // open/close

    /**
     * Try to open (or create) a file from the specified path.
     * @param path Path to try to open.
     * @param flags Open mode; typically O_RDONLY/O_WRONLY/O_RDWR combined with other modifiers (see POSIX).
     * @param mode Permissions to be set on the file if it is going to be created (O_CREAT).
     * @return File descriptor or -1 if the file cannot be opened.
     * @see <a href="https://man7.org/linux/man-pages/man2/open.2.html">man 2 open</a>
     * @throws LastErrorException If errno is set during the operation. Use Native#getLastError to query the error code.
     */
    int open(String path, int flags, int mode) throws LastErrorException;

    /**
     * Close the specified file descriptor.
     * @param fd File descriptor to close.
     * @return -1 on failure, 0 otherwise.
     * @see <a href="https://man7.org/linux/man-pages/man2/close.2.html">man 2 close</a>
     * @throws LastErrorException If errno is set during the operation. Use Native#getLastError to query the error code.
     */
    int close(int fd) throws LastErrorException;

    // read/write

    /**
     * Request a write to the current position in the file referred by a file descriptor.
     * @param fd File descriptor of the file to write.
     * @param buffer Buffer with bytes to write.
     * @param count Size of the buffer.
     * @return Number of bytes written or -1 if an error occurred.
     * @see <a href="https://man7.org/linux/man-pages/man2/write.2.html">man 2 write</a>
     * @throws LastErrorException If errno is set during the operation. Use Native#getLastError to query the error code.
     */
    int write(int fd, Buffer buffer, int count) throws LastErrorException;

    /**
     * Request a read from the current position in the file referred by a file descriptor.
     * @param fd File descriptor of the file to read.
     * @param buffer Buffer where to put the data.
     * @param count Size of the buffer.
     * @return Number of bytes read or -1 if an error occurred.
     * @see <a href="https://man7.org/linux/man-pages/man2/read.2.html">man 2 read</a>
     * @throws LastErrorException If errno is set during the operation. Use Native#getLastError to query the error code.
     */
    int read(int fd, Buffer buffer, int count) throws LastErrorException;

    // map/unmap

    /**
     * Map a file to memory.
     * @param addr Address hint from the userspace where to put the mapping in memory. Pass NULL to ignore the hint.
     * @param len Length of the memory to map.
     * @param prot Memory protection flags (PROT_READ/PROT_WRITE/PROT_EXEC). See manpages for details.
     * @param flags Memory mapping flags (MAP_SHARED/MAP_FILE/...). See manpages for deatils.
     * @param fd Opened file descriptor of the file that needs to be mapped to memory.
     * @param off Offset in the file from which to start the mapping.
     * @return On success, address of the mapped memory. On failure, -1 (MAP_FAILED) is returned.
     * @see <a href="https://man7.org/linux/man-pages/man2/mmap.2.html">man 2 mmap</a>
     * @throws LastErrorException If errno is set during the operation. Use Native#getLastError to query the error code.
     */
    Pointer mmap(Pointer addr, NativeLong len, int prot, int flags, int fd, NativeLong off) throws LastErrorException;

    /**
     * Unmap a file from memory.
     * @param addr Address where the file was mapped.
     * @param len Length of the mapped area.
     * @return -1 on failure, 0 otherwise.
     * @see <a href="https://man7.org/linux/man-pages/man2/munmap.2.html">man 2 munmap</a>
     * @throws LastErrorException If errno is set during the operation. Use Native#getLastError to query the error code.
     */
    int munmap(Pointer addr, NativeLong len) throws LastErrorException;

    /**
     * Synchronize memory-mapped data with file contents.
     * @param addr Address where the file was mapped.
     * @param len Length of the mapped area.
     * @param flags Synchronization type (MS_SYNC/MS_ASYNC/MS_INVALIDATE). See manpages for details.
     * @return -1 on failure, 0 otherwise.
     * @see <a href="https://man7.org/linux/man-pages/man2/msync.2.html">man 2 msync</a>
     * @throws LastErrorException If errno is set during the operation. Use Native#getLastError to query the error code.
     */
    int msync(Pointer addr, NativeLong len, int flags) throws LastErrorException;
} public class NativeFramebuffer extends NativeDevice {

    /**
     * Create a native device to provide access to the specified character device
     *
     * @param dname name of the character device
     * @throws LastErrorException when operations fails
     */
    public NativeFramebuffer(@NonNull String dname) throws LastErrorException {
        super(dname);
    }

    /**
     * Create a native device to provide access to the specified character device
     *
     * @param dname name of the character device
     * @param flags Opening mode, e.g. read, write or both.
     * @throws LastErrorException when operations fails
     */
    public NativeFramebuffer(@NonNull String dname, int flags) throws LastErrorException {
        super(dname, flags);
    }

    /**
     * Create a native device to provide access to the specified character device
     *
     * @param dname name of the character device
     * @param libc  standard C library interface to be used.
     * @throws LastErrorException when operations fails
     */
    public NativeFramebuffer(@NonNull String dname, @NonNull ILibc libc) throws LastErrorException {
        super(dname, libc);
    }

    /**
     * Create a native device to provide access to the specified character device
     *
     * @param dname name of the character device
     * @param flags Opening mode, e.g. read, write or both.
     * @param libc  standard C library interface to be used.
     * @throws LastErrorException when operations fails
     */
    public NativeFramebuffer(@NonNull String dname, int flags, @NonNull ILibc libc) throws LastErrorException {
        super(dname, flags, libc);
    }

    /**
     * Fetch fixed screen info.
     *
     * @return Non-changing info about the display.
     */
    public fb_fix_screeninfo getFixedScreenInfo() throws LastErrorException {
        fb_fix_screeninfo info = new fb_fix_screeninfo();
        super.ioctl(FBIOGET_FSCREENINFO, info.getPointer());
        info.read();
        return info;
    }

    /**
     * Fetch variable screen info.
     *
     * @return Changeable info about the display.
     * @throws LastErrorException when operations fails
     */
    public fb_var_screeninfo getVariableScreenInfo() throws LastErrorException {
        fb_var_screeninfo info = new fb_var_screeninfo();
        super.ioctl(FBIOGET_VSCREENINFO, info.getPointer());
        info.read();
        return info;
    }

    /**
     * Send variable screen info.
     *
     * @param info Changeable info about the display.
     * @throws LastErrorException when operations fails
     */
    public void setVariableScreenInfo(@NonNull fb_var_screeninfo info) throws LastErrorException {
        info.write();
        super.ioctl(FBIOPUT_VSCREENINFO, info.getPointer());
    }

    /**
     * Identify which framebuffer is connected to a specified VT.
     *
     * @param console VT number.
     * @return Framebuffer number or -1 if console has no framebuffer.
     * @throws LastErrorException when operations fails
     */
    public int mapConsoleToFramebuffer(int console) throws LastErrorException {
        fb_con2fbmap map = new fb_con2fbmap();
        map.console = console;
        map.write();
        super.ioctl(FBIOGET_CON2FBMAP, map.getPointer());
        map.read();
        return map.framebuffer;
    }

    /**
     * fb_fix_screeninfo mapping
     */
    public static class fb_fix_screeninfo extends Structure {
        /**
         * identification string eg "TT Builtin"
         */
        public byte[] id = new byte[16];
        /**
         * Start of frame buffer mem (physical address)
         */
        public NativeLong smem_start;
        /**
         * Length of frame buffer mem
         */
        public int smem_len;
        /**
         * see FB_TYPE_*
         */
        public int type;
        /**
         * Interleave for interleaved Planes
         */
        public int type_aux;
        /**
         * see FB_VISUAL_*
         */
        public int visual;
        /**
         * zero if no hardware panning
         */
        public short xpanstep;
        /**
         * zero if no hardware panning
         */
        public short ypanstep;
        /**
         * zero if no hardware ywrap
         */
        public short ywrapstep;
        /**
         * length of a line in bytes
         */
        public int line_length;
        /**
         * Start of Memory Mapped I/O (physical address)
         */
        public NativeLong mmio_start;
        /**
         * Length of Memory Mapped I/O
         */
        public int mmio_len;
        /**
         * Indicate to driver which specific chip/card we have
         */
        public int accel;
        /**
         * see FB_CAP_*
         */
        public short capabilities;
        /**
         * Reserved for future compatibility
         */
        public short[] reserved = new short[2];

        /**
         * Initialize this structure.
         */
        public fb_fix_screeninfo() {
            super(ALIGN_GNUC);
        }

        public fb_fix_screeninfo(Pointer p) {
            super(p, ALIGN_GNUC);
        }

        @Override
        protected List<String> getFieldOrder() {
            return Arrays.asList("id", "smem_start", "smem_len",
                    "type", "type_aux", "visual",
                    "xpanstep", "ypanstep", "ywrapstep", "line_length",
                    "mmio_start", "mmio_len", "accel", "capabilities", "reserved");
        }

        /**
         * Reference wrapper
         */
        public static class ByReference extends fb_fix_screeninfo implements Structure.ByReference {
        }

        /**
         * Value wrapper
         */
        public static class ByValue extends fb_fix_screeninfo implements Structure.ByValue {
        }
    }

    /**
     * fb_bitfield mapping
     */
    public static class fb_bitfield extends Structure {
        /**
         * beginning of bitfield
         */
        public int offset;
        /**
         * length of bitfield
         */
        public int length;
        /**
         * != 0 : Most significant bit is right
         */
        public int msb_right;

        /**
         * Initialize this structure.
         */
        public fb_bitfield() {
            super(ALIGN_GNUC);
        }

        public fb_bitfield(Pointer p) {
            super(p, ALIGN_GNUC);
        }

        @Override
        protected List<String> getFieldOrder() {
            return Arrays.asList("offset", "length", "msb_right");
        }

        /**
         * Calculate little-endian byte offset from the bitshift number.
         *
         * @return Offset in byte array
         */
        public int toLEByteOffset() {
            if (length != 8) {
                throw new IllegalArgumentException("Byte offset is applicable only to 8bit sized components");
            }
            if ((offset % 8) != 0) {
                throw new IllegalArgumentException("Byte offset is applicable only to 8bit aligned components");
            }
            return offset / 8;
        }

        /**
         * Reference wrapper
         */
        public static class ByReference extends fb_bitfield implements Structure.ByReference {
        }

        /**
         * Value wrapper
         */
        public static class ByValue extends fb_bitfield implements Structure.ByValue {
        }
    }

    /**
     * fb_var_screeninfo mapping
     */
    public static class fb_var_screeninfo extends Structure {
        /**
         * visible X resolution
         */
        public int xres;
        /**
         * visible Y resolution
         */
        public int yres;
        /**
         * virtual X resolution
         */
        public int xres_virtual;
        /**
         * virtual Y resolution
         */
        public int yres_virtual;
        /**
         * offset from virtual to visible X resolution
         */
        public int xoffset;
        /**
         * offset from virtual to visible Y resolution
         */
        public int yoffset;
        /**
         * BPP value
         */
        public int bits_per_pixel;
        /**
         * 0 = color, 1 = grayscale, >1 = FOURCC
         */
        public int grayscale;
        /**
         * info about red channel
         */
        public fb_bitfield.ByValue red;
        /**
         * info about green channel
         */
        public fb_bitfield.ByValue green;
        /**
         * info about blue channel
         */
        public fb_bitfield.ByValue blue;
        /**
         * info about transparency channel
         */
        public fb_bitfield.ByValue transp;
        /**
         * != 0 Non standard pixel format
         */
        public int nonstd;
        /**
         * see FB_ACTIVATE_*
         */
        public int activate;
        /**
         * height of picture in mm
         */
        public int height;
        /**
         * width of picture in mm
         */
        public int width;
        /**
         * (OBSOLETE) see fb_info.flags
         */
        public int accel_flags;
        /**
         * pixel clock in ps (pico seconds)
         */
        public int pixclock;
        /**
         * time from sync to picture (pixclocks)
         */
        public int left_margin;
        /**
         * time from picture to sync (pixclocks)
         */
        public int right_margin;
        /**
         * time from sync to picture (pixclocks)
         */
        public int upper_margin;
        /**
         * time from sync to picture (pixclocks)
         */
        public int lower_margin;
        /**
         * length of horizontal sync (pixclocks)
         */
        public int hsync_len;
        /**
         * length of vertical sync (pixclocks)
         */
        public int vsync_len;
        /**
         * see FB_SYNC_*
         */
        public int sync;
        /**
         * see FB_VMODE_*
         */
        public int vmode;
        /**
         * angle we rotate counter clockwise
         */
        public int rotate;
        /**
         * colorspace for FOURCC-based modes
         */
        public int colorspace;
        /**
         * Reserved for future compatibility
         */
        public int[] reserved = new int[4];

        /**
         * Initialize this structure.
         */
        public fb_var_screeninfo() {
            super(ALIGN_GNUC);
        }

        public fb_var_screeninfo(Pointer p) {
            super(p, ALIGN_GNUC);
        }


        @Override
        protected List<String> getFieldOrder() {
            return Arrays.asList("xres", "yres", "xres_virtual", "yres_virtual",
                    "xoffset", "yoffset", "bits_per_pixel", "grayscale",
                    "red", "green", "blue", "transp", "nonstd", "activate",
                    "height", "width", "accel_flags", "pixclock",
                    "left_margin", "right_margin", "upper_margin", "lower_margin",
                    "hsync_len", "vsync_len", "sync", "vmode", "rotate", "colorspace", "reserved");
        }

        /**
         * Reference wrapper
         */
        public static class ByReference extends fb_var_screeninfo implements Structure.ByReference {
        }

        /**
         * Value wrapper
         */
        public static class ByValue extends fb_var_screeninfo implements Structure.ByValue {
        }
    }

    public static class fb_con2fbmap extends Structure {
        public int console;
        public int framebuffer;

        public fb_con2fbmap() {
            super(ALIGN_GNUC);
        }

        public fb_con2fbmap(Pointer p) {
            super(p, ALIGN_GNUC);
        }

        @Override
        protected List<String> getFieldOrder() {
            return Arrays.asList("console", "framebuffer");
        }
    }
} public class NativeTTY extends NativeDevice {

    /**
     * Initialize new TTY.
     *
     * @param dname Path to TTY device.
     * @throws LastErrorException when the operation fails.
     */
    public NativeTTY(@NonNull String dname) throws LastErrorException {
        super(dname, NativeConstants.O_RDWR);
    }

    /**
     * Initialize new TTY.
     *
     * @param dname Path to TTY device.
     * @param flags Opening mode, e.g. read, write or both.
     * @throws LastErrorException when the operation fails.
     */
    public NativeTTY(@NonNull String dname, int flags) throws LastErrorException {
        super(dname, flags);
    }

    /**
     * Initialize new TTY.
     *
     * @param dname Path to TTY device.
     * @param libc  standard C library interface to be used.
     * @throws LastErrorException when the operation fails.
     */
    public NativeTTY(@NonNull String dname, @NonNull ILibc libc) throws LastErrorException {
        super(dname, NativeConstants.O_RDWR, libc);
    }

    /**
     * Initialize new TTY.
     *
     * @param dname Path to TTY device.
     * @param flags Opening mode, e.g. read, write or both.
     * @param libc  standard C library interface to be used.
     * @throws LastErrorException when the operation fails.
     */
    public NativeTTY(@NonNull String dname, int flags, @NonNull ILibc libc) throws LastErrorException {
        super(dname, flags, libc);
    }

    /**
     * Get current TTY mode. TTY mode is mostly about VT switching.
     *
     * @return TTY mode.
     * @throws LastErrorException when the operation fails.
     */
    public vt_mode getVTmode() throws LastErrorException {
        vt_mode mode = new vt_mode();
        super.ioctl(VT_GETMODE, mode.getPointer());
        mode.read();
        return mode;
    }

    /**
     * Set current TTY mode. TTY mode is mostly about VT switching.
     *
     * @param mode TTY mode.
     * @throws LastErrorException when the operation fails.
     */
    public void setVTmode(@NonNull vt_mode mode) throws LastErrorException {
        mode.write();
        super.ioctl(VT_SETMODE, mode.getPointer());
    }

    /**
     * Get current TTY state.
     *
     * @return TTY state.
     * @throws LastErrorException when the operation fails.
     */
    public vt_stat getVTstate() throws LastErrorException {
        vt_stat stat = new vt_stat();
        super.ioctl(VT_GETSTATE, stat.getPointer());
        stat.read();
        return stat;
    }

    /**
     * Get current keyboard mode.
     *
     * @return Keyboard mode (raw, transformed or off) - K_* constants.
     * @throws LastErrorException when the operation fails.
     */
    public int getKeyboardMode() throws LastErrorException {
        IntByReference kbd = new IntByReference(0);
        super.ioctl(KDGKBMODE, kbd);
        return kbd.getValue();
    }

    /**
     * Set keyboard mode.
     *
     * @param mode Keyboard mode (raw, transformed or off) - K_* constants.
     * @throws LastErrorException when the operation fails.
     */
    public void setKeyboardMode(int mode) throws LastErrorException {
        super.ioctl(KDSKBMODE, mode);
    }

    /**
     * Set console mode.
     *
     * @param mode Console mode - graphics or text mode - KD_* constants.
     * @throws LastErrorException when the operation fails.
     */
    public void setConsoleMode(int mode) throws LastErrorException {
        super.ioctl(KDSETMODE, mode);
    }

    /**
     * Signal VT switch to the kernel.
     *
     * @param mode VT switching signal - VT_* constants.
     * @throws LastErrorException when the operation fails.
     */
    public void signalSwitch(int mode) throws LastErrorException {
        super.ioctl(VT_RELDISP, mode);
    }

    /**
     * Info about an active VT.
     */
    public static class vt_stat extends Structure {
        public short v_active; /* active vt */
        public short v_signal; /* signal to send */
        public short v_state; /* vt bitmask */

        public vt_stat() {
            super(ALIGN_GNUC);
        }

        public vt_stat(Pointer p) {
            super(p, ALIGN_GNUC);
        }

        @Override
        protected List<String> getFieldOrder() {
            return Arrays.asList("v_active", "v_signal", "v_state");
        }
    }

    /**
     * Info about VT configuration.
     */
    public static class vt_mode extends Structure {
        public byte mode;        /* vt mode */
        public byte waitv;        /* if set, hang on writes if not active */
        public short relsig;        /* signal to raise on release req */
        public short acqsig;        /* signal to raise on acquisition */
        public short frsig;        /* unused (set to 0) */

        public vt_mode() {
            super(ALIGN_GNUC);
        }

        public vt_mode(Pointer p) {
            super(p, ALIGN_GNUC);
        }

        @Override
        protected List<String> getFieldOrder() {
            return Arrays.asList("mode", "waitv", "relsig", "acqsig", "frsig");
        }
    }

} public static final int KD_GRAPHICS = 0x01; public static final int KD_TEXT = 0x00; public static final int K_OFF = 0x04; public static final int O_RDWR = 02; public static final int SIGUSR2 = 12; public static final int VT_AUTO = 0x00; /* auto vt switching */ public static final int VT_PROCESS = 0x01;    /* process controls switching */
import com.sun.jna.LastErrorException;
import ev3dev.utils.io.ILibc;
import ev3dev.utils.io.NativeFramebuffer;
import ev3dev.utils.io.NativeTTY;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import static ev3dev.utils.io.NativeConstants.KD_GRAPHICS;
import static ev3dev.utils.io.NativeConstants.KD_TEXT;
import static ev3dev.utils.io.NativeConstants.K_OFF;
import static ev3dev.utils.io.NativeConstants.O_RDWR;
import static ev3dev.utils.io.NativeConstants.SIGUSR2;
import static ev3dev.utils.io.NativeConstants.VT_AUTO;
import static ev3dev.utils.io.NativeConstants.VT_PROCESS;
package ev3dev.hardware.display;




/**
 * <p>System console manager.</p>
 *
 * <p>It manages the output mode of the display. It is possible
 * to switch between graphics mode and text mode. Graphics mode reserves
 * the display for drawing operation and hides text output. On the
 * other hand, text mode suspends drawing operations and shows the text
 * on the Linux console.
 * This class also manages VT (= Virtual Terminal = console) switches
 * in the case of a VT switch occuring when graphics mode is set.</p>
 *
 * <p>Implementation of this class is based on the GRX3 linuxfb plugin.</p>
 *
 * @author Jakub Vaněk
 * @since 2.4.7
 */
@Slf4j
class OwnedDisplay extends DisplayInterface {

    private ILibc libc;