一、整个过程
打开设备 → 建通道 → 绑定 → 连接 → 收发 → 关闭 → 查状态
所有 .c 文件里最终都会落到这些命令,连接两块板卡 100% 用到:
一、最核心:用户态直接调用的 IOCTL 接口(必背)
所有 .c 文件里最终都会落到这些命令,连接两块板卡 100% 用到:
c
运行
// 通道生命周期
RIO_CM_CHAN_CREATE // 创建通道(必须第一个调用)
RIO_CM_CHAN_BIND // 绑定本地板卡ID/端口
RIO_CM_CHAN_LISTEN // 服务端:监听连接
RIO_CM_CHAN_ACCEPT // 服务端:接受连接
RIO_CM_CHAN_CONNECT // 客户端:主动连接
RIO_CM_CHAN_CLOSE // 关闭通道
// 数据收发
RIO_CM_CHAN_SEND // 发送数据
RIO_CM_CHAN_RECEIVE // 接收数据
// 状态查询(排查问题必用)
RIO_CM_EP_GET_LIST_SIZE // 获取板卡端点数量
RIO_CM_EP_GET_LIST // 获取所有端点信息(ID/端口)
RIO_CM_MPORT_GET_LIST // 获取物理端口状态
RIO_CM_CHAN_GET_STATUS // 获取通道当前状态
这些是跨所有 .c 文件的统一入口,不管驱动代码多复杂,用户态只用这一套。
二、必须掌握的 关键结构体(填参数就靠它)
所有 .c 文件都会传递这些结构体,你写连接代码必须定义它们:
c
运行
// 1. 通道创建
struct rio_cm_chan {
int chan_id; // 通道ID
};
// 2. 绑定本地板卡(核心!)
struct rio_cm_bind {
u16 local_id; // 本地 RapidIO 地址 ID
u8 local_port; // 本地端口号
u8 dev_id; // 设备号
};
// 3. 客户端连接目标板卡(核心!)
struct rio_cm_connect {
u16 remote_id; // 目标板卡 ID
u8 remote_port; // 目标端口
int timeout; // 连接超时
};
// 4. 监听(服务端)
struct rio_cm_listen {
int backlog; // 最大等待连接数
};
// 5. 数据收发(核心!)
struct rio_cm_msg {
void *buf; // 数据缓冲区
u32 len; // 数据长度
};
✅ 记住:连接板卡 = 填这几个结构体 + 调用 IOCTL
三、内核层关键函数(所有 .c 文件都会用到)
你不用全看懂,但知道它们干嘛用,就能快速定位问题:
1. 通道相关(riocm_channel.c)
rio_cm_chan_create():创建通道内核对象rio_cm_chan_bind():绑定硬件端口rio_cm_chan_listen():启动监听rio_cm_chan_accept():建立连接rio_cm_chan_connect():发起连接rio_cm_chan_close():关闭并释放资源
2. 数据收发(riocm_msg.c)
rio_cm_msg_send():发送报文rio_cm_msg_receive():接收报文rio_cm_msg_queue():消息队列管理
3. 硬件与拓扑查询(riocm_main.c)
rio_cm_get_ep_list():获取全网板卡列表rio_cm_get_mport_list():获取本地物理端口rio_cm_dev_init():驱动初始化
4. 底层 RapidIO 协议(rio.c)
rio_open()/rio_close():设备打开关闭rio_read()/rio_write():底层寄存器读写rio_phys_connect():物理链路建立
四、两块板卡连接的最简万能流程
不管代码在多少个 .c 文件里,真实干活就 7 步:
服务端(板卡 A,被动等待)
open("/dev/rio_cm")RIO_CM_CHAN_CREATERIO_CM_CHAN_BIND(填本地 ID、端口)RIO_CM_CHAN_LISTENRIO_CM_CHAN_ACCEPT(阻塞等客户端)SEND / RECEIVE通信CLOSE
客户端(板卡 B,主动连接)
open("/dev/rio_cm")RIO_CM_CHAN_CREATERIO_CM_CHAN_BIND(本地 ID、端口)RIO_CM_CHAN_CONNECT(填对方 ID、端口)SEND / RECEIVECLOSE
五、直接能上手的最小接口集
open()RIO_CM_CHAN_CREATERIO_CM_CHAN_BINDRIO_CM_CHAN_LISTENRIO_CM_CHAN_ACCEPTRIO_CM_CHAN_CONNECTRIO_CM_CHAN_SENDRIO_CM_CHAN_RECEIVERIO_CM_CHAN_CLOSEclose()
六、可直接用的示例代码框架
客户端示例(主动连接)
#include <stdio.h>//负责打印输入
#include <stdlib.h>//负责内存退出
#include <unistd.h>//Linux系统调用(close)等
#include <fcntl.h>//打开文件
#include <sys/ioctl.h>//和硬件通信时的核心接口
#include "rio.h" // 驱动头文件,包含IOCTL命令和结构体定义
int main() {
int fd = open("/dev/rio_cm", O_RDWR);
if (fd < 0) {
perror("open failed");
return -1;
}
// 1. 创建通道
struct rio_cm_chan chan;
if (ioctl(fd, RIO_CM_CHAN_CREATE, &chan) < 0) {
perror("create chan failed");
close(fd);
return -1;
}
// 2. 绑定本地地址(本地RapidIO ID=0x1,端口=1)
struct rio_cm_bind bind_info = {
.local_id = 0x1,
.local_port = 1,
.dev_id = 0
};
if (ioctl(fd, RIO_CM_CHAN_BIND, &bind_info) < 0) {
perror("bind failed");
close(fd);
return -1;
}
// 3. 连接服务端(服务端RapidIO ID=0x2,端口=1)
struct rio_cm_connect connect_info = {
.remote_id = 0x2,
.remote_port = 1,
.timeout = 5000 // 超时5秒
};
if (ioctl(fd, RIO_CM_CHAN_CONNECT, &connect_info) < 0) {
perror("connect failed");
close(fd);
return -1;
}
printf("连接服务端成功!\n");
// 4. 发送数据
char send_buf[1024] = "Hello from Client!";
struct rio_cm_msg send_msg = {
.buf = send_buf,
.len = strlen(send_buf)
};
if (ioctl(fd, RIO_CM_CHAN_SEND, &send_msg) < 0) {
perror("send failed");
close(fd);
return -1;
}
// 5. 接收响应
char recv_buf[1024];
struct rio_cm_msg recv_msg = {
.buf = recv_buf,
.len = sizeof(recv_buf)
};
if (ioctl(fd, RIO_CM_CHAN_RECEIVE, &recv_msg) < 0) {
perror("receive failed");
close(fd);
return -1;
}
printf("收到服务端响应: %s\n", recv_buf);
// 6. 关闭连接
close(fd);
return 0;
}
服务端示例(被动连接)
c
运行
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include "rio.h"
int main() {
int listen_fd = open("/dev/rio_cm", O_RDWR);
if (listen_fd < 0) {
perror("open failed");
return -1;
}
// 1. 创建监听通道
struct rio_cm_chan chan;
if (ioctl(listen_fd, RIO_CM_CHAN_CREATE, &chan) < 0) {
perror("create listen chan failed");
close(listen_fd);
return -1;
}
// 2. 绑定本地地址(本地RapidIO ID=0x2,端口=1)
struct rio_cm_bind bind_info = {
.local_id = 0x2,
.local_port = 1,
.dev_id = 0
};
if (ioctl(listen_fd, RIO_CM_CHAN_BIND, &bind_info) < 0) {
perror("bind failed");
close(listen_fd);
return -1;
}
// 3. 开始监听
struct rio_cm_listen listen_info = {
.backlog = 5 // 监听队列长度
};
if (ioctl(listen_fd, RIO_CM_CHAN_LISTEN, &listen_info) < 0) {
perror("listen failed");
close(listen_fd);
return -1;
}
printf("等待客户端连接...\n");
// 4. 接受连接(阻塞)
int conn_fd = ioctl(listen_fd, RIO_CM_CHAN_ACCEPT, NULL);
if (conn_fd < 0) {
perror("accept failed");
close(listen_fd);
return -1;
}
printf("客户端连接成功!\n");
// 5. 接收客户端数据
char recv_buf[1024];
struct rio_cm_msg recv_msg = {
.buf = recv_buf,
.len = sizeof(recv_buf)
};·
if (ioctl(conn_fd, RIO_CM_CHAN_RECEIVE, &recv_msg) < 0) {
perror("receive failed");
close(conn_fd);
close(listen_fd);
return -1;
}
printf("收到客户端消息: %s\n", recv_buf);
// 6. 发送响应
char send_buf[1024] = "Hello from Server!";
struct rio_cm_msg send_msg = {
.buf = send_buf,
.len = strlen(send_buf)
};
if (ioctl(conn_fd, RIO_CM_CHAN_SEND, &send_msg) < 0) {
perror("send failed");
close(conn_fd);
close(listen_fd);
return -1;
}
// 7. 关闭连接
close(conn_fd);
close(listen_fd);
return 0;
}