Files
E502_ADC_BF_PC_companion/lib/l502/linux/l502_spec.c

370 lines
12 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 "../l502api_private.h"
#include "../lpcie_ioctls.h"
#include <sys/ioctl.h>
#include <linux/ioctl.h>
#include <linux/types.h>
#include <stdlib.h>
#include <dirent.h>
#include <libgen.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#define LPCIE_CLASS_DIR "/sys/class/lpcie"
static int32_t f_ioctl(int fd, unsigned long int req, void* val) {
return ioctl(fd, req, val) ? X502_ERR_IOCTL_FAILD : X502_ERR_OK;
}
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);
}
int32_t l502_port_fpga_reg_read(t_x502_hnd hnd, uint32_t reg, uint32_t *val) {
t_lpcie_mem_rw mem_wr = {reg,0};
int32_t err = f_ioctl (L502_PCI_IFACE_FILE(hnd), LPCIE_IOCTL_MEMFPGA_RD, &mem_wr);
if ((err == X502_ERR_OK) && (val != NULL))
*val = mem_wr.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);
}
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);
}
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);
}
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);
}
int32_t l502_port_stream_rdy_size(t_x502_hnd hnd, uint32_t ch, uint32_t *rdy_size) {
t_lpcie_get_rdy_par rdy_par = {ch,0};
int32_t err = f_ioctl (L502_PCI_IFACE_FILE(hnd), LPCIE_IOCTL_STREAM_GET_RDY_SIZE, &rdy_par);
if ((err == X502_ERR_OK) && (rdy_size != NULL))
*rdy_size = rdy_par.rdy_size;
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);
}
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);
}
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);
}
int32_t l502_port_cycle_check_setup(t_x502_hnd hnd, uint32_t ch, uint32_t *done) {
t_lpcie_cycle_check_setup_par par;
int32_t err;
memset(&par, 0, sizeof(par));
par.ch = ch;
err = f_ioctl(L502_PCI_IFACE_FILE(hnd), LPCIE_IOCTL_CYCLE_CHECK_SETUP, &par);
if (err == X502_ERR_OK)
*done = par.done;
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);
}
int32_t l502_port_get_drv_ver(t_x502_hnd hnd, uint32_t *ver) {
return f_ioctl(L502_PCI_IFACE_FILE(hnd), LPCIE_IOCTL_GET_DRV_VERSION, ver);
}
int32_t l502_port_stream_read(t_x502_hnd hnd, uint32_t *buff, uint32_t size, uint32_t timeout) {
struct timeval tmval = {timeout/1000, (timeout%1000)*1000};
uint32_t rcv_size = 0;
int out = 0;
int32_t err = X502_ERR_OK;
while (!out && (err == X502_ERR_OK) && (rcv_size < size)) {
fd_set rd_set;
int sel = 0;
FD_ZERO(&rd_set);
FD_SET(L502_PCI_IFACE_FILE(hnd), &rd_set);
sel = select(L502_PCI_IFACE_FILE(hnd)+1, &rd_set, NULL, NULL, &tmval);
if ((sel > 0) && (FD_ISSET(L502_PCI_IFACE_FILE(hnd), &rd_set))) {
ssize_t rd = read(L502_PCI_IFACE_FILE(hnd), &buff[rcv_size], (size-rcv_size)*4);
if (rd>0) {
rcv_size += rd/4;
} else if (rd == 0) {
out = 1;
} else {
err = X502_ERR_RECV;
}
} else if (sel==0) {
out = 1;
} else {
err = X502_ERR_RECV;
}
}
return err != X502_ERR_OK ? err : (int32_t)rcv_size;
}
int32_t l502_port_stream_write(t_x502_hnd hnd, const uint32_t *buff, uint32_t size,
uint32_t timeout) {
struct timeval tmval = {timeout/1000, (timeout%1000)*1000};
uint32_t snd_size = 0;
int32_t err = X502_ERR_OK;
int out = 0;
while (!out && (err == X502_ERR_OK) && (snd_size < size)) {
fd_set wr_set;
int sel = 0;
FD_ZERO(&wr_set);
FD_SET(L502_PCI_IFACE_FILE(hnd), &wr_set);
sel = select(L502_PCI_IFACE_FILE(hnd)+1, NULL, &wr_set, NULL, &tmval);
if ((sel > 0) && (FD_ISSET(L502_PCI_IFACE_FILE(hnd), &wr_set))) {
ssize_t wr = write(L502_PCI_IFACE_FILE(hnd), &buff[snd_size], (size-snd_size)*4);
if (wr > 0) {
snd_size += wr/4;
} else if (wr==0) {
out = 1;
} else {
err = X502_ERR_SEND;
}
} else if (sel==0) {
out = 1;
} else {
err = X502_ERR_SEND;
}
}
return err != X502_ERR_OK ? err : (int32_t)snd_size;
}
static int32_t f_get_file_par(const char *path, char *filebuf,
const char *file, char *res, uint32_t req_size,
uint32_t *read_size) {
int f;
int32_t err = X502_ERR_OK;
strcpy(filebuf, path);
strcat(filebuf, file);
f = open (filebuf, O_RDONLY);
if (f == -1) {
err = X502_ERR_GET_INFO;
} else {
ssize_t rd = read(f, res, req_size);
if (rd < 0) {
err = X502_ERR_GET_INFO;
} else {
if (read_size!=NULL)
*read_size = rd;
}
close(f);
}
return err;
}
static void f_del_eol(char *str) {
for ( ; *str; str++) {
if ((*str=='\n') || (*str=='\r'))
*str = '\0';
}
}
static int32_t f_fill_devlist(const char *devname, t_x502_devrec *info) {
int32_t err = 0;
int path_len = strlen(devname) + strlen(LPCIE_CLASS_DIR) + 2;
char *filename = malloc(path_len + 21);
char *path = malloc(path_len);
if ((filename != NULL) && (path != NULL)) {
sprintf(path, LPCIE_CLASS_DIR "/%s", devname);
err = f_get_file_par(path, filename, "/name", info->devname,
sizeof(info->devname), NULL);
if (err == X502_ERR_OK)
f_del_eol(info->devname);
if (err == X502_ERR_OK) {
/* получаем серийный номер устройства */
err = f_get_file_par(path, filename, "/sn", info->serial,
sizeof(info->serial), NULL);
if (err == X502_ERR_OK)
f_del_eol(info->serial);
}
/* получаем информацию, открыто ли устройство */
if (err == X502_ERR_OK) {
char val = '0';
err = f_get_file_par(path, filename, "/opened", &val, 1, NULL);
if ((err == X502_ERR_OK) && (val!='0'))
info->flags |= X502_DEVFLAGS_DEVREC_OPENED;
}
/* получаем информацию, присутствует ли BlackFin */
if (err == X502_ERR_OK) {
char val = '0';
if ((f_get_file_par(path, filename, "/bf", &val, 1, NULL) == X502_ERR_OK)
&& (val != '0')) {
info->flags |= X502_DEVFLAGS_BF_PRESENT;
}
if ((f_get_file_par(path, filename, "/dac", &val, 1, NULL) == X502_ERR_OK)
&& (val != '0')) {
info->flags |= X502_DEVFLAGS_DAC_PRESENT;
}
if ((f_get_file_par(path, filename, "/gal", &val, 1, NULL) == X502_ERR_OK)
&& (val != '0')) {
info->flags |= X502_DEVFLAGS_GAL_PRESENT;
}
}
if (err == X502_ERR_OK) {
char *devname_cpy = malloc(strlen(devname)+1);
if (devname_cpy!=NULL) {
strcpy(devname_cpy, devname);
err = l502_devlist_gen(info, devname_cpy);
if (err != X502_ERR_OK) {
free(devname_cpy);
}
} else {
err = X502_ERR_MEMORY_ALLOC;
}
}
} else {
err = X502_ERR_MEMORY_ALLOC;
}
free(filename);
free(path);
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) {
const char *devname = (const char *)devinfo->internal->iface_data;
int32_t err = X502_ERR_OK;
int path_len = strlen(devname)+6;
char *path = malloc(path_len);
if (path != NULL) {
int file;
snprintf(path, path_len, "/dev/%s", devname);
file = open(path, O_RDWR);
if (file != -1) {
hnd->iface_data = malloc(sizeof(t_pci_iface_data));
if (hnd->iface_data == NULL) {
err = X502_ERR_MEMORY_ALLOC;
close(file);
} else {
L502_PCI_IFACE_FILE(hnd) = file;
}
} else {
/** @todo Разобрать коды ошибок */
err = X502_ERR_DEVICE_OPEN;
}
free(path);
} else {
err = X502_ERR_MEMORY_ALLOC;
}
return err;
}
int32_t l502_port_close(t_x502_hnd hnd) {
if (hnd->iface_data !=NULL) {
close(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) {
uint32_t curcnt = 0;
int32_t err = X502_ERR_OK;
/* все устройства, поддерживаемые драйвером LPCIE, создают папку
в директории класса устройств lpcie*/
DIR *class_dir = opendir(LPCIE_CLASS_DIR);
if (class_dir!=NULL) {
struct dirent *dev_ent;
/* читаем все записи в директории класса */
while ((dev_ent=readdir(class_dir))!=NULL) {
/* проверяем, что имя начинается с lpcie */
if (!memcmp(dev_ent->d_name, "lpcie", sizeof("lpcie")-1)) {
t_x502_devrec info;
int info_used = 0;
X502_DevRecordInit(&info);
/* получаем информацию о устройстве из служебных файлов,
* предоставляемых драйвером */
if (f_fill_devlist(dev_ent->d_name, &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);
}
}
closedir(class_dir);
}
if (devcnt != NULL)
*devcnt = curcnt;
return err != X502_ERR_OK ? err : curcnt > size ? (int32_t)size : (int32_t)curcnt ;
}