#include #include #include #include #include #include // 函数:从设备读取数据到本地内存(缓冲区) // 功能:实现设备到主机的数据传输 // 参数: // dev_fd : 设备实例句柄 // addr : 设备中的源地址 // buffer : 缓冲区基指针 // size : 数据大小 // 返回值: // 成功:0;失败:-1 int dev_read (int dev_fd, uint64_t addr, void *buffer, uint64_t size) { if ( addr != lseek(dev_fd, addr, SEEK_SET) ) // 调整文件偏移到指定地址 return -1; // 偏移失败 if ( size != read(dev_fd, buffer, size) ) // 从设备读取数据到缓冲区 return -1; // 读取失败 return 0; } // 函数:从本地内存(缓冲区)写数据到设备 // 功能:实现主机到设备的数据传输 // 参数: // dev_fd : 设备实例句柄 // addr : 设备中的目标地址 // buffer : 缓冲区基指针 // size : 数据大小 // 返回值: // 成功:0;失败:-1 int dev_write (int dev_fd, uint64_t addr, void *buffer, uint64_t size) { if ( addr != lseek(dev_fd, addr, SEEK_SET) ) return -1; if ( size != write(dev_fd, buffer, size) ) return -1; return 0; } // 函数:获取毫秒级别的时间 // 功能:返回当前时间的毫秒数 static uint64_t get_millisecond () { struct timeb tb; ftime(&tb); return (uint64_t)tb.millitm + (uint64_t)tb.time * 1000UL; // tb.time is the number of seconds since 00:00:00 January 1, 1970 UTC time; // tb.millitm is the number of milliseconds in a second } // 函数:解析无符号整数 // 功能:从字符串中解析出十六进制或十进制的无符号64位整数 // 参数: // string : 输入的字符串 // pvalue : 解析后的值的指针 // 返回值: // 成功解析的项数,失败则为0 int parse_uint (char *string, uint64_t *pvalue) { if ( string[0] == '0' && string[1] == 'x' ) // 十六进制格式"0xXXXXXXXX" return sscanf( &(string[2]), "%lx", pvalue); else // 十进制格式 return sscanf( string , "%lu", pvalue); } #define DMA_MAX_SIZE 0x10000000UL // DMA操作的最大尺寸定义 256kb char USAGE[] = "Usage: \n" "\n" " 写入设备(主机到设备):\n" " %s <文件名> to <设备名> <设备内地址> <大小>\n" " 示例:\n" " %s data.bin to /dev/xdma0_h2c_0 0x100000 0x10000\n" "\n" " 读取设备(设备到主机):\n" " %s <文件名> from <设备名> <设备内地址> <大小>\n" " 示例:\n" " %s data.bin from /dev/xdma0_c2h_0 0x100000 0x10000\n"; int main (int argc, char *argv[]) { int ret = -1; uint64_t millisecond; char usage_string [1024]; char *dev_name, *file_name; char direction; uint64_t address, size; int dev_fd = -1; FILE *file_p = NULL; void *buffer = NULL; sprintf(usage_string, USAGE, argv[0], argv[0], argv[0], argv[0] ); if (argc < 6) { // not enough argument puts(usage_string); return -1; } file_name = argv[1]; direction = argv[2][0]; dev_name = argv[3]; if ( 0 == parse_uint(argv[4], &address) ) { // parse the address in the device puts(usage_string); return -1; } if ( 0 == parse_uint(argv[5], &size ) ) { // parse the size in the device puts(usage_string); return -1; } // print information: if (direction == 't') { // to (write device, host-to-device) printf("from : %s\n" , file_name); printf("to : %s addr=0x%lx\n" , dev_name, address); printf("size : 0x%lx\n\n" , size); } else if (direction == 'f') { // from (read device, device-to-host) printf("from : %s addr=0x%lx\n" , dev_name, address); printf("to : %s\n" , file_name); printf("size : 0x%lx\n\n" , size); } else { puts(usage_string); return -1; } if (size > DMA_MAX_SIZE || size == 0) { printf("*** ERROR: DMA size must larger than 0 and NOT be larger than %lu\n", DMA_MAX_SIZE); return -1; } buffer = malloc(size); // allocate local memory (buffer) if (buffer == NULL) { printf("*** ERROR: failed to allocate buffer\n"); goto close_and_clear; } dev_fd = open(dev_name, O_RDWR); // open device if (dev_fd < 0) { printf("*** ERROR: failed to open device %s\n", dev_name); goto close_and_clear; } file_p = fopen(file_name, direction == 't' ? "rb" : "wb"); // open file for read/write if (file_p == NULL) { printf("*** ERROR: failed to open file %s\n", file_name); goto close_and_clear; } millisecond = get_millisecond(); // start time if (direction == 't') { if ( size != fread(buffer, 1, size, file_p) ) { // local file -> local buffer printf("*** ERROR: failed to read %s\n", file_name); goto close_and_clear; } if ( dev_write(dev_fd, address, buffer, size) ) { // local buffer -> device printf("*** ERROR: failed to write %s\n", dev_name); goto close_and_clear; } } else { if ( dev_read(dev_fd, address, buffer, size) ) { // device -> local buffer printf("*** ERROR: failed to read %s\n", dev_name); goto close_and_clear; } if ( size != fwrite(buffer, 1, size, file_p) ) { // local buffer -> local file printf("*** ERROR: failed to write %s\n", file_name); goto close_and_clear; } } millisecond = get_millisecond() - millisecond; // get time consumption millisecond = (millisecond > 0) ? millisecond : 1; // avoid divide-by-zero printf("time=%lu ms data rate=%.1lf KBps\n", millisecond, (double)size / millisecond ); ret = 0; close_and_clear: if (buffer != NULL) free(buffer); if (dev_fd >= 0) close(dev_fd); if (file_p != NULL) fclose(file_p); return ret; } int main(int argc, char *argv[]) { int ret = -1; // 初始化返回值为-1,表示程序可能运行失败 uint64_t millisecond; // 用于存储操作所花费的毫秒数 char usage_string[1024]; // 存储程序使用说明的字符串 char *dev_name, *file_name; // 分别指向设备名和文件名的指针 char direction; // 存储传输方向的字符,'t' 表示写入设备,'f' 表示读取设备 uint64_t address, size; // 存储设备地址和传输数据大小 int dev_fd = -1; // 设备文件描述符,初始设置为-1表示未打开设备 FILE *file_p = NULL; // 文件指针,初始为NULL void *buffer = NULL; // 数据缓冲区指针,初始为NULL // 根据程序名和命令行参数构造使用说明字符串 sprintf(usage_string, USAGE, argv[0], argv[0], argv[0], argv[0]); // 检查命令行参数数量是否足够 if (argc < 6) { puts(usage_string); // 打印使用说明 return -1; // 参数不足,退出程序 } // 解析命令行参数 file_name = argv[1]; direction = argv[2][0]; dev_name = argv[3]; // 解析设备地址和数据大小,如果解析失败则打印使用说明并退出 if (parse_uint(argv[4], &address) == 0) { puts(usage_string); return -1; } if (parse_uint(argv[5], &size) == 0) { puts(usage_string); return -1; } // 根据传输方向打印操作信息 if (direction == 't') { printf("从: %s\n至: %s 地址=0x%lx\n大小: 0x%lx\n", file_name, dev_name, address, size); } else if (direction == 'f') { printf("从: %s 地址=0x%lx\n至: %s\n大小: 0x%lx\n", dev_name, address, file_name, size); } else { puts(usage_string); return -1; // 无效的方向参数 } // 检查数据大小是否合法 if (size > DMA_MAX_SIZE || size == 0) { printf("*** 错误: DMA大小必须大于0且不超过 %lu\n", DMA_MAX_SIZE); return -1; } // 分配缓冲区 buffer = malloc(size); if (buffer == NULL) { printf("*** 错误: 分配缓冲区失败\n"); goto close_and_clear; // 跳转到资源释放部分 } // 打开设备 dev_fd = open(dev_name, O_RDWR); if (dev_fd < 0) { printf("*** 错误: 打开设备 %s 失败\n", dev_name); goto close_and_clear; } // 打开文件 file_p = (direction == 't') ? fopen(file_name, "rb") : fopen(file_name, "wb"); if (file_p == NULL) { printf("*** 错误: 打开文件 %s 失败\n", file_name); goto close_and_clear; } // 记录操作开始时间 millisecond = get_millisecond(); // 根据传输方向进行读写操作 if (direction == 't') { // 写入设备 if (fread(buffer, 1, size, file_p) != size) { printf("*** 错误: 读取文件 %s 失败\n", file_name); goto close_and_clear; } if (dev_write(dev_fd, address, buffer, size)) { printf("*** 错误: 写入设备 %s 失败\n", dev_name); goto close_and_clear; } } else { // 读取设备 if (dev_read(dev_fd, address, buffer, size)) { printf("*** 错误: 读取设备 %s 失败\n", dev_name); goto close_and_clear; } if (fwrite(buffer, 1, size, file_p) != size) { printf("*** 错误: 写入文件 %s 失败\n", file_name); goto close_and_clear; } } // 计算并打印操作耗时和数据传输速率 millisecond = get_millisecond() - millisecond; millisecond = (millisecond > 0) ? millisecond : 1; // 避免除以零错误 printf("耗时=%lu 毫秒 数据速率=%.1lf KB/s\n", millisecond, (double)size / millisecond / 1024); ret = 0; // 如果一切正常,设置返回值为0,表示成功 close_and_clear: // 清理资源标签 // 释放缓冲区 if (buffer != NULL) free(buffer); // 关闭设备文件 if (dev_fd >= 0) close(dev_fd); // 关闭文件 if (file_p != NULL) fclose(file_p); return ret; // 返回程序执行结果 }