RTEMS 网络驱动的一些分析和理解

Network 的 demo 是独立提供的,所以应该自己去官网ftp里面下载。

network-demos-4.10.2\netdemo 里面的例子是最原始的,所以应该以这个作为切入点。

首先rtems_bsdnet_config 必须由用户自己提供,这个可以提供一个用户配置接口的机会,一些 init 中必须配置的选项

#define CONFIGURE_USE_IMFS_AS_BASE_FILESYSTEM

#define CONFIGURE_EXECUTIVE_RAM_SIZE(512*1024)

#define CONFIGURE_MAXIMUM_SEMAPHORES 20

#define CONFIGURE_MAXIMUM_TASKS      20

#define CONFIGURE_LIBIO_MAXIMUM_FILE_DESCRIPTORS20

必须有文件系统的支持,一般使用 IMFS 就行,配置工作RAM的大小,必须大于 256K(当然了,如果非常熟悉协议栈,则还可以根据实际项目精简的)必须配置信号量,和任务数,最后FILE_DESCRIPTORS 也是必须提供的,因为创建socket 实际上使用的文件系统中的file descriptor。

注意一下, netdemo 中的还配置了 init 相关的东西,因为他的demo在init中演示,所以要适配一下,例如修改 init的优先级为 120,不然的话,init默认优先级是1,网络demon优先级100就根本无法运行了。还有属性什么的,大概了解就行了,和网络本身无关。

 

1)分析 structrtems_bsdnet_config  的定义

可以看到,ifconfig,是否使用bootp,是必须提供的,其他的参数可以保持0,则使用默认值,其中 ifconfig 是指具体attach 到网络的网卡的一些属性,这个也是必须提供的,而且比较重要,可以有多个网卡设备,通过 ifconfig 的链表连接在一起,每个独立的网卡都通过rtems_bsdnet_ifconfig 结构来描述。其他的属性比如配置网络后台程序的优先级,默认是 100,mbuf缓冲的大小,cluster的大小等,默认是 64K,128k,所有网络的处理获取空间是通过 mbuf 来进行的,所以这个直接影响网络应用,还有 gateway,等,可以自己提供,也可以通过 bootp自动获取,还有 tcp ,udp 时候的缓冲区大小,可以看出,用rtems做网络应用的时候,应该至少提供 256K 的RAM给网络协议栈。当然,这个不是硬性规定,这个是根据实际剪裁的,当然前提是很熟悉整个架构。

 

可以这么理解rtems_bsdnet_config 配置的是系统(rtems本身)所处的网络的环境,服务器ip,网关等,而不涉及网卡本身的属性,因为系统可以配置多张网卡的,而认为多张网卡同处于同一个网络环境中,但是各自有各自的IP,掩码等属性。而具体网卡通过链表struct rtems_bsdnet_ifconfig *ifconfig; 连起来,形成一个整体的网络环境。

 

2)rtems_bsdnet_ifconfig的分析

之前说了,每个网卡都有独立的配置文件,通过rtems_bsdnet_ifconfig 结构体来完成,这个也是开发网络驱动的时候必须重点关注的,其中 name 表示网卡的名字,一般取  eth0 之类的就行了,int           (*attach)(structrtems_bsdnet_ifconfig *conf, int attaching); 函数就比较重要了,是网卡驱动必须提供的,连接网卡驱动和网络协议栈的桥梁。然后 netx 是指向下一个网卡的rtems_bsdnet_ifconfig 描述文件,其他参数可以默认也可以自己配置,就是网卡的IP,netmask,MAC地址,参数,buffer大小等等。drv_ctrl 则是一个void* 类型的成员,指向网卡本身的控制结构,这样就可以将驱动的参数在协议栈中传递了,驱动的其他地方也会用到,这样就不需要用结构体。

 

用户必须提供的结构体就是这2个了。然后初始化的时候需要执行网络初始化函数rtems_bsdnet_initialize_network (); 执行初始化。

 

 

