Device and adapter initialization
This topic describes the steps for a NetAdapterCx client driver to initialize and start WDFDEVICE and NETADAPTER objects. For more info about these objects and their relationship, see Summary of NetAdapterCx objects.
EVT_WDF_DRIVER_DEVICE_ADD
A NetAdapterCx client driver registers its EVT_WDF_DRIVER_DEVICE_ADD callback function when it calls WdfDriverCreate from its DriverEntry routine.
In EVT_WDF_DRIVER_DEVICE_ADD, a NetAdapterCx client driver should do the following in order:
Call NetDeviceInitConfig.
status = NetDeviceInitConfig(DeviceInit); if (!NT_SUCCESS(status)) { return status; }
Call WdfDeviceCreate.
Tip
If your device supports more than one NETADAPTER, we recommend storing pointers to each adapter in your device context.
Create the NETADAPTER object. To do so, the client calls NetAdapterInitAllocate, followed by optional NetAdapterInitSetXxx methods to initialize the adapter's attributes. Finally, the client calls NetAdapterCreate.
The following example shows how a client driver might initialize a NETADAPTER object. Note that error handling is simplified in this example.
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); ...
Optionally, you can add context space to the NETADAPTER object. Since you can set a context on any WDF object, you could add separate context space for the WDFDEVICE and the NETADAPTER objects. In the example in step 3, the client adds MY_ADAPTER_CONTEXT
to the NETADAPTER object. For more info, see Framework Object Context Space.
We recommend that you put device-related data in the context for your WDFDEVICE, and networking-related data such as link layer addresses into your NETADAPTER context. If you are porting an existing NDIS 6.x driver, you'll likely have a single MiniportAdapterContext that combines networking-related and device-related data into a single data structure. To simplify the porting process, just convert that entire structure to the WDFDEVICE context, and make the NETADAPTER's context a small structure that points to the WDFDEVICE's context.
You can optionally provide 2 callbacks to the NET_ADAPTER_DATAPATH_CALLBACKS_INIT method:
For details on what to provide in your implementations of these callbacks, see the individual reference pages.
EVT_WDF_DEVICE_PREPARE_HARDWARE
Many NetAdapterCx client drivers start their adapters from within their EVT_WDF_DEVICE_PREPARE_HARDWARE callback function, with the notable exception of Mobile Broadband class extension client drivers. To register an EVT_WDF_DEVICE_PREPARE_HARDWARE callback function, a NetAdapterCx client driver must call WdfDeviceInitSetPnpPowerEventCallbacks.
Within EVT_WDF_DEVICE_PREPARE_HARDWARE, in addition to other hardware preparation tasks the client driver sets the adapter's required and optional capabilities.
NetAdapterCx requires the client driver to set the following capabilities:
Data path capabilities. The driver calls NetAdapterSetDataPathCapabilities to set these capabilities. For more information, see Network data buffer management.
Link layer capabilities. The driver calls NetAdapterSetLinkLayerCapabilities to set these capabilities.
Link layer maximum transfer unit (MTU) size. The driver calls NetAdapterSetLinkLayerMtuSize to set the MTU size.
The driver must then call NetAdapterStart to start their adapter.
The following example shows how a client driver might start a NETADAPTER object. Note that code required for setting up each adapter capabilities method is left out for brevity and clarity, and error handling is simplified.
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;
}