1. 程式人生 > 實用技巧 >ndis網絡卡驅動收發包

ndis網絡卡驅動收發包

嘗試描述ndis網絡卡驅動的收發包過程

  1. 設定一個_NDIS_MINIPORT_DRIVER_CHARACTERISTICS結構,包含初始化,處理中斷,發包等很多自己寫的handle,初作為引數提供給MRegisterMiniportDriver函式
  2. MRegisterMiniportDriver會首先呼叫其中初始化handle模型如下
    NDIS_STATUS MiniportInitialize(
    ...NDIS_HANDLE NdisMiniportHandle,
    ...NDIS_HANDLE MiniportDriverContext,
    ...PNDIS_MINIPORT_INIT_PARAMETERS MiniportInitParameters // 系統給我們提供的_NDIS_MINIPORT_INIT_PARAMETERS結構

    )
    其中_NDIS_MINIPORT_INIT_PARAMETERS結構裡包含一項 PNDIS_RESOURCE_LIST AllocatedResources, 這個AllocatedResources包含下面資料;
    switch (resource->Type) 【參考https://blog.csdn.net/xiangbaohui/article/details/105179813】
    {
    ... case CmResourceTypePort:
    ......Adapter->IoBaseAddress = resource->u.Port.Start ; // 得到了一個IoBaseAddress

    ......Adapter->IoRange = resource->u.Port.Length; //
    ...
    }
  3. 呼叫函式 NdisMRegisterIoPortRange去得到一個操控網絡卡的IO Port
    Status = NdisMRegisterIoPortRange(
    ... (PVOID *)&Adapter->PortOffset, // 返回一個portoffset,就是通過這個portoffset去操控硬體的,和以前的in out埠指令一樣
    ... Adapter->AdapterHandle,

    ... NdisGetPhysicalAddressLow ( Adapter->IoBaseAddress ) , // 上面我們得到的IoBaseAddress
    ... Adapter->IoRange);
  4. 有了上面的portoffset,我們可以給硬體下命令,設定收發包的地址,RxDescStartAddr和TxDescStartAddr都是【portoffset+暫存器偏移】,操作相應地址等於下相應的命令
    case SCB_RUC_LOAD_BASE : // 設定收包地址,為我們要收包的地址
    ... RTL_W32 ( RxDescStartAddr, NdisGetPhysicalAddressLow ( Adapter->HwRbdBasePa ) ); // 地址是自己分配的
    ... RTL_W32 ( RxDescStartAddr + 4, NdisGetPhysicalAddressHigh ( Adapter->HwRbdBasePa ));
    case SCB_TBD_LOAD_BASE : // 設定發包地址,寫地址【portoffset+暫存器偏移】為我們要發包的地址
    ... RTL_W32 ( TxDescStartAddr, NdisGetPhysicalAddressLow ( Adapter->HwTbdBasePa ) ); // 地址是自己分配的
    ... RTL_W32 ( TxDescStartAddr + 4, NdisGetPhysicalAddressHigh ( Adapter->HwTbdBasePa ) );
  5. 地址設定好了,以後
    【 收包 - 網絡卡寫資料到收包地址,生成一箇中斷,通知驅動程式的中斷處理函式去取資料 】
    【 發包 - 我們把資料寫到發包地址,通過portoffset通知網絡卡去取資料 】
    =================================================================================================================

大概流程如此,從系統得到一個portoffset,通過給portoffset下相應的命令,來完成對應的工作 (以前都是通過cpu的In out指令下的命令)。
-- 設定收發包地址(所謂的地址其實是一連串的地址描述符,下面)
-- 收包 - 資料寫入後,產生硬體中斷,通知我們去取
-- 發包 - 資料寫好後,給portoffset下對應指令,讓網絡卡去發

傳給網絡卡的地址,參考 https://blog.csdn.net/hz5034/article/details/79794615這篇文章
設定的收發包地址,是一串的連續的描述符,addr->[描述符][描述符][描述符].N個.[描述符],把這個addr通過portoffset下命令傳給網絡卡,網絡卡或是dma能夠認識這個描述符的,他們會自動工作。
描述符的結構大概如下:
typedef struct _TBD_STRUC { // 發包的描述符, 一個包一個描述符
... UINT16 FrameLength ;
... UINT16 status;
... UINT32 notused;
... UINT32 TbdBufferAddress; // 網絡卡會去這個地址取發包的資料
... UINT32 TbdBufferAddressHigh ;
} TBD_STRUC, *PTBD_STRUC;

typedef struct _RTK_RECEIVE_BUFFER_DESCRIPOR_STRUC { // 收包的描述符,網絡卡會挨個往裡面的buf_addr地址寫資料
... UINT32 status;
... UINT32 vlan_tag;
... UINT32 buf_addr; // 網絡卡會把資料寫到這個地址
... UINT32 buf_Haddr;
} HW_RBD, *PHW_RBD;

參考:NDIS 6.0的miniport裝置驅動 ---- http://www.codesoso.com/code/NDIS-miniport-driver.aspx