设备和适配器初始化

本主题介绍 NetAdapterCx 客户端驱动程序初始化以及启动 WDFDEVICE 和 NETADAPTER 对象的步骤。 有关这些对象及其关系的详细信息,请参阅 NetAdapterCx 对象的摘要

EVT_WDF_DRIVER_DEVICE_ADD

NetAdapterCx 客户端驱动程序从其 DriverEntry 例程调用 WdfDriverCreate 时,会注册其 EVT_WDF_DRIVER_DEVICE_ADD 回调函数。

EVT_WDF_DRIVER_DEVICE_ADD 中,NetAdapterCx 客户端驱动程序应依次执行以下操作:

  1. 调用 NetDeviceInitConfig

    status = NetDeviceInitConfig(DeviceInit);
    if (!NT_SUCCESS(status)) 
    {
        return status;
    }
    
  2. 调用 WdfDeviceCreate

    提示

    如果设备支持多个 NETADAPTER,则建议在设备上下文中存储指向每个适配器的指针。

  3. 创建 NETADAPTER 对象。 为此,客户端会调用 NetAdapterInitAllocate,然后调用可选的 NetAdapterInitSetXxx 方法来初始化适配器的属性。 最后,客户端会调用 NetAdapterCreate

    以下示例显示了客户端驱动程序如何初始化 NETADAPTER 对象。 请注意,本例中的错误处理进行了简化。

    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attribs, MY_ADAPTER_CONTEXT);
    
    //
    // Allocate the initialization structure
    //
    PNETADAPTER_INIT adapterInit = NetAdapterInitAllocate(device);
    if(adapterInit == NULL)
    {
        return status;
    }        
    
    //
    // Optional: set additional attributes
    //
    
    // Datapath callbacks for creating packet queues
    NET_ADAPTER_DATAPATH_CALLBACKS datapathCallbacks;
    NET_ADAPTER_DATAPATH_CALLBACKS_INIT(&datapathCallbacks,
                                        MyEvtAdapterCreateTxQueue,
                                        MyEvtAdapterCreateRxQueue);
    NetAdapterInitSetDatapathCallbacks(adapterInit,
                                       datapathCallbacks);
    // 
    // Required: create the adapter
    //
    NETADAPTER* netAdapter;
    status = NetAdapterCreate(adapterInit, &attribs, netAdapter);
    if(!NT_SUCCESS(status))
    {
        NetAdapterInitFree(adapterInit);
        adapterInit = NULL;
        return status;
    }
    
    //
    // Required: free the adapter initialization object even 
    // if adapter creation succeeds
    //
    NetAdapterInitFree(adapterInit);
    adapterInit = NULL;
    
    //
    // Optional: initialize the adapter's context
    //
    PMY_ADAPTER_CONTEXT adapterContext = GetMyAdapterContext(&netAdapter);
    ...
    

还可以为 NETADAPTER 对象添加上下文空间。 由于可以在任何 WDF 对象上设置上下文,因此可以为 WDFDEVICE 和 NETADAPTER 对象添加单独的上下文空间。 在步骤 3 的示例中,客户端将 MY_ADAPTER_CONTEXT 添加到 NETADAPTER 对象中。 有关详细信息,请参阅框架对象上下文空间

建议将与设备相关的数据放在 WDFDEVICE 上下文中,并将与网络相关的数据(如链路层地址)放在 NETADAPTER 上下文中。 如果正在移植现有的 NDIS 6.x 驱动程序,则可能会有一个 MiniportAdapterContext,它会将网络相关数据和设备相关数据合并到一个数据结构中。 为了简化移植过程,只需将整个结构转换为 WDFDEVICE 上下文,并使 NETADAPTER 的上下文成为一个指向 WDFDEVICE 上下文的小型结构。

可以选择向 NET_ADAPTER_DATAPATH_CALLBACKS_INIT 方法提供 2 个回调:

有关在实现这些回调时应提供哪些功能的详细信息,请参阅各参考页面。

EVT_WDF_DEVICE_PREPARE_HARDWARE

许多 NetAdapterCx 客户端驱动程序都是从 EVT_WDF_DEVICE_PREPARE_HARDWARE 回调函数中启动适配器的,但移动宽带类扩展客户端驱动程序是个明显的例外。 要注册 EVT_WDF_DEVICE_PREPARE_HARDWARE 回调函数,NetAdapterCx 客户端驱动程序必须调用 WdfDeviceInitSetPnpPowerEventCallbacks

EVT_WDF_DEVICE_PREPARE_HARDWARE 中,除了其他硬件准备任务外,客户端驱动程序还会设置适配器的必要和可选功能。

NetAdapterCx 要求客户端驱动程序设置以下功能:

然后,驱动程序必须调用 NetAdapterStart 来启动其适配器。

以下示例显示了客户端驱动程序如何启动 NETADAPTER 对象。 请注意,为简洁明了起见,设置每个适配器功能方法所需的代码已省略,错误处理也经过了简化。

PMY_DEVICE_CONTEXT deviceContext = GetMyDeviceContext(device);

NETADAPTER netAdapter = deviceContext->NetAdapter;

PMY_ADAPTER_CONTEXT adapterContext = GetMyAdapterContext(netAdapter);

//
// Set required adapter capabilities
//

// Link layer capabilities
...
NetAdapterSetDatapathCapabilities(netAdapter,
                                  &txCapabilities,
                                  &rxCapabilities);
...
NetAdapterSetLinkLayerCapabilities(netAdapter,
                                   &linkLayerCapabilities);
...
NetAdapterSetLinkLayerMtuSize(netAdapter,
                              MY_MAX_PACKET_SIZE - ETHERNET_HEADER_LENGTH);

//
// Set optional adapter capabilities
//

// Link layer capabilities
...
NetAdapterSetPermanentLinkLayerAddress(netAdapter,
                                       &adapterContext->PermanentAddress);
...
NetAdapterSetCurrentLinkLayerAddress(netAdapter,
                                     &adapterContext->CurrentAddress);

// Datapath capabilities
...
NetAdapterSetDatapathCapabilities(netAdapter,
                                  &txCapabilities,
                                  &rxCapabilities);

// Receive scaling capabilities
...
NetAdapterSetReceiveScalingCapabilities(netAdapter,
                                        &receiveScalingCapabilities);

// Hardware offload capabilities
...
NetAdapterOffloadSetChecksumCapabilities(netAdapter,
                                         &checksumCapabilities);
...
NetAdapterOffloadSetLsoCapabilities(netAdapter,
                                    &lsoCapabilities);
...
NetAdapterOffloadSetRscCapabilities(netAdapter,
                                    &rscCapabilities);

//
// Required: start the adapter
//
status = NetAdapterStart(netAdapter);
if(!NT_SUCCESS(status))
{
    return status;
}