#include #include #include #include #include #include "../l502api_private.h" #include /* GUID интерфейса устройств lpcie для связи приложения с драйвером */ DEFINE_GUID (GUID_LPCIE_INTERFACE, 0x53869b9a, 0x7875, 0x4fd3, 0x9e, 0x04, 0xbe, 0xc8, 0x1a, 0x92, 0xf9, 0xa9); #define L502_IOCTL_TIMEOUT 500 typedef struct { int32_t size; SP_DEVICE_INTERFACE_DETAIL_DATA *intf_detail; } t_lpcie_devlst_intptr; static int32_t f_ioctl(HANDLE hDevice, uint32_t dwIoControlCode, // control code of operation to perform void* lpInBuffer, // pointer to buffer to supply input data uint32_t nInBufferSize, // size of input buffer in bytes void* lpOutBuffer, // pointer to buffer to receive output data uint32_t nOutBufferSize, // size of output buffer in bytes uint32_t* rx_size, uint32_t TimeOut) { // таймаут в мс uint32_t RealBytesTransferred; uint32_t BytesReturned; OVERLAPPED Ov; int32_t err = X502_ERR_OK; uint32_t syserr = 0; // инициализируем OVERLAPPED структуру memset(&Ov, 0x0, sizeof(OVERLAPPED)); // создаём событие для асинхронного запроса Ov.hEvent = CreateEvent(NULL, FALSE , FALSE, NULL); if(!Ov.hEvent) { err = X502_ERR_MEMORY_ALLOC; } else { // посылаем требуемый запрос if(!DeviceIoControl( hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, &BytesReturned, &Ov)) { syserr = GetLastError(); if(syserr != ERROR_IO_PENDING) { CloseHandle(Ov.hEvent); err = X502_ERR_IOCTL_FAILD; GetOverlappedResult(hDevice, &Ov, &RealBytesTransferred, TRUE); } } } if (err == X502_ERR_OK) { // ждём окончания выполнения запроса if (WaitForSingleObject(Ov.hEvent, TimeOut) == WAIT_TIMEOUT) { CancelIo(hDevice); CloseHandle(Ov.hEvent); err = X502_ERR_IOCTL_TIMEOUT; GetOverlappedResult(hDevice, &Ov, &RealBytesTransferred, TRUE); } } // попробуем получить кол-во реально переданных байт данных if (err == X502_ERR_OK) { if(!GetOverlappedResult(hDevice, &Ov, &RealBytesTransferred, TRUE)) { syserr = GetLastError(); CancelIo(hDevice); CloseHandle(Ov.hEvent); err = X502_ERR_IOCTL_FAILD; } else if(nOutBufferSize != RealBytesTransferred) { CancelIo(hDevice); CloseHandle(Ov.hEvent); } else { CloseHandle(Ov.hEvent); } } if ((err == X502_ERR_OK) && (rx_size != NULL)) { *rx_size = RealBytesTransferred; } if (err==X502_ERR_IOCTL_FAILD) { if (syserr == ERROR_NO_SYSTEM_RESOURCES) err = X502_ERR_INSUFFICIENT_SYSTEM_RESOURCES; } return err; } int32_t l502_port_fpga_reg_write(t_x502_hnd hnd, uint32_t reg, uint32_t val) { t_lpcie_mem_rw mem_wr = {reg,val}; return f_ioctl (L502_PCI_IFACE_FILE(hnd), LPCIE_IOCTL_MEMFPGA_WR, &mem_wr, sizeof(mem_wr), NULL, 0, NULL, L502_IOCTL_TIMEOUT) ? X502_ERR_FPGA_REG_READ : 0; } int32_t l502_port_fpga_reg_read(t_x502_hnd hnd, uint32_t reg, uint32_t *val) { uint32_t rd_val; int32_t err = f_ioctl (L502_PCI_IFACE_FILE(hnd), LPCIE_IOCTL_MEMFPGA_RD, ®, sizeof(reg), &rd_val, sizeof(rd_val), NULL, L502_IOCTL_TIMEOUT); if (err != X502_ERR_OK) { err = X502_ERR_FPGA_REG_READ; } else if (val != NULL) { *val = rd_val; } return err; } int32_t l502_port_stream_set_params(t_x502_hnd hnd, t_lpcie_stream_ch_params *par) { return f_ioctl(L502_PCI_IFACE_FILE(hnd), LPCIE_IOCTL_STREAM_SET_PARAMS, par, sizeof(t_lpcie_stream_ch_params), NULL, 0, NULL, L502_IOCTL_TIMEOUT); } int32_t l502_port_stream_start(t_x502_hnd hnd, uint32_t ch, uint32_t single) { return f_ioctl(L502_PCI_IFACE_FILE(hnd), single ? LPCIE_IOCTL_STREAM_START_SINGLE : LPCIE_IOCTL_STREAM_START, &ch, sizeof(ch), NULL, 0, NULL, L502_IOCTL_TIMEOUT); } int32_t l502_port_stream_stop(t_x502_hnd hnd, uint32_t ch, uint32_t flags) { return f_ioctl(L502_PCI_IFACE_FILE(hnd), LPCIE_IOCTL_STREAM_STOP, &ch, sizeof(ch), NULL, 0, NULL, L502_IOCTL_TIMEOUT); } int32_t l502_port_stream_free(t_x502_hnd hnd, uint32_t ch, uint32_t flags) { return f_ioctl(L502_PCI_IFACE_FILE(hnd), LPCIE_IOCTL_STREAM_FREE, &ch, sizeof(ch), NULL, 0, NULL, L502_IOCTL_TIMEOUT); } int32_t l502_port_stream_rdy_size(t_x502_hnd hnd, uint32_t ch, uint32_t *rdy_size) { uint32_t rd_val; int32_t err = f_ioctl (L502_PCI_IFACE_FILE(hnd), LPCIE_IOCTL_STREAM_GET_RDY_SIZE, &ch, sizeof(ch), &rd_val, sizeof(rd_val), NULL, L502_IOCTL_TIMEOUT); if ((err == X502_ERR_OK) && (rdy_size != NULL)) *rdy_size = rd_val; return err; } int32_t l502_port_cycle_load_start(t_x502_hnd hnd, uint32_t ch, uint32_t size, uint32_t min_irq_step) { t_lpcie_cycle_set_par par; memset(&par, 0, sizeof(par)); par.ch = ch; par.size = size; par.irq_step = min_irq_step; return f_ioctl (L502_PCI_IFACE_FILE(hnd), LPCIE_IOCTL_CYCLE_LOAD, &par, sizeof(par), NULL, 0, NULL, L502_IOCTL_TIMEOUT); } int32_t l502_port_cycle_setup(t_x502_hnd hnd, uint32_t ch, uint32_t evt) { t_lpcie_cycle_evt_par par; memset(&par, 0, sizeof(par)); par.ch = ch; par.evt = evt; return f_ioctl (L502_PCI_IFACE_FILE(hnd), LPCIE_IOCTL_CYCLE_SWITCH, &par, sizeof(par), NULL, 0, NULL, L502_IOCTL_TIMEOUT); } int32_t l502_port_cycle_stop(t_x502_hnd hnd, uint32_t ch, uint32_t evt) { t_lpcie_cycle_evt_par par; memset(&par, 0, sizeof(par)); par.ch = ch; par.evt = evt; return f_ioctl (L502_PCI_IFACE_FILE(hnd), LPCIE_IOCTL_CYCLE_STOP, &par, sizeof(par), NULL, 0, NULL, L502_IOCTL_TIMEOUT); } int32_t l502_port_cycle_check_setup(t_x502_hnd hnd, uint32_t ch, uint32_t *done) { uint32_t rd_val; int32_t err = f_ioctl (L502_PCI_IFACE_FILE(hnd), LPCIE_IOCTL_CYCLE_CHECK_SETUP, &ch, sizeof(ch), &rd_val, sizeof(rd_val), NULL, L502_IOCTL_TIMEOUT); if ((err == X502_ERR_OK) && (done != NULL)) *done = rd_val; return err; } int32_t l502_port_renew_info(t_x502_hnd hnd) { return f_ioctl(L502_PCI_IFACE_FILE(hnd), LPCIE_IOCTL_RELOAD_DEVINFO, NULL, 0, NULL, 0, NULL, L502_IOCTL_TIMEOUT); } int32_t l502_port_get_drv_ver(t_x502_hnd hnd, uint32_t *ver) { uint32_t rd_val; int32_t err = f_ioctl (L502_PCI_IFACE_FILE(hnd), LPCIE_IOCTL_GET_DRV_VERSION, NULL, 0, &rd_val, sizeof(rd_val), NULL, L502_IOCTL_TIMEOUT); if ((err == X502_ERR_OK) && (ver != NULL)) *ver = rd_val; return err; } int32_t l502_port_stream_read(t_x502_hnd hnd, uint32_t* buff, uint32_t size, uint32_t timeout) { int send_size = 4*size; uint32_t NumberOfBytesRead = 0; int32_t err = X502_ERR_OK; OVERLAPPED Ov; // инициализируем OVERLAPPED структуру memset(&Ov, 0, sizeof(OVERLAPPED)); Ov.hEvent = CreateEvent(NULL, FALSE , FALSE, NULL); if(!Ov.hEvent) { err = X502_ERR_MEMORY_ALLOC; } if (err == X502_ERR_OK) { // посылаем асинхронный запрос на сбор необходимого кол-ва данных if(!ReadFile(L502_PCI_IFACE_FILE(hnd), buff, send_size, NULL, &Ov)) { if(GetLastError() != ERROR_IO_PENDING) { CancelIo(L502_PCI_IFACE_FILE(hnd)); CloseHandle(Ov.hEvent); err = X502_ERR_RECV; GetOverlappedResult(L502_PCI_IFACE_FILE(hnd), &Ov, &NumberOfBytesRead, TRUE); } } } // ждём окончания выполнения запроса if (err == X502_ERR_OK) { if (WaitForSingleObject(Ov.hEvent, timeout) == WAIT_TIMEOUT) { CancelIo(L502_PCI_IFACE_FILE(hnd)); CloseHandle(Ov.hEvent); GetOverlappedResult(L502_PCI_IFACE_FILE(hnd), &Ov, &NumberOfBytesRead, TRUE); } else if(!GetOverlappedResult(L502_PCI_IFACE_FILE(hnd), &Ov, &NumberOfBytesRead, TRUE)) { CancelIo(L502_PCI_IFACE_FILE(hnd)); CloseHandle(Ov.hEvent); err = X502_ERR_RECV; } else { CloseHandle(Ov.hEvent); } } return err != X502_ERR_OK ? err : NumberOfBytesRead/4; } int32_t l502_port_stream_write(t_x502_hnd hnd, const uint32_t* buff, uint32_t size, uint32_t timeout) { int send_size = 4*size; uint32_t NumberOfBytesRead = 0; int32_t err = X502_ERR_OK; OVERLAPPED Ov; // инициализируем OVERLAPPED структуру memset(&Ov, 0, sizeof(OVERLAPPED)); Ov.hEvent = CreateEvent(NULL, FALSE , FALSE, NULL); if(!Ov.hEvent) { err = X502_ERR_MEMORY_ALLOC; } if (err == X502_ERR_OK) { // посылаем асинхронный запрос на сбор необходимого кол-ва данных if(!WriteFile(L502_PCI_IFACE_FILE(hnd), buff, send_size, NULL, &Ov)) { if(GetLastError() != ERROR_IO_PENDING) { CancelIo(L502_PCI_IFACE_FILE(hnd)); CloseHandle(Ov.hEvent); err = X502_ERR_SEND; GetOverlappedResult(L502_PCI_IFACE_FILE(hnd), &Ov, &NumberOfBytesRead, TRUE); } } } // ждём окончания выполнения запроса if (err == X502_ERR_OK) { if (WaitForSingleObject(Ov.hEvent, timeout) == WAIT_TIMEOUT) { CancelIo(L502_PCI_IFACE_FILE(hnd)); CloseHandle(Ov.hEvent); GetOverlappedResult(L502_PCI_IFACE_FILE(hnd), &Ov, &NumberOfBytesRead, TRUE); } else if(!GetOverlappedResult(L502_PCI_IFACE_FILE(hnd), &Ov, &NumberOfBytesRead, TRUE)) { CancelIo(L502_PCI_IFACE_FILE(hnd)); CloseHandle(Ov.hEvent); err = X502_ERR_SEND; } else { CloseHandle(Ov.hEvent); } } return err != X502_ERR_OK ? err : NumberOfBytesRead/4; } static int32_t f_get_file_par(SP_DEVICE_INTERFACE_DETAIL_DATA *detail, TCHAR* filebuf, const TCHAR* file, char* res, uint32_t req_size, uint32_t* read_size) { HANDLE ifile; int32_t err = 0; _tcscpy(filebuf, TEXT(detail->DevicePath)); _tcscat(filebuf, file); ifile = CreateFile(filebuf, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); if (ifile != INVALID_HANDLE_VALUE) { DWORD read_cnt=0; if (!ReadFile(ifile, res, req_size, &read_cnt, NULL)) { err = X502_ERR_GET_INFO; } else { if (read_size!=NULL) *read_size = read_cnt; } CloseHandle(ifile); } else { err = X502_ERR_GET_INFO; } return err; } static int f_fill_devlist(SP_DEVICE_INTERFACE_DETAIL_DATA *detail, t_x502_devrec *info) { int32_t err = X502_ERR_OK; TCHAR *filename = malloc(sizeof(TCHAR)*21 + _tcslen(detail->DevicePath)); if (filename == NULL) { err = X502_ERR_MEMORY_ALLOC; } else { err = f_get_file_par(detail, filename, TEXT("\\name"), info->devname, sizeof(info->devname), NULL); if (err == X502_ERR_OK) { /* получаем серийный номер устройства */ err = f_get_file_par(detail, filename, TEXT("\\sn"), info->serial, sizeof(info->serial), NULL); } /* получаем информацию, открыто ли устройство */ if (err == X502_ERR_OK) { char val = '0'; f_get_file_par(detail, filename, TEXT("\\opened"), &val, 1, NULL); if (!err && (val!='0')) info->flags |= X502_DEVFLAGS_DEVREC_OPENED; } /* получаем информацию, присутствует ли BlackFin */ if (err == X502_ERR_OK) { char val = '0'; if ((f_get_file_par(detail, filename, TEXT("\\bf"), &val, 1, NULL)==0) && (val != '0')) { info->flags |= X502_DEVFLAGS_BF_PRESENT; } if ((f_get_file_par(detail, filename, TEXT("\\dac"), &val, 1, NULL)==0) && (val != '0')) { info->flags |= X502_DEVFLAGS_DAC_PRESENT; } if ((f_get_file_par(detail, filename, TEXT("\\gal"), &val, 1, NULL)==0) && (val != '0')) { info->flags |= X502_DEVFLAGS_GAL_PRESENT; } } if (err == X502_ERR_OK) { err = l502_devlist_gen(info, detail); } free(filename); } return err; } int32_t l502_port_free_iface_data(void *intptr) { free(intptr); return X502_ERR_OK; } int32_t l502_port_open(t_x502_hnd hnd, const t_x502_devrec *devinfo) { SP_DEVICE_INTERFACE_DETAIL_DATA *detail = (SP_DEVICE_INTERFACE_DETAIL_DATA *)devinfo->internal->iface_data; int32_t err = X502_ERR_OK; HANDLE file = CreateFile(detail->DevicePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if (file != INVALID_HANDLE_VALUE) { hnd->iface_data = malloc(sizeof(t_pci_iface_data)); if (hnd->iface_data == NULL) { err = X502_ERR_MEMORY_ALLOC; CloseHandle(file); } else { L502_PCI_IFACE_FILE(hnd) = file; } } else { DWORD syserr = GetLastError(); if (syserr == ERROR_ACCESS_DENIED) { err = X502_ERR_DEVICE_ACCESS_DENIED; } else if (syserr == ERROR_FILE_NOT_FOUND) { err = X502_ERR_DEVICE_NOT_FOUND; } else { err = X502_ERR_DEVICE_OPEN; } } return err; } int32_t l502_port_close(t_x502_hnd hnd) { if (hnd->iface_data !=NULL) { CloseHandle(L502_PCI_IFACE_FILE(hnd)); free(hnd->iface_data); hnd->iface_data = NULL; } return X502_ERR_OK; } X502_EXPORT(int32_t) L502_GetDevRecordsList(t_x502_devrec *list, uint32_t size, uint32_t flags, uint32_t *devcnt) { HDEVINFO infoSet; SP_DEVINFO_DATA infoData; DWORD index=0; uint32_t curcnt=0; int32_t err = X502_ERR_OK; infoData.cbSize = sizeof(SP_DEVINFO_DATA); /* получаем список устройств с подержкой интерфейса lpcie */ infoSet = SetupDiGetClassDevs(&GUID_LPCIE_INTERFACE,NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); /* проходимся по всем устройствам из списка */ while (SetupDiEnumDeviceInfo(infoSet, index, &infoData)) { SP_DEVICE_INTERFACE_DATA intfData; intfData.cbSize = sizeof(intfData); /* получаем информацию о интерфейсе */ if (SetupDiEnumDeviceInterfaces(infoSet, &infoData, &GUID_LPCIE_INTERFACE, 0, &intfData)) { DWORD req_size; /* узнаем резмер детальной информации о интерфейсе (нужна для получения имени устройства) */ if (!SetupDiGetDeviceInterfaceDetail(infoSet, &intfData, NULL, 0, &req_size, NULL) && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) { SP_DEVICE_INTERFACE_DETAIL_DATA* detail = (SP_DEVICE_INTERFACE_DETAIL_DATA*) malloc(req_size); if (detail != NULL) { int detail_used = 0; /* пытаемся получить всю информацию */ detail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); if (SetupDiGetDeviceInterfaceDetail(infoSet, &intfData, detail, req_size, NULL, NULL)) { t_x502_devrec info; int info_used = 0; detail_used = 1; X502_DevRecordInit(&info); /* получаем информацию о устройстве из служебных файлов, * предоставляемых драйвером */ if (f_fill_devlist(detail, &info) == X502_ERR_OK) { /* если нужны только не открытые, то уже открытое * устройство пропускаем */ if (!(flags & X502_GETDEVS_FLAGS_ONLY_NOT_OPENED) || !(info.flags & X502_DEVFLAGS_DEVREC_OPENED)) { /* если есть место в списке - то сохраняем * полученную информацию */ if ((list!=NULL) && (curcnt < size)) { list[curcnt] = info; info_used = 1; } curcnt++; } } if (!info_used) X502_FreeDevRecordList(&info,1); } if (!detail_used) { free(detail); } } else { err = X502_ERR_MEMORY_ALLOC; } } } index++; } if (infoSet != NULL) { SetupDiDestroyDeviceInfoList(infoSet); } if (devcnt != NULL) *devcnt = curcnt; return err != X502_ERR_OK ? err : curcnt > size ? size : curcnt ; }