/**
 * Copyright (c) 2010 by MCST.
 */
#ifndef _MCST_MOKM_H
#define _MCST_MOKM_H

#ifndef TRUE
    #define TRUE 1
#endif
#ifndef FALSE
    #define FALSE 0
#endif


/**
 *  IOCTL COMMANDS
 */
#define MOKM_IOC                (0xDAF5 << 8)
#define MOKM_IOC_RESET          (MOKM_IOC | 0x01)
#define MOKM_IOC_GET_STAT       (MOKM_IOC | 0x02)
#define MOKM_IOC_GET_MAXXFER    (MOKM_IOC | 0x03)
#define MOKM_IOC_CLEAR_STAT     (MOKM_IOC | 0x04)
#define MOKM_IOC_SND_MSG        (MOKM_IOC | 0x05)   //func
#define MOKM_IOC_RCV_MSG        (MOKM_IOC | 0x06)   //func
#define MOKM_IOC_SET_DBG        (MOKM_IOC | 0x07)
#define MOKM_IOC_WR_BUF         (MOKM_IOC | 0x0b)   //func
#define MOKM_IOC_GET_RD_WAIT    (MOKM_IOC | 0x0c)
#define MOKM_IOC_GET_WR_WAIT    (MOKM_IOC | 0x0d)
#define MOKM_IOC_SET_RD_WAIT    (MOKM_IOC | 0x0e)
#define MOKM_IOC_SET_WR_WAIT    (MOKM_IOC | 0x0f)
#define MOKM_IOC_PUT_RD_BUF     (MOKM_IOC | 0x10)   //func
#define MOKM_IOC_RD_BUF         (MOKM_IOC | 0x11)   //func
#define MOKM_IOC_DBG_POINT      (MOKM_IOC | 0x12)   //
#define MOKM_IOC_GET_WR_BUF     (MOKM_IOC | 0x13)   //func
#define MOKM_IOC_PUT_WR_BUF     (MOKM_IOC | 0x14)   //func

// ioctl MOKM_IOC_WR_BUF
typedef struct {
    int size; // Must be the first in this struct
    int buf_num;
} mokm_bufwr_t;


/**
 *  Statistics for MOKM
 */
typedef struct {
    // interrupts
    u_int       rsv_reset;          // Reset request
    u_int       lost_connect;       // Connection lost
    u_int       pear_optic_error;   // Pear optic error
    u_int       optic_error;        // Our optic error
    // -cmd
    u_int       rx_cmd_buf_full;    // Receive CMD buffer full
    u_int       tx_cmd_error;       // ERROR transmit CMD
    u_int       tx_cmd_buf_busy;    // Transmit CMD buffer busy
    u_int       rx_cmd_int;         // We recieved CMD
    // -rx
    u_int       rx_buf_ok;          // Reciever Done
    uint64_t    rx_size_all;        // Received bytes
    u_int       rx_buf_lost;        // Reciever Done with empty buf ptr
    u_int       rx_buf_pci_err;     // PCI ERROR on RCV DATA
    u_int       rx_buf_error;       // DATA recieve ERROR
    // -tx
    u_int       tx_buf_ok;          // Transmitter Done
    uint64_t    tx_size_all;        // Transmitted bytes
    u_int       tx_unknown_buf;     // Transmiter Done with empty buf ptr
    u_int       tx_buf_pci_err;     // PCI ERROR on TRANSMIT DATA
    u_int       tx_buf_error;       // DATA transmit ERROR
    u_int       tx_channel_error;   // Transmiter channel error
    //
    u_int       tx_remote_req;      // Remote request
    u_int       exception;          // EXCEPTION
    u_int       exception_code;

    // last write error
    u_int       lwr_pearrd;         // Pear still not ready (TRC.b.pearrd_rdy == 0)
    u_int       lwr_cfu_fail;       // copy_from_user failure
    u_int       lwr_nobuf;          // can't find requested buf
    u_int       lwr_timeout;        // timeout was reached (wait_event_interruptible_timeout)
    u_int       lwr_cantxmit;       // cant xmit buf

    // cur buf stat
    u_int       n_free_r_buf;
    u_int       n_free_w_buf;
} mokm_stat_t;


/**
 *  BUFFERS
 */
#ifndef PAGE_SIZE
	#error PAGE_SIZE
#endif
// Number of buffers in one pool (read or write) & One buffer size (max(x*y)==512)
#define MOKM_BUF_NUM    10
#define MOKM_BUF_SIZE   (PAGE_SIZE) // 4k
//
//#define MOKM_BUF_NUM    4
//#define MOKM_BUF_SIZE   (PAGE_SIZE*128) // 512k
//
#define POOLBUFS (MOKM_BUF_SIZE*MOKM_BUF_NUM) // must be pow of 2 // max==2Mb


/**
 *  Debug
 */
#undef PDEBUG
#ifdef MOKMDEBUG  // defined in makefile
#  define PDEBUG(fmt, args...) fprintf(stderr, fmt, ## args)
#else // not debugging: nothing
# define PDEBUG(fmt, args...)
#endif
#undef nPDEBUG
#define nPDEBUG(fmt, args...) // nothing: it's a placeholder



