Files
E502_ADC_BF_PC_companion/l502/win/l502_spec.c

508 lines
19 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <Windows.h>
#include <SetupAPI.h>
#include <initguid.h>
#include <stddef.h>
#include <tchar.h>
#include "../l502api_private.h"
#include <winioctl.h>
/* 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, &reg, 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 ;
}