设备和适配器初始化
本主题介绍 NetAdapterCx 客户端驱动程序初始化以及启动 WDFDEVICE 和 NETADAPTER 对象的步骤。 有关这些对象及其关系的详细信息,请参阅 NetAdapterCx 对象的摘要。
EVT_WDF_DRIVER_DEVICE_ADD
NetAdapterCx 客户端驱动程序从其 DriverEntry 例程调用 WdfDriverCreate 时,会注册其 EVT_WDF_DRIVER_DEVICE_ADD 回调函数。
在 EVT_WDF_DRIVER_DEVICE_ADD 中,NetAdapterCx 客户端驱动程序应依次执行以下操作:
-
status = NetDeviceInitConfig(DeviceInit); if (!NT_SUCCESS(status)) { return status; }
调用 WdfDeviceCreate。
提示
如果设备支持多个 NETADAPTER,则建议在设备上下文中存储指向每个适配器的指针。
创建 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 要求客户端驱动程序设置以下功能:
数据路径功能。 驱动程序会调用 NetAdapterSetDataPathCapabilities 来设置这些功能。 有关详细信息,请参阅网络数据缓冲区管理。
链接层功能。 驱动程序会调用 NetAdapterSetLinkLayerCapabilities 来设置这些功能。
链路层最大传输单元 (MTU) 大小。 驱动程序会调用 NetAdapterSetLinkLayerMtuSize 来设置 MTU 大小。
然后,驱动程序必须调用 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;
}