#include "ldevusbu.h"
//////////////////////////////////////////////////////////////////////////////////////////

void COMMAND_E440(ldevusb *dev, u16 Cmd) {
    int status = -1;
    u32 TO = 1000;
    PUT_PM_WORD_E440(dev, L_COMMAND_E440, LBIOS_OUTVAR(Cmd));
    status = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
                           V_COMMAND_IRQ_E440, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
                           0, 0, NULL, 0, HZ*10);

    while(LBIOS_INVAR(GET_PM_WORD_E440(dev, L_COMMAND_E440))&&(TO--));
}


u16 GET_DM_WORD_E440(ldevusb *dev, u16 Addr) {
    int status = -1;
    u16 Data;
    u16 *Dat = (u16 *)kmalloc(2,GFP_KERNEL);
    status = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
                           V_GET_ARRAY_E440, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
                           (u16)(Addr|DM_E440), 0, Dat, sizeof(u16), HZ*10);
    Data = Dat[0];
    kfree(Dat);
    return Data;
}

void PUT_DM_WORD_E440(ldevusb *dev, u16 Addr, u16 Data) {
    int status = -1;
    u16 *Dat = (u16 *)kmalloc(2,GFP_KERNEL);
    Dat[0]=Data;
    status = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
                           V_PUT_ARRAY_E440, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
                           (u16)(Addr|DM_E440), 0, Dat, sizeof(u16), HZ*10);
    kfree(Dat);
}

u32 GET_PM_WORD_E440(ldevusb *dev, u16 Addr) {
    int status = -1;
    u32 Data;
    u32 *Dat = (u32 *)kmalloc(4,GFP_KERNEL);
    status = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
                           V_GET_ARRAY_E440, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
                           (u16)(Addr|PM_E440), 0, Dat, sizeof(u32), HZ*10);
    Data = Dat[0];
    kfree(Dat);
    return Data;
}

void PUT_PM_WORD_E440(ldevusb *dev, u16 Addr, u32 Data) {
    int status = -1;
    u32 *Dat = (u32 *)kmalloc(4,GFP_KERNEL);
    Dat[0] = Data;
    status = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
	                         V_PUT_ARRAY_E440, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
                           (u16)(Addr|PM_E440), 0, Dat, sizeof(u32), HZ*10);
    kfree(Dat);
}

void GET_DATA_MEMORY_E440(ldevusb *dev, u16 *Data, u32 Count, u16 Addr) {
    int status = -1;
    int i,ss,s = Count/2048; // bytes
    u8 *Dat = kmalloc(4096,GFP_KERNEL);
    for(i = 0; i < s; ++i) {
        status = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
                              V_GET_ARRAY_E440, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
                              //(u16)((Addr+i*2048)|DM_E440), 0, (u8 *)(&Data[2048*i]), 2048*sizeof(u16), HZ*10);
                              (u16)((Addr+i*2048)|DM_E440), 0, (u8 *)Dat, 2048*sizeof(u16), HZ*10);
        memcpy(&Data[2048*i],Dat,2048*sizeof(u16));
    }

    ss = Count%2048;
    if(ss) {
        status = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
	                           V_GET_ARRAY_E440, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
                             //(u16)((Addr+s*2048)|DM_E440), 0, (u8 *)(&Data[2048*s]), ss*sizeof(u16), HZ*10);
                             (u16)((Addr+s*2048)|DM_E440), 0, (u8 *)Dat, ss*sizeof(u16), HZ*10);
        memcpy(&Data[2048*s],Dat,ss*sizeof(u16));
    }
    kfree(Dat);
}

