184 lines
3.7 KiB
C
184 lines
3.7 KiB
C
/*
|
|
* This file is part of the Xilinx DMA IP Core driver tools for Linux
|
|
*
|
|
* Copyright (c) 2016-present, Xilinx, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This source code is licensed under BSD-style license (found in the
|
|
* LICENSE file in the root directory of this source tree)
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <unistd.h>
|
|
#include <time.h>
|
|
#include <errno.h>
|
|
#include <sys/types.h>
|
|
|
|
/*
|
|
* man 2 write:
|
|
* On Linux, write() (and similar system calls) will transfer at most
|
|
* 0x7ffff000 (2,147,479,552) bytes, returning the number of bytes
|
|
* actually transferred. (This is true on both 32-bit and 64-bit
|
|
* systems.)
|
|
*/
|
|
|
|
#define RW_MAX_SIZE 0x7ffff000
|
|
|
|
int verbose = 0;
|
|
|
|
uint64_t getopt_integer(char *optarg)
|
|
{
|
|
int rc;
|
|
uint64_t value;
|
|
|
|
rc = sscanf(optarg, "0x%lx", &value);
|
|
if (rc <= 0)
|
|
rc = sscanf(optarg, "%lu", &value);
|
|
//printf("sscanf() = %d, value = 0x%lx\n", rc, value);
|
|
|
|
return value;
|
|
}
|
|
|
|
ssize_t read_to_buffer(char *fname, int fd, char *buffer, uint64_t size,
|
|
uint64_t base)
|
|
{
|
|
ssize_t rc;
|
|
uint64_t count = 0;
|
|
char *buf = buffer;
|
|
off_t offset = base;
|
|
int loop = 0;
|
|
|
|
while (count < size) {
|
|
uint64_t bytes = size - count;
|
|
|
|
if (bytes > RW_MAX_SIZE)
|
|
bytes = RW_MAX_SIZE;
|
|
|
|
if (offset) {
|
|
rc = lseek(fd, offset, SEEK_SET);
|
|
if (rc != offset) {
|
|
fprintf(stderr, "%s, seek off 0x%lx != 0x%lx.\n",
|
|
fname, rc, offset);
|
|
perror("seek file");
|
|
return -EIO;
|
|
}
|
|
}
|
|
|
|
/* read data from file into memory buffer */
|
|
rc = read(fd, buf, bytes);
|
|
if (rc < 0) {
|
|
fprintf(stderr, "%s, read 0x%lx @ 0x%lx failed %ld.\n",
|
|
fname, bytes, offset, rc);
|
|
perror("read file");
|
|
return -EIO;
|
|
}
|
|
|
|
count += rc;
|
|
if (rc != bytes) {
|
|
fprintf(stderr, "%s, read underflow 0x%lx/0x%lx @ 0x%lx.\n",
|
|
fname, rc, bytes, offset);
|
|
break;
|
|
}
|
|
|
|
buf += bytes;
|
|
offset += bytes;
|
|
loop++;
|
|
}
|
|
|
|
if (count != size && loop)
|
|
fprintf(stderr, "%s, read underflow 0x%lx/0x%lx.\n",
|
|
fname, count, size);
|
|
return count;
|
|
}
|
|
|
|
ssize_t write_from_buffer(char *fname, int fd, char *buffer, uint64_t size,
|
|
uint64_t base)
|
|
{
|
|
ssize_t rc;
|
|
uint64_t count = 0;
|
|
char *buf = buffer;
|
|
off_t offset = base;
|
|
int loop = 0;
|
|
|
|
while (count < size) {
|
|
uint64_t bytes = size - count;
|
|
|
|
if (bytes > RW_MAX_SIZE)
|
|
bytes = RW_MAX_SIZE;
|
|
|
|
if (offset) {
|
|
rc = lseek(fd, offset, SEEK_SET);
|
|
if (rc != offset) {
|
|
fprintf(stderr, "%s, seek off 0x%lx != 0x%lx.\n",
|
|
fname, rc, offset);
|
|
perror("seek file");
|
|
return -EIO;
|
|
}
|
|
}
|
|
|
|
/* write data to file from memory buffer */
|
|
rc = write(fd, buf, bytes);
|
|
if (rc < 0) {
|
|
fprintf(stderr, "%s, write 0x%lx @ 0x%lx failed %ld.\n",
|
|
fname, bytes, offset, rc);
|
|
perror("write file");
|
|
return -EIO;
|
|
}
|
|
|
|
count += rc;
|
|
if (rc != bytes) {
|
|
fprintf(stderr, "%s, write underflow 0x%lx/0x%lx @ 0x%lx.\n",
|
|
fname, rc, bytes, offset);
|
|
break;
|
|
}
|
|
buf += bytes;
|
|
offset += bytes;
|
|
|
|
loop++;
|
|
}
|
|
|
|
if (count != size && loop)
|
|
fprintf(stderr, "%s, write underflow 0x%lx/0x%lx.\n",
|
|
fname, count, size);
|
|
|
|
return count;
|
|
}
|
|
|
|
|
|
/* Subtract timespec t2 from t1
|
|
*
|
|
* Both t1 and t2 must already be normalized
|
|
* i.e. 0 <= nsec < 1000000000
|
|
*/
|
|
static int timespec_check(struct timespec *t)
|
|
{
|
|
if ((t->tv_nsec < 0) || (t->tv_nsec >= 1000000000))
|
|
return -1;
|
|
return 0;
|
|
|
|
}
|
|
|
|
void timespec_sub(struct timespec *t1, struct timespec *t2)
|
|
{
|
|
if (timespec_check(t1) < 0) {
|
|
fprintf(stderr, "invalid time #1: %lld.%.9ld.\n",
|
|
(long long)t1->tv_sec, t1->tv_nsec);
|
|
return;
|
|
}
|
|
if (timespec_check(t2) < 0) {
|
|
fprintf(stderr, "invalid time #2: %lld.%.9ld.\n",
|
|
(long long)t2->tv_sec, t2->tv_nsec);
|
|
return;
|
|
}
|
|
t1->tv_sec -= t2->tv_sec;
|
|
t1->tv_nsec -= t2->tv_nsec;
|
|
if (t1->tv_nsec >= 1000000000) {
|
|
t1->tv_sec++;
|
|
t1->tv_nsec -= 1000000000;
|
|
} else if (t1->tv_nsec < 0) {
|
|
t1->tv_sec--;
|
|
t1->tv_nsec += 1000000000;
|
|
}
|
|
}
|