SRIO通信总线

一、整个过程

打开设备 → 建通道 → 绑定 → 连接 → 收发 → 关闭 → 查状态

所有 .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,被动等待)

  1. open("/dev/rio_cm")
  2. RIO_CM_CHAN_CREATE
  3. RIO_CM_CHAN_BIND(填本地 ID、端口)
  4. RIO_CM_CHAN_LISTEN
  5. RIO_CM_CHAN_ACCEPT(阻塞等客户端)
  6. SEND / RECEIVE 通信
  7. CLOSE

客户端(板卡 B,主动连接)

  1. open("/dev/rio_cm")
  2. RIO_CM_CHAN_CREATE
  3. RIO_CM_CHAN_BIND(本地 ID、端口)
  4. RIO_CM_CHAN_CONNECT(填对方 ID、端口)
  5. SEND / RECEIVE
  6. CLOSE

五、直接能上手的最小接口集

  1. open()
  2. RIO_CM_CHAN_CREATE
  3. RIO_CM_CHAN_BIND
  4. RIO_CM_CHAN_LISTEN
  5. RIO_CM_CHAN_ACCEPT
  6. RIO_CM_CHAN_CONNECT
  7. RIO_CM_CHAN_SEND
  8. RIO_CM_CHAN_RECEIVE
  9. RIO_CM_CHAN_CLOSE
  10. close()

六、可直接用的示例代码框架

客户端示例(主动连接)

复制代码
#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;
}
相关推荐
lq12332102 小时前
Windows文件搜索工具 WizFile v3.14
windows
Warren982 小时前
Windows 本地安装 Jenkins 教程
linux·运维·windows·功能测试·mysql·jenkins
汤愈韬2 小时前
ip-prefix(IP前缀列表)
linux·服务器·网络协议·tcp/ip
deviant-ART2 小时前
win11首次使用, 如何跳过微软账号登录
windows·微软
SPC的存折8 小时前
1、Redis数据库基础
linux·运维·服务器·数据库·redis·缓存
小疙瘩9 小时前
只是记录自己发布若依分离系统到linux过程中遇到的问题
linux·运维·服务器
我是伪码农11 小时前
外卖餐具智能推荐
linux·服务器·前端
透明的玻璃杯11 小时前
window环境下使用类似tail的命令跟踪滚动的日志
windows
私人珍藏库11 小时前
【windows】跨平台 Android 刷机Root工具箱
android·windows·工具·刷机·软件·多功能