#ifndef __COMMON_H
#define __COMMON_H
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/miscdevice.h>
#include <linux/dma-mapping.h>
#include <linux/time.h>
#include <linux/mutex.h>
// #include <linux/semaphore.h>
// #include <linux/uaccess.h>
// #include <linux/hrtimer.h>
// #include <linux/ktime.h>

#define ZPCIDEV_MODULE_INFO  "Zhiyuan PCI/PCIE Device"
#define ZPCIDEV_DRIVER_NAME  "zpcidev"
#define ZPCIDEV_DRIVER_VERS  "1.2.2"

#define REG_R(base,offs)  readl((u32*)((u8*)(base)+(offs)))
#define REG_W(base,offs,val)  writel(val,(u32*)((u8*)(base)+(offs)))

/************************************************************/
/* type define */

typedef struct {
    __u32 addr;
    __u32 size;
    __u32 fifo;
    __u32 pad;
    void *buff;
} zpcidev_reg_rw;

#define ZPCIDEV_MAX_BARS  6
#define ZPCIDEV_MAX_PORTS  2
#define SEM_SIZE    8

struct pcie_trigger{
    // struct hrtimer timer;
    struct semaphore sem;
    wait_queue_head_t wait_queue;
    bool timer_expired;
};

typedef struct {
    int type;
} zpcidev_port;

typedef struct{
    dma_addr_t dma_pa;
    void* dma_va;
    size_t dma_size;
    __u32 dma_pa_mask;
    __u32 dma_pa_ofs;
    struct mutex dma_mtx;
}cdma_ctrl_t;

typedef struct{
    __u64 phyAddr;
    __u64 length;
}__testMsg;

struct board_node_s;

typedef struct {
    struct pci_dev *pcidev;
    struct miscdevice miscDev;
    char miscDevName[256];
    bool miscdev_rdy;
    struct {
        size_t start;
        size_t end;
        size_t size;
        void __iomem *base;
    } bars[ZPCIDEV_MAX_BARS];
    int irq;
    int deviceType;
    int nChannels;
    int devIndex;
    /**
     * 一张主站卡两个通道，一个通道4个中断，分别是高低优先级邮箱、PDO、SOCK
     */
    struct pcie_trigger semHr[SEM_SIZE];
    cdma_ctrl_t dmaHandle;
    struct{
        spinlock_t locked;
    }InterruptMsg;
    struct board_node_s* boardNode;
    // struct semaphore sem[SEM_SIZE];
    // zpcidev_port ports[ZPCIDEV_MAX_PORTS];
} zpcidev_device;

#define BOARD_NAME_LEN  30
#define VERSION_MSG_LEN 30
#define BOARD_SERIALNO_LEN 30
#define DEV_NAME_LEN    30
#define SERIAL_LEN      30

typedef struct{
    char caBoardName[BOARD_NAME_LEN];
    char caVersion[VERSION_MSG_LEN];
    char caSerialNo[BOARD_SERIALNO_LEN];
    __u32 u32Alias;
    __u32 u32EcatChannelCnt;
}board_info_t;

typedef struct{
    char caDriverVersion[VERSION_MSG_LEN];
    __u32 u32BoardCnt;
}driver_info_t;


typedef struct board_node_s{
    __u32 u32BoardIndex;
    board_info_t board_info;
    struct board_node_s* prev;
    struct board_node_s* next;
    zpcidev_device* pdev;
    char caDevName[DEV_NAME_LEN];
    __u32 u32BarSize[ZPCIDEV_MAX_BARS];
}board_node_t;

typedef struct{
    driver_info_t driver_info;
    board_node_t* header;
    char miscDevName[DEV_NAME_LEN];
    struct miscdevice miscdev;
}device_info_t;

typedef struct{
    int board_index;
    board_info_t board_info;
}get_board_info_t;

typedef struct{
    char devID[DEV_NAME_LEN];
    char caDevName[DEV_NAME_LEN];
    __u32 u32BarSize[ZPCIDEV_MAX_BARS];
}get_devName_t;

