
#include "pcidev_manage.h"

#include "pcie_cdma_cfg.h"

#define FPGA_VERSION_VALUE(pdev) REG_R(pdev->bars[1].base, 0)
#define ALIAS_VALUE(pdev) (~REG_R(pdev->bars[1].base, 0x18)&0x0F)

// extern device_info_t device_info;
// extern spinlock_t glock;
// void* filp;
// spinlock_t operateLock;

int zpcidev_manage_f_open(struct inode *inode, struct file *file)
{
    _DBG_("+++ open manage +++");
    // zpcidev_manage_miscdev_update_board_info();
    _DBG_("---");
    return 0;
}

int zpcidev_manage_f_close(struct inode *inode, struct file *file)
{
    _DBG_("+++ close manage +++");
    _DBG_("---");
    return 0;
}

long zpcidev_manage_f_ioctl(struct file *file, unsigned int cmd, unsigned long _arg)
{
    int ret = -1;
    int i, num;
    board_node_t* node;
    int type = 0;

    ManageDev* dev = file_to_dev_manage(file);

    _DBG_("+++ ioctl: board cnt=%d, cmd=%d", zpcidev_get_board_cnt(), cmd);
    switch (cmd) {
    // case IOCTL_LOCK:{
    //     int result = 0;
    //     _MSG_("try lock,state:%x", spin_is_locked(&operateLock));
    //     if (spin_trylock(&operateLock)){
    //         ret = 0;
    //         _MSG_("lock success.");
    //         filp = file;
    //     }else{
    //         _MSG_("try lock failed.");
    //         ret = -1;
    //     }
    //     break;
    // }
    // case IOCTL_UNLOCK:{
    //     _MSG_("request release lock");
    //     if (filp == file){
    //         spin_unlock(&operateLock);
    //         _MSG_("release lock");
    //         filp = NULL;
    //     }
    //     break;
    // }
    case IOCTL_READ_BOARD_INFO:{
        get_board_info_t  board_info;
        get_board_info_t* arg = (get_board_info_t*)_arg;
        ret = copy_from_user(&board_info, arg, sizeof(board_info));
        if (ret) {
            _DBG_("IOCTL_READ_BOARD_INFO:copy_from_user(opt) failed");
            ret = -1;
            break;
        }
        _DBG_("+++ ioctl: IOCTL_READ_BOARD_INFO, index=%d", board_info.board_index);
        node = dev->nodeHeader.next;
        for (i = 0; i != board_info.board_index && node != &dev->nodeHeader; i++){
            node = node->next;
        }
        if (i == board_info.board_index){
            node->board_info.u32Alias = ALIAS_VALUE(node->pdev);
            ret = copy_to_user(&(arg->board_info), &(node->board_info), sizeof(node->board_info));
        }
        break;
    }
    case IOCTL_READ_DRIVER_INFO:{
        driver_info_t driver_info;
        ret = zpcidev_get_driver_version_msg(driver_info.caDriverVersion, sizeof(driver_info.caDriverVersion));
        if (ret) {
            _ERR_("driver version read err.");
        }
        driver_info.u32BoardCnt = zpcidev_get_board_cnt();
        _DBG_("+++ ioctl: IOCTL_READ_DRIVER_INFO");
        ret = copy_to_user((void*)_arg, &driver_info, sizeof(driver_info));
        break;
    }
    case IOCTL_READ_DEV_MSG:{
        get_devName_t get_devname;
        get_devName_t* arg = (get_devName_t*)_arg;
        ret = copy_from_user(&get_devname, arg, sizeof(get_devname));
        if (ret) {
            _DBG_("IOCTL_READ_DEV_MSG:copy_from_user(opt) failed");
            ret = -1;
            break;
        }
        _DBG_("+++ ioctl: IOCTL_READ_DEV_MSG, ID=%s", get_devname.devID);
        node = dev->nodeHeader.next;

        if (sscanf(get_devname.devID, "ID%d", &num) == 1){
            type = 1;
        }else if (sscanf(get_devname.devID, "AL%d", &num) == 1){
            type = 2;
        }else if (memcmp(get_devname.devID, "NO", 2) == 0){
            type = 3;
        }else{
            type = 0;
        }
       
        if (type){
            for (i = 0; node != &dev->nodeHeader; i++){
                _DBG_("+++ type:%d, id:%u, al:%u, no:%s", type, node->u32BoardIndex, node->board_info.u32Alias, node->board_info.caSerialNo)
                if (type == 1){
                    if (num == node->u32BoardIndex){
                        break;
                    }
                }else if (type == 2){
                    node->board_info.u32Alias = ALIAS_VALUE(node->pdev);
                    if (num == node->board_info.u32Alias){
                        break;
                    }
                }else if (type == 3){
                    if (memcmp(get_devname.devID, node->board_info.caSerialNo, strlen(node->board_info.caSerialNo)) == 0){
                        break;
                    }
                }
                node = node->next;
            }
            if (node){
                ret = copy_to_user(&(arg->caDevName), &(node->caDevName), sizeof(node->caDevName));
                if (!ret){
                    ret = copy_to_user(&(arg->u32BarSize), &(node->u32BarSize), sizeof(node->u32BarSize));
                    if (ret){
                        _DBG_("IOCTL_READ_DEV_MSG:copy_from_user(opt) failed");
                        ret = -1;
                    }
                }else{
                    _DBG_("IOCTL_READ_DEV_MSG:copy_from_user(opt) failed");
                    ret = -1;
                }
            }else{
                _DBG_("IOCTL_READ_DEV_MSG:node not found");
                ret = -1;
            }
        }else{
            _DBG_("IOCTL_READ_DEV_MSG:node not found");
            ret = -1;
        }
        
        break;
    }
    default:
        break;
    }
    _DBG_("--- ioctl: ret=%d", ret);
    return ret;
}



board_node_t* create_board_info(zpcidev_device *pcidev){
    board_node_t* kbuff;
    int i;
    kbuff = kzalloc(sizeof(board_node_t), GFP_KERNEL);
    kbuff->pdev = pcidev;
    kbuff->u32BoardIndex = pcidev->devIndex;
    sprintf(kbuff->board_info.caSerialNo, "NO06060%d", pcidev->devIndex);
    kbuff->board_info.u32Alias = ALIAS_VALUE(pcidev);
    strcpy(kbuff->board_info.caBoardName, "PCIe-Ethercat");
    sprintf(kbuff->board_info.caVersion, "fpga:%08x", FPGA_VERSION_VALUE(pcidev));
    _MSG_("FPGA version: 0x%08X", FPGA_VERSION_VALUE(pcidev));
    for (i = 0; i < ZPCIDEV_MAX_BARS; i++){
        kbuff->u32BarSize[i] = pcidev->bars[i].size;
    }
    strcpy(kbuff->caDevName, pcidev->miscDevName);
    kbuff->board_info.u32EcatChannelCnt = 0;
    return kbuff;
}