void PUT_DATA_MEMORY_E440(ldevusb *dev, u16 *Data, u32 Count, u16 Addr) { // how words
    int status = -1;
    int i,ss,s = Count/2048; // bytes
    u8 *Dat = kmalloc(4096,GFP_KERNEL);
    for(i = 0; i < s; ++i) {
        memcpy(Dat,&Data[2048*i],2048*sizeof(u16));
        status = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
                             V_PUT_ARRAY_E440, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
                             //(u16)((Addr+i*2048)|DM_E440), 0, (u8 *)(&Data[2048*i]), 2048*sizeof(u16), HZ*10);
                             (u16)((Addr+i*2048)|DM_E440), 0, (u8 *)Dat, 2048*sizeof(u16), HZ*10);
    }

    ss = Count % 2048;
    if (ss) {
        memcpy(Dat,&Data[2048*s],ss*sizeof(u16));
        status = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
                             V_PUT_ARRAY_E440, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
                             //(u16)((Addr+s*2048)|DM_E440), 0, (u8 *)(&Data[2048*s]), ss*sizeof(u16), HZ*10);
                             (u16)((Addr+s*2048)|DM_E440), 0, (u8 *)Dat, ss*sizeof(u16), HZ*10);
    }
    kfree(Dat);
}

void PUT_PM_MEMORY_E440(ldevusb *dev, u32 *Data, u32 Count, u16 Addr) {
    int status = -1;
    u32 MP = 1024;
    int i,ss,s = Count/MP; // bytes
    u8 *Dat = kmalloc(4096,GFP_KERNEL);
    for(i = 0; i<s; ++i) {
        memcpy(Dat,&Data[MP*i],MP*sizeof(u32));
        status = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
                             V_PUT_ARRAY_E440, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
                             //(u16)((Addr+i*MP)|PM_E440), 0, (u8 *)(&Data[MP*i]), MP*sizeof(u32), HZ*10);
                             (u16)((Addr+i*MP)|PM_E440), 0, (u8 *)Dat, MP*sizeof(u32), HZ*10);
    }
    ss = Count % MP;
    if(ss) {
        memcpy(Dat,&Data[MP*s],ss*sizeof(u32));
        status = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
                                   V_PUT_ARRAY_E440, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
                                  //(u16)((Addr+s*MP)|PM_E440), 0, (u8 *)(&Data[MP*s]), ss*sizeof(u32), HZ*10);
                                  (u16)((Addr+s*MP)|PM_E440), 0, (u8 *)Dat, ss*sizeof(u32), HZ*10);
    }
    kfree(Dat);
}

void GET_PM_MEMORY_E440(ldevusb *dev, u32 *Data, u32 Count, u16 Addr) {
    int status = -1;
    u32 MP = 1024;
    int i,ss,s = Count/MP; // bytes
    u8 *Dat = kmalloc(4096,GFP_KERNEL);
    for(i = 0; i < s; i++) {
   	status = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
                             V_GET_ARRAY_E440, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
                             //(u16)((Addr+i*MP)|PM_E440), 0, (u8 *)(&Data[MP*i]), MP*sizeof(u32), HZ*10);
                             (u16)((Addr+i*MP)|PM_E440), 0, (u8 *)Dat, MP*sizeof(u32), HZ*10);

        memcpy(&Data[MP*i],Dat,MP*sizeof(u32));
    }
    ss = Count % MP;
    if(ss) {
        status = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
                                 V_GET_ARRAY_E440, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
                                //(u16)((Addr+s*MP)|PM_E440), 0, (u8 *)(&Data[MP*s]), ss*sizeof(u32), HZ*10);
                                (u16)((Addr+s*MP)|PM_E440), 0, (u8 *)Dat, ss*sizeof(u32), HZ*10);
        memcpy(&Data[MP*s],Dat,ss*sizeof(u32));
    }
    kfree(Dat);
}


//------------------------------------------------------------------------
// разрешение/запрещение режима записи в ППЗУ модуля
//------------------------------------------------------------------------
u32 EnableFlashWrite_E440(ldevusb *dev, u16 Flag) {
    int i;
    u16 word = (Flag) ? 0x9800 : 0x8000;
    PUT_PM_WORD_E440(dev,L_FLASH_ENABLED_E440,LBIOS_OUTVAR(word));
    COMMAND_E440(dev,cmENABLE_FLASH_WRITE_E440);
    for(i=0; i < 1000; i++)
        udelay(10);
    return 1;
}