typedef struct{
    __u8 interrupt;
    __u64 timeout;
    __s8  result;
}wait_sem_t;

#define DEV_BAR_NUM 3
typedef struct{
	size_t barPtr[DEV_BAR_NUM];
	size_t barSize[DEV_BAR_NUM];
}PCIE_BAR_MSG;

typedef struct{
	uintptr_t srcAddr;
	uintptr_t desAddr;
	uint32_t  dataSize;
	uint32_t  timeout_ms;
    uint32_t  copyMode;
}PCIe_CDMA_MSG;

typedef struct{
    uint32_t dmaSize;
    uintptr_t dmaVa;
    uintptr_t dmaPa;
}PCIe_CMDA_INFO;

typedef struct {
    struct miscdevice dev;
    __u8 devIsReady;
    board_node_t nodeHeader;
}ManageDev;

typedef struct{
    char caDriverVersion[VERSION_MSG_LEN];
    __u32 deviceNum;
    ManageDev manageDev;
}DriverGlobalRes;

typedef enum{
    ZPCIe_IOCTL_USER_ADDR_ERR = -99999,

}ZPCIe_IOCTL_ERR;

/************************************************************/

enum{
    CDMA_PC_READ_FROM_DEVICE = 0,  //PC read from device
    CDMA_PC_WRITE_TO_DEVICE,       //PC write to device
    CDMA_DEVICE_COPY_TO_DEVICE,    //device copy to device
    CDMA_COPY_MODE_SIZE,
};

// #define IOCTL_REG_W  _IOWR(100, 0, zpcidev_reg_rw)
// #define IOCTL_REG_R  _IOWR(100, 1, zpcidev_reg_rw)
#define IOCTL_READ_BOARD_INFO  _IOWR(100, 3, get_board_info_t)
#define IOCTL_READ_DRIVER_INFO  _IOWR(100, 4, driver_info_t)
#define IOCTL_READ_DEV_MSG     _IOWR(100, 5, get_devName_t)
#define IOCTL_WAIT_INT  _IOWR(100, 6, wait_sem_t)
#define IOCTL_LOCK _IOWR(100, 7, int)
#define IOCTL_UNLOCK _IOWR(100, 8, int)
#define IOCTL_GET_BAR_MSG _IOWR(100, 9, PCIE_BAR_MSG)
#define IOCTL_CTRL_0 _IOWR(100, 10, __testMsg)
#define IOCTL_CDMA_INFO _IOWR(100, 11, PCIe_CMDA_INFO)
#define IOCTL_CDMA_COPY _IOWR(100, 12, PCIe_CDMA_MSG)


#define file_to_dev(file)  (container_of(file->private_data, zpcidev_device, miscDev))
#define file_to_dev_manage(file)  (container_of(file->private_data, ManageDev, dev))

extern unsigned dbg;
#define _DBG_(fmt, args...)  if (dbg) { printk(KERN_DEBUG ZPCIDEV_DRIVER_NAME ":%s<%d>: " fmt "\r\n", __FUNCTION__, __LINE__, ##args); }
#define _WRN_(fmt, args...)  printk(KERN_INFO  ZPCIDEV_DRIVER_NAME ":%s(%d): " fmt "\r\n", __FUNCTION__, __LINE__, ##args)
#define _MSG_(fmt, args...)  printk(KERN_INFO  ZPCIDEV_DRIVER_NAME ": " fmt "\r\n", ##args)
#define _ERR_(fmt, args...)  printk(KERN_ERR ZPCIDEV_DRIVER_NAME ":%s(%d): " fmt "\r\n", __FUNCTION__, __LINE__, ##args)

/**************************************** */
/* common interface */

__u32 zpcidev_get_board_cnt(void);

__s32 zpcidev_get_driver_version_msg(void* outputBuff, __u32 buffSize);


/**************************************** */


#endif //__COMMON_H