【嵌入式linux】网口和USB热插拔检测

在Linux常常需要对网口和USB等外设接口进行插拔检测,从而执行部分初始化操作。下面简要介绍Linux的Netlink机制,并在C程序中使用Linux的Netlink机制完成网口和USB口插拔检测

Netlink 是 Linux 内核与用户空间进程通信的一种机制,主要用于内核模块和用户程序之间的数据传输。它比传统的通信方式(如 ioctl、procfs、sysfs)更灵活高效。
一、主要特点
双向通信:支持内核与用户空间的双向数据传输。
多协议支持:通过不同的协议类型(如 NETLINK_ROUTE、NETLINK_SOCK_DIAG)满足多种通信需求。
多播支持:允许一个消息同时发送给多个接收者。
异步通信:支持异步消息传递,适合事件驱动场景。
二、使用场景
网络配置:如 iproute2 工具通过 Netlink 配置网络接口和路由。
防火墙和策略路由:如 iptables 和 nftables 使用 Netlink 配置规则。
设备管理:如 udev 通过 Netlink 监控设备事件。
三、基本使用步骤
1.创建套接字:用户空间使用 socket() 创建 Netlink 套接字。

int sock_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);

2.绑定地址:绑定 Netlink 地址。

struct sockaddr_nl addr;
memset(&addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK;
addr.nl_pid = getpid(); // 通常使用进程ID
bind(sock_fd, (struct sockaddr*)&addr, sizeof(addr));

3.发送和接收消息:使用 sendmsg() 和 recvmsg() 进行消息传递。
4.处理消息:解析和处理接收到的消息。

Demo1:使用Netlink实现网口热插拔。(ZYNQ-7020平台,linux内核为4.19)


#include <sys/socket.h>
#include <linux/if.h>
#include <linux/rtnetlink.h>
#include <linux/netlink.h>
typedef void (*network_status_callback)(char *eth_name,int status) ;
void network_link_monitor(network_status_callback arg)
{
	int sock;
	int ret;
	struct sockaddr_nl sa;
	int len=4096;
	char buf[4096]={0};
	struct nlmsghdr *nh;
	struct ifinfomsg  *ifinfo;
	struct rtattr *attr;
	network_status_callback nm=arg;
	int i;
	memset(&sa,0,sizeof(sa));
	sa.nl_family=AF_NETLINK;
	sa.nl_groups=RTNLGRP_LINK;
	//sa.nl_pid=getpid();
	
	//创建套接字和绑定Netlink地址,这里使用NETLINK_ROUTE
	sock=socket(AF_NETLINK,SOCK_RAW,NETLINK_ROUTE);
	if(sock<0)
		printf("socket err %d\n",__LINE__);
	setsockopt(sock,SOL_SOCKET,SO_RCVBUF,&len,sizeof(len));
	if(bind(sock,(struct sockaddr*)&sa,sizeof(sa))<0)
		printf("bind err %d\n",__LINE__);
		
	//阻塞接收内核的Netlink消息,可根据应用需求使用非阻塞IO读
	while((ret=read(sock,buf,sizeof(buf)))>0)
	{
		for(nh=(struct nlmsghdr*)buf;NLMSG_OK(nh,ret);nh=NLMSG_NEXT(nh,ret))
		{
			//解析和处理接收到的内核消息
			if(nh->nlmsg_type==NLMSG_DONE)
				break;
			else if(nh->nlmsg_type==NLMSG_ERROR)
			{
				printf("read err %d\n",__LINE__);
				return ;
			}
			else if (nh->nlmsg_type!=RTM_NEWLINK)
			{
				printf("nlmsg_type err %d\n",__LINE__);
				continue;
			}
			ifinfo=NLMSG_DATA(nh);
			//printf("%u : %s \n",ifinfo->ifi_index,(ifinfo->ifi_flags&IFF_LOWER_UP)?"UP":"DOWN");
			attr=(struct rtattr*)(((char*)nh)+NLMSG_SPACE(sizeof(*ifinfo)));
			len=nh->nlmsg_len-NLMSG_SPACE(sizeof(*ifinfo));
			for(;RTA_OK(attr,len);attr=RTA_NEXT(attr,len))
			{
				if(attr->rta_type==IFLA_IFNAME)
				{
					//执行热插拔检测回调函数
					//printf("%s : %s\n",(char*)RTA_DATA(attr),(ifinfo->ifi_flags&IFF_LOWER_UP)?"up":"down");
					if(ifinfo->ifi_flags&IFF_LOWER_UP)
						nm((char*)RTA_DATA(attr),LINK_UP);
					else
						nm((char*)RTA_DATA(attr),LINK_DOWN);
					break;
				}
			}
		}
	}
}

/*
网络插拔检测回调
*/
void monitor_callback(char *eth_name,int status)//status--1 up
{
	printf("%s %s\n",eth_name,status?"up":"down");
}

int main()
{
	printf("net test\n");
    network_link_monitor(monitor_callback);
	while(1)sleep(1);    
    return 0;
}

编译Demo生成net_test拷贝到板子上
测试结果:重复插拔网口可看到内核打印信息和应用程序打印网口up和down信息
在这里插入图片描述
Demo2:使用Netlink实现USB口热插拔。(ZYNQ-7020平台,linux内核为4.19)

static void usb_host_thread(void *arg)
{
	char rcv_buf[32]={0};
	int link_status=0;
    int ret=0;
    //判断USB口初始拔插状态
    ret=usb_exec(USB_HOST_CMD);
    if(ret==0)
        link_status=1;
    else
        link_status=0;
    struct sockaddr_nl client;
    struct timeval tv;
    int CppLive,rcvlen;
    fd_set fds;
    int buffersize=1024;
    //创建套接字和绑定Netlink地址,这里使用NETLINK_KOBJECT_UEVENT
    CppLive=socket(AF_NETLINK,SOCK_RAW,NETLINK_KOBJECT_UEVENT);
	if(CppLive<0)
	{
	    printf("socket err %d\n",__LINE__);
        return;
    }
    memset(&client,0,sizeof(client));
    client.nl_family=AF_NETLINK;
    //client.nl_pid=getpid();
    client.nl_groups=1;
    setsockopt(CppLive,SOL_SOCKET,SO_RCVBUF,&buffersize,sizeof(buffersize));
    bind(CppLive,(struct sockaddr*)&client,sizeof(client));
    while(1)
	{
        char buf[2048]={0};
        /*
        FD_ZERO(&fds);
        FD_SET(CppLive,&fds);
        tv.tv_sec=0;
        tv.tv_usec=100 * 1000;
        ret=select(CppLive+1,&fds,NULL,NULL,&tv);
        if(ret<0)
        {
            printf("select err %d\n",__LINE__);
            continue;
        }
            
        if(!(ret>0 && FD_ISSET(CppLive, &fds)))
        {
            printf("select err %d\n",__LINE__);
            continue;
        }
        */  
        //阻塞接收内核的Netlink消息,可根据应用需求使用非阻塞IO读
        rcvlen=recv(CppLive,buf,sizeof(buf),0);
        if(rcvlen > 0)
        {
        	//解析和处理接收到的内核消息
            //printf("%s\n",buf);
            if(strstr(buf,"add")!=NULL)
            {
                if(link_status==0)
                {
                    ((void (*)(int))arg)(1);
                }
                link_status=1;
            }
            else if(strstr(buf,"remove")!=NULL)
            {
                if(link_status==1)
                {
                    ((void (*)(int))arg)(0);
                }
                link_status=0;
            }
        }
            
	}
	
}

void callback(int status)
{
	if(status==1)
		printf("usb host up\n");
	if(status==0)
		printf("usb host down\n");
}

int main()
{
	printf("usb test\n");
    usb_host_monitor(callback);
	while(1)sleep(1);    
    return 0;
}

编译Demo生成usb_test拷贝到板子上
测试结果:重复插拔USB host口可看到应用程序打印USB口的up和down信息
在这里插入图片描述

### 米联科开发板 USB3.0 驱动支持分析 米联科开发板在设计过程中采用了多种接口形式以满足不同场景的需求。对于USB3.0的支持,主要体现在以下几个方面: #### 1. **硬件层面的设计** 开发板上的传统DB9接口因体积较大被替换为Mini USB接口[^1],这表明其对外部设备的连接更加注重小型化便捷性。然而,具体到USB3.0的支持情况,需确认开发板所使用的主控芯片是否具备原生USB3.0控制器功能。 如果开发板确实集成了USB3.0控制器,则通常会在产品文档中明确说明,并提供相应的驱动程序支持文件。如果没有特别提及USB3.0的支持,则可能仅限于USB2.0标准下的数据传输能力。 #### 2. **软件驱动支持** 针对USB3.0的驱动支持问题,一般情况下,现代操作系统(如Windows、Linux)已内置了对主流USB3.0控制器的通用驱动支持。这意味着大多数基于XHCI(eXtensible Host Controller Interface)规范的USB3.0控制器无需额外安装专用驱动即可正常工作。 但在某些特定应用场景下,尤其是涉及高速外设或特殊功能模块时,仍需要依赖厂商提供的定制化驱动程序。例如,在嵌入式系统开发环境中,开发者可能需要手动配置内核选项或将第三方驱动集成至目标平台的操作系统镜像中[^3]。 #### 3. **注意事项与操作建议** 当使用USB接口进行调试或其他操作时,应注意遵循正确的连接顺序以防损毁硬件组件。比如,JTAG端子不支持热插拔特性,因此应在断电状态下完成所有必要的物理连线后再给开发板供电[^2]。虽然USB本身允许热插拔,但仍推荐按照上述流程执行以最大限度保护设备安全。 另外,若计划利用千兆以太网RJ45网口开展网络通信测试活动,则应确保相关外围电路均已正确初始化并达到稳定运行状态——即观察到对应的指示灯点亮现象后方可继续后续步骤。 ```bash # 示例命令:检查Linux系统中的USB设备列表 lsusb ``` 以上脚本可用于初步判断当前主机是否识别到了预期类型的USB装置及其版本号信息。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值