//------------------------------------------------------------------------
// чтенние слова из ППЗУ
//------------------------------------------------------------------------
void ReadFlashWord_E440(ldevusb *dev, u16 FlashAddress, u16 *Data) {
    PUT_PM_WORD_E440(dev,L_FLASH_ADDRESS_E440, LBIOS_OUTVAR((u16)((FlashAddress << 7) | 0xC000)));
    COMMAND_E440(dev,cmREAD_FLASH_WORD_E440);
    *Data = LBIOS_INVAR(GET_PM_WORD_E440(dev,L_FLASH_DATA_E440));

}

//------------------------------------------------------------------------
// запись слова в ППЗУ
//------------------------------------------------------------------------
void WriteFlashWord_E440(ldevusb *dev, u16 FlashAddress, u16 Data) {
    int i;
    PUT_PM_WORD_E440(dev,L_FLASH_ADDRESS_E440, LBIOS_OUTVAR((u16)((FlashAddress << 7) | 0xA000)));
    PUT_PM_WORD_E440(dev,L_FLASH_DATA_E440, LBIOS_OUTVAR(Data));
    COMMAND_E440(dev,cmWRITE_FLASH_WORD_E440);
    for(i=0; i < 1000;i++)
        udelay(10);
}

void SetBoardFIFO(ldevusb *dev) {
    switch(dev->Type) {
        case E440: PUT_PM_WORD_E440(dev, L_ADC_FIFO_LENGTH_E440, LBIOS_OUTVAR(dev->wFIFO*2)); break;
    }
}


void EnableE440(ldevusb *dev, int b) {
    int i;
    int status = -1;
    if(b) {// start ADC
        // synchro config

        PUT_PM_WORD_E440(dev,L_INPUT_MODE_E440, LBIOS_OUTVAR(dev->adcPar.t3.SynchroType));
        PUT_PM_WORD_E440(dev,L_SYNCHRO_AD_TYPE_E440, LBIOS_OUTVAR(dev->adcPar.t3.SynchroSensitivity));
        PUT_PM_WORD_E440(dev,L_SYNCHRO_AD_MODE_E440, LBIOS_OUTVAR(dev->adcPar.t3.SynchroMode));
        PUT_PM_WORD_E440(dev,L_SYNCHRO_AD_CHANNEL_E440, LBIOS_OUTVAR(dev->adcPar.t3.AdChannel));
        PUT_PM_WORD_E440(dev,L_SYNCHRO_AD_POROG_E440, LBIOS_OUTVAR(dev->adcPar.t3.AdPorog));

        PUT_PM_WORD_E440(dev,L_CONTROL_TABLE_LENGHT_E440, LBIOS_OUTVAR(dev->adcPar.t3.NCh));
        for (i=0; i < dev->adcPar.t3.NCh; i++)
            PUT_PM_WORD_E440(dev,L_CONTROL_TABLE_E440+i, LBIOS_OUTVAR(dev->adcPar.t3.Chn[i]) );

        PUT_PM_WORD_E440(dev,L_FIRST_SAMPLE_DELAY_E440, LBIOS_OUTVAR(dev->adcPar.t3.FPDelay));
        PUT_PM_WORD_E440(dev,L_ADC_RATE_E440, LBIOS_OUTVAR(dev->adcPar.t3.Rate));
        PUT_PM_WORD_E440(dev,L_INTER_KADR_DELAY_E440, LBIOS_OUTVAR(dev->adcPar.t3.Kadr));

        status = usb_clear_halt(dev->udev, usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr));
      
        status = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
                                V_START_ADC_E440, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
                                0x0|DM_E440, dev->wFIFO, NULL, 0, HZ*10);
      
        COMMAND_E440(dev, cmSTART_ADC_E440);
        DbgPrint("start start \n");
    } else { // stop ADC
        DbgPrint("stop stop \n");
        COMMAND_E440(dev, cmSTOP_ADC_E440);
      
        status = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
                                V_START_ADC_E440, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
                                0x0|DM_E440, dev->wFIFO, NULL, 0, HZ*10);

        DbgPrint("pipe aborted \n");
    }
}
