SylixOS网卡驱动调用篇

SylixOS网卡驱动调用篇


1.开发环境

  • 操作系统:SylixOS
  • 编程环境:RealEvo-IDE3.1
  • 硬件平台:IMX6Q实验箱

2.技术实现

《SylixOS网卡驱动框架篇》里提过,网卡驱动的收发功能是通过netdev结构里的transmit和receive两个成员实现的。本篇文章将介绍SylixOS里的LWIP协议栈是如何调用底层网卡驱动里的这两个成员函数的。


2.1 网卡发送函数的调用

整个网卡驱动发送函数的调用关系如图 2-1 所示。
SylixOS网卡驱动调用篇_第1张图片
图2-1

网卡驱动在向SylixOS注册网卡驱动时,需要调用netdev_add函数,这个函数接收一个netdev结构的参数。因为在网卡驱动初始化过程中,已经在底层驱动里实现了netdev下的transmit和receive两个成员。所以netdev_add函数可以通过netdev这个参数找到驱动里的收发功能函数。

netdev_add函数里会调用netifapi_netif_add 来添加API函数,netifapi_netif_add接收的一个函数参数是netdev_netif_init。netifapi_netif_add函数最终会调用netdev_netif_init函数。

netdev_netif_init函数会把netdev_netif_linkoutput赋值给netif结构体下的linkoutput。netdev_netif_linkoutput的具体实现如程序清单 2-1 所示。

LWIP协议栈里最终调用到底层驱动时,就是通过netif的linkoutput实现的,如程序清单 2 1所示,netdev_netif_linkoutput会调用宏NETDEV_TRANSMIT,这个宏的实现如程序清单 2 2 所示。NETDEV_TRANSMIT会调用netdev里的transmit成员函数来进行数据包的发送。

程序清单2-1 netdev_netif_linkoutput函数

/* lwip netif linkoutput hook function */
static err_t  netdev_netif_linkoutput (struct netif *netif, struct pbuf *p)
{
  netdev_t *netdev = (netdev_t *)(netif->state);
  int ret;

#if ETH_PAD_SIZE
  pbuf_header(p, -ETH_PAD_SIZE);
#endif

  ret = NETDEV_TRANSMIT(netdev, p);

#if ETH_PAD_SIZE
  pbuf_header(p, ETH_PAD_SIZE);
#endif

  if (ret < 0) {
    return (ERR_IF);
  }
  return (ERR_OK);
}

程序清单2-2 NETDEV_TRANSMIT

 #define NETDEV_TRANSMIT(netdev, a)      (netdev)->drv->transmit((netdev), a)

2.2 网卡接收函数的调用

《SylixOS网卡驱动实现篇》里提到过,网卡驱动里的接收中断使用netdev_notify函数来通知协议栈已经收到数据,并让协议栈调用netdev的receive成员函数来进行接收报文的处理。

接收处理函数enetCoreRecv里接收两个参数,一个是netdev结构体,另一个是input类型的函数。

netdev_notify的具体实现如程序清单 2 3 所示,里面会通过q_en这个参数来决定是否使用队列的方式来接收,如果不使用,则直接调用宏NETDEV_RECEIVE,否则通过netJobAdd把接收处理函数添加到队列中。不管哪一种方式,最后都会调用netdev下的receive成员函数,而receive的第二个input类型的参数就是程序清单 2 3 中的netdev_netif_linkinput。

因此,底层驱动的接收处理函数会通过netdev_netif_linkinput把网卡收到的数据一层层的传到协议栈中去进行对应的处理。

程序清单 2 3 netdev_notify函数

/* if netdev detected a packet in netdev buffer, driver can call this function to receive this packet.
   notify:0 can transmit 1: can receive 
   qen:0 do not use netjob queue 1:use netjob queue */
int  netdev_notify (struct netdev *netdev, netdev_inout inout, int q_en)
{
  if (!netdev || (netdev->magic_no != NETDEV_MAGIC)) {
    return (-1);
  }

  if (inout != LINK_INPUT) {
    return (0);
  }

  if (q_en) {
    if (netJobAdd(netdev->drv->receive, netdev, 
                  (void *)netdev_netif_linkinput, 0, 0, 0, 0) == 0) {
      return (0);

    } else {
      return (-1);
    }
  }

  NETDEV_RECEIVE(netdev, netdev_netif_linkinput);

  return (0);
} 

参考资料


你可能感兴趣的:(操作系统,网卡驱动,操作系统,网卡)