下面说说网络驱动的架构

随便找个驱动来看看就行了,例如\libbsp\arm\csb336\network

int rtems_mc9328mxl_enet_attach (

   struct rtems_bsdnet_ifconfig *config,

   void *chip  /* only one ethernet,so no chip number */

    )

{

前面说了,必须提供一个 attach 函数,将网络驱动和协议栈连接起来,config 就是用户提供的 rtems_bsdnet_ifconfig 结构,

 

struct ifnet *ifp;

ifp = &softc.arpcom.ac_if;

   if (ifp->if_softc != NULL) {

       printf ("Driver already in use.\n");

       return 0;

}

 Softc就是一个全局网络驱动,一般是不直接使用的,因为存在互斥问题,一般是注册进struct inet 结构当中在网络协议栈中传递

ifp->if_softc = &softc;

   ifp->if_unit = unitnumber;

   ifp->if_name = unitname;

   ifp->if_mtu = mtu;

   ifp->if_init = mc9328mxl_enet_init;

   ifp->if_ioctl = mc9328mxl_enet_ioctl;

   ifp->if_start = mc9328mxl_enet_start;

   ifp->if_output = ether_output;

   ifp->if_flags = IFF_BROADCAST;

   if (ifp->if_snd.ifq_maxlen == 0) {

       ifp->if_snd.ifq_maxlen = ifqmaxlen;

}

/* Attach theinterface */

    if_attach (ifp);

    ether_ifattach (ifp);

这些是必须提供的函数,主要是初始化和ioctl,而start则在协议栈准备好数据的时候执行,让网卡发送数据,接收数据则因为是中断驱动的异步结构,所以是不需要在这里做的。最后执行协议栈内部函数将具体的网卡描述结构传入到协议栈中

 

void mc9328mxl_enet_init(void *arg)

初始化函数,根据 task_id 判断是否第一次进入。如果是,则初始化硬件,创建发送和接收任务,最后ifp->if_flags |= IFF_RUNNING; 让协议栈知道网卡驱动准备好了,启动网卡的发送和接收硬件。

 

void mc9328mxl_enet_start(struct ifnet*ifp)

{

   mc9328mxl_enet_softc_t *sc = ifp->if_softc;

 

   rtems_bsdnet_event_send(sc->tx_task, START_TRANSMIT_EVENT);

   ifp->if_flags |= IFF_OACTIVE;

}

协议栈准备好数据了,则开始发送,这里指需要发送event,然后准备为oactive,则发送任务收到event后就开始发送了。

 

void mc9328mxl_enet_tx_task(void *arg)

发送任务,首先是一个循环,等待event,这个是 start 发过来的,接着IF_DEQUEUE(&ifp->if_snd, m); 得到一个需要发送的数据包,注意,数据包可能有多个,通过链表连接起来,所以必须循环多次,ifp->if_flags &= ~IFF_OACTIVE; 发送完之后设置标志。

 

void mc9328mxl_enet_rx_task(void *arg)

首先,同样是等待event,而这里不同,这个event 是从接收中断中发来的。然后准备 mbuf 的数据包,最后调用ether_input(ifp, eh, m); 将数据包交给网络协议栈分析,它的事就做完了。

 

mc9328mxl_enet_ioctl (struct ifnet *ifp,ioctl_command_t command, caddr_t data)

注意是实现几个标志位的使用,还是统计网络参数,基本可以照抄的。

 

static void enet_isr(void * unused)

几种情况,发送完毕后,则发送START_TRANSMIT_EVENT,提示发送任务继续发送,如果是接收中断,则发送START_RECEIVE_EVENT ,让接收任务工作,如果是错误,则统计,中断上下文中,不要做其他操作,只应该发event,否则可能涉及原子上下文的问题。

你可能感兴趣的:(RTEMS 网络驱动的一些分析和理解)