/**
 * OPEN
 *
 * Returns buffer number on success,
 * negative on failure:
 *  -ENODEV - no device found
 *  -EBUSY - MOKM allready open and busy. Try again later.
 */


/**
 *  IOCTL
 */

/**
 * Move buffer from free_list to ready_list
 * @fd: device file handle
 * @pool: write pool (from mmap)
 * @write_array: return start of selected buffer
 *
 * Returns buffer number on success,
 * negative on failure:
 *  -EAGAIN - No Free Bufs (free buf list empty)
 */
int mokm_get_write_buf (int fd, int *pool, int **write_array)
{
	int res;
	if ((res = ioctl(fd, MOKM_IOC_GET_WR_BUF, NULL)) < 0 ) {
		*write_array = NULL;
		return res;
	}

	*write_array = pool+(res*MOKM_BUF_SIZE)/sizeof(u_int32_t);
	return res;
}

/**
 * Move buffer from ready_list to busy_list and try to transmit
 * @fd: device file handle
 * @buf_num: buffer number
 * @size: bytes to transmit
 *
 * Returns real transmitted bytes, 0 if request is buffered,
 * negative on failure:
 *  -EBUSY - Transmitter is busy
 *  -ENOLINK - Not connected (link down)
 *  -ENOSPC - Pear still not ready (TRC.b.pearrd_rdy == 0)
 *  -EINVAL - copy_from_user failure
 *  -EAGAIN - can't find requested buf
 *  -ETIMEDOUT - timeout was reached (wait_event_interruptible_timeout)
 *  -EFAULT - cant xmit buf
 */
int mokm_write (int fd, int buf_num, int size)
{
    mokm_bufwr_t buffer;

    buffer.buf_num = buf_num;
    buffer.size = size;
    return (ioctl(fd, MOKM_IOC_WR_BUF, &buffer));
}

/**
 * Wait while current transmit done and move buffer from ready_list to free_list
 * @fd: device file handle
 * @buf_num: buffer number
 *
 * Returns 0 on success,
 * negative on failure:
 *  -EAGAIN - can't find buf
 */
int mokm_put_write_buf (int fd, int buf_num)
{
    return (ioctl(fd, MOKM_IOC_PUT_WR_BUF, buf_num));
}

/**
 * Get buffer with received data (and move buffer from ready_list to busy_list)
 * @fd: device file handle
 * @pool: read pool (from mmap)
 * @read_array: return start of received buffer
 * @buf_num: return received buffer number
 *
 * Returns real received bytes,
 * negative on failure:
 *  -EAGAIN - nothing to read (ready list empty)
 *  -EFAULT - BUFF == NULL / Rcv wrong buff_num
 *  -EINVAL - copy_to_user failure
 */
int mokm_read (int fd, int* pool, int** read_array, int* buf_num)
{
	int res;
	int num;

	*buf_num = -1;
	if ((res = ioctl(fd, MOKM_IOC_RD_BUF, &num)) < 0) {
        *buf_num = -1;
        *read_array = NULL;
		return res;
	}

	*buf_num = num;
	*read_array = pool+(num*MOKM_BUF_SIZE)/sizeof(u_int32_t);
	return res;
}

/**
 * Move buffer from busy_list to free_list
 * @fd: device file handle
 * @buf_num: buffer number
 *
 * Returns 0 on success,
 * negative on failure:
 *  -EAGAIN - can't find buf
 */
int mokm_put_read_buf (int fd, int buf_num)
{
    return (ioctl(fd, MOKM_IOC_PUT_RD_BUF, buf_num));
}


/**
 * Send message
 * @fd: device file handle
 * @cmd: message
 *
 * Returns transmitted status, 0 if Ok,
 * negative on failure:
 *  -EBUSY - Tranmiter NOT ready (TRC.b.wr_rdy == 0)
 */
int mokm_write_cmd (int fd, u_int32_t cmd)
{
	return (ioctl(fd, MOKM_IOC_SND_MSG, cmd));
}

/**
 * Receive message
 * @fd: device file handle
 * @cmd: return message
 *
 * Returns received status, 0 if Ok,
 * negative on failure:
 *  -ETIMEDOUT - timeout was reached (wait_event_interruptible_timeout)
 *  -EINTR - Interrupted/Error
 *  -EINVAL - copy_to_user failure
 */
int mokm_read_cmd (int fd, u_int32_t* cmd)
{
    return (ioctl(fd, MOKM_IOC_RCV_MSG, cmd));
}


/**
 * Get statistics information
 * @fd: device file handle
 * @stat: return statistics
 *
 * Returns 0 if Ok,
 * negative on failure:
 *  -EINVAL - copy_to_user failure
 */
int mokm_get_stat (int fd, mokm_stat_t *stat)
{
    return (ioctl(fd, MOKM_IOC_GET_STAT, stat));
}

/**
 * Clear statistics information
 * @fd: device file handle
 *
 */
void mokm_clear_stat (int fd)
{
    ioctl(fd, MOKM_IOC_CLEAR_STAT, NULL);
}



#endif // _UAPI_MCST_MOKM_H
