编写 MBBCx 客户端驱动程序

警告

本主题中的序列图仅用于说明目的。 它们不是公共合同,将来可能会更改。

MBBCx 客户端驱动程序的 INF 文件

MBBCx 客户端驱动程序的 INF 文件与其他 NetAdapterCx 客户端驱动程序相同。 有关详细信息,请参阅 NetAdapterCx 客户端驱动程序的 INF 文件

遵循 通用指南 ,确保 INF 文件满足通用要求。

初始化设备

除了 NetAdapterCx 为 NetAdapter 设备初始化所需的任务外,MBB 客户端驱动程序还必须在其 EvtDriverDeviceAdd 回调函数中执行以下任务:

  1. 在调用 NetDeviceInitConfig 之后但在调用 WdfDeviceCreate 之前调用MBB_DEVICE_CONFIG_INIT,引用框架传入的同一WDFDEVICE_INIT对象。

  2. 调用 MbbDeviceInitialize 以使用初始化 MBB_DEVICE_CONFIG 结构和从 WdfDeviceCreate 获取的 WDFDEVICE 对象注册 MBB 设备特定的回调函数。

以下示例演示如何初始化 MBB 设备。 为清楚起见,已排除错误处理。

    status = NetDeviceInitConfig(deviceInit);
    status = MbbDeviceInitConfig(deviceInit);

    // Set up other callbacks such as Pnp and Power policy

    status = WdfDeviceCreate(&deviceInit, &deviceAttributes, &wdfDevice);

    MBB_DEVICE_CONFIG mbbDeviceConfig;
    MBB_DEVICE_CONFIG_INIT(&mbbDeviceConfig,
                           EvtMbbDeviceSendMbimFragment,
                           EvtMbbDeviceReceiveMbimFragment,
                           EvtMbbDeviceSendServiceSessionData,
                           EvtMbbDeviceCreateAdapter);

    status = MbbDeviceInitialize(wdfDevice, &mbbDeviceConfig);

与其他类型的 NetAdapterCx 驱动程序不同,MBB 客户端驱动程序不得从 EvtDriverDeviceAdd 回调函数中创建 NETADAPTER 对象。 相反,MBBCx 稍后会指示它这样做。

接下来,客户端驱动程序必须调用 MbbDeviceSetMbimParameters,通常在后面的 EvtDevicePrepareHardware 回调函数中。

此消息流图说明了初始化过程。

显示 MBBCx 客户端驱动程序初始化过程的示意图。

此消息流图说明了初始化过程。

显示 MBBCx 客户端驱动程序初始化过程的示意图。

处理 MBIM 控制消息

MBBCx 对控制平面使用 MBIM 规范修订版 1.0 第 8、9 和 10 节中定义的标准 MBIM 控制命令。 命令和响应通过客户端驱动程序提供的一组回调函数和 MBBCx 提供的 API 进行交换。 MBBCx 使用以下函数调用模拟 MBIM 设备的操作模型,如 MBIM 规范 Rev 1.0 第 5.3 节中定义:

  • MBBCx 通过调用其 EvtMbbDeviceSendMbimFragment 回调函数向客户端驱动程序发送 MBIM 命令消息。 客户端驱动程序通过调用 MbbRequestComplete 异步完成此发送请求。
  • 客户端驱动程序通过调用 MbbDeviceResponseAvailable 来指示结果的可用性。
  • MBBCx 通过调用其 EvtMbbDeviceReceiveMbimFragment 回调函数从客户端驱动程序提取 MBIM 响应消息。 客户端驱动程序通过调用 MbbRequestCompleteWithInformation 异步完成此 get-response 请求。
  • MBB 客户端驱动程序可以通过调用 MbbDeviceResponseAvailable 来通知 MBBCx 有关未经请求的设备事件。 然后,MBBCx 从客户端驱动程序检索信息的方式与提取 MBIM 响应消息的方式类似。

下图演示了 MBBCx 客户端驱动程序消息交换流。

显示 MBBCx 与客户端驱动程序之间的 MBIM 消息交换的示意图。

MBIM 控制消息的同步

MBBCx 框架始终将调用序列化到客户端驱动程序的 EvtMbbDeviceSendMbimFragmentEvtMbbDeviceReceiveMbimFragment 回调函数中。 在客户端驱动程序调用 MbbRequestComplete 或 MbbRequestCompleteWithInformation 之前,框架不会进行新的调用。

虽然客户端驱动程序保证不会接收重叠的 EvtMbbDeviceSendMbimFragmentEvtMbbDeviceReceiveMbimFragment 回调,但它可能会在设备提供对前一命令的响应之前连续接收对它们的多个调用。

如果设备不处于 D0 状态,MBBCx 框架将首先将设备引入 D0 (,即调用 EvtDeviceD0Entry) ,然后调用 EvtMbbDeviceSendMbimFragmentEvtMbbDeviceReceiveMbimFragment。 MBBCx 框架还保证设备保持 D0 状态,这意味着在客户端调用 MbbRequestCompleteMbbRequestCompleteWithInformation 之前,它不会调用 EvtDeviceD0Exit

为 PDP 上下文/EPS 持有者创建 NetAdapter 接口

在建立数据会话之前,MBBCx 将指示客户端驱动程序创建 NETADAPTER 对象,MBBCx 将使用该对象来表示已激活的数据会话的网络接口。 这是通过 MBBCx 调用客户端驱动程序的 EvtMbbDeviceCreateAdapter 回调函数来实现的。

EvtMbbDeviceCreateAdapter 回调函数的实现中,MBBCx 客户端驱动程序必须首先执行与任何 NetAdapterCx 客户端驱动程序一样创建 NETADAPTER 对象所需的相同任务。 此外,它还必须执行以下附加任务:

  1. 对 NetAdapterCreate 创建的 NETADAPTER 对象调用 MbbAdapterInitialize

  2. 调用 MbbAdapterinitialize 后,调用 MbbAdapterGetSessionId 以检索 MBBCx 打算使用此 NETADAPTER 对象的数据会话 ID。 例如,如果返回的值为 0,则表示 MBBCx 将使用此 NETADAPTER 接口作为由主 PDP 上下文/默认 EPS 持有者建立的数据会话。

  3. 建议 MBBCx 客户端驱动程序在创建的 NETADAPTER 对象和返回的 SessionId 之间保留内部映射。 这有助于跟踪数据会话与 NETADAPTER 对象的关系,这在激活多个 PDP 上下文/EPS 持有者时特别有用。

  4. 在从 EvtMbbDeviceCreateAdapter 返回之前,客户端驱动程序必须通过调用 NetAdapterStart 来启动适配器。 (可选)他们还可以通过在调用 NetAdapterStart之前调用以下一个或多个函数来设置适配器的功能:

MBBCx 至少调用此回调函数一次,因此主 PDP 上下文/默认 EPS 持有者始终有一个 NETADPATER 对象。 如果激活了多个 PDP 上下文/EPS 持有者,MBBCx 可能会多次调用此回调函数,每次建立一次数据会话。 NETADAPTER 对象表示的网络接口与数据会话之间必须存在一对一关系,如下图所示。

显示不同数据会话的多个 NETADAPTER 对象的示意图。

以下示例演示如何为数据会话创建 NETADAPTER 对象。 请注意,为简洁明了起见,设置适配器功能所需的错误处理和代码被排除在外。

    NTSTATUS
    EvtMbbDeviceCreateAdapter(
        WDFDEVICE  Device,
        PNETADAPTER_INIT AdapterInit
    )
    {
        // Get the client driver defined per-device context
        PMY_DEVICE_CONTEXT deviceContext = MyGetDeviceContext(Device);

        // Set up the client driver defined per-adapter context
        WDF_OBJECT_ATTRIBUTES adapterAttributes;
        WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&adapterAttributes,
                                                MY_NETADAPTER_CONTEXT);


        // Create the NETADAPTER object
        NETADAPTER netAdapter;
        NTSTATUS status = NetAdapterCreate(AdapterInit,
                                           &adapterAttributes,
                                           &netAdapter);

        // Initialize the adapter for MBB
        status = MbbAdapterInitialize(netAdapter);

        // Retrieve the Session ID and use an array to store
        // the session <-> NETADAPTER object mapping
        ULONG sessionId;
        PMY_NETADAPTER_CONTEXT netAdapterContext = MyGetNetAdapterContext(netAdapter);

        netAdapterContext->NetAdapter = netAdapter;

        sessionId = MbbAdapterGetSessionId(netAdapter);

        netAdapterContext->SessionId = sessionId;

        deviceContext->Sessions[sessionId].NetAdapterContext = netAdapterContext;

        //
        // Optional: set adapter capabilities
        //
        ...
        NetAdapterSetDatapathCapabilities(netAdapter,
                                          &txCapabilities,
                                          &rxCapabilities);

        ...
        NetAdapterSetLinkLayerCapabilities(netAdapter,
                                           &linkLayerCapabilities);

        ...
        NetAdapterSetLinkLayerMtuSize(netAdapter,
                                      MY_MAX_PACKET_SIZE - ETHERNET_HEADER_LENGTH);

        //
        // Required: start the adapter
        //
        status = NetAdapterStart(netAdapter);

        return status;
    }

有关设置数据路径功能的代码示例,请参阅 网络数据缓冲区管理

MBBCx 保证在请求具有相同会话 ID 的MBIM_CID_CONNECT之前调用 EvtMbbDeviceCreateAdapter。 以下流程图显示了客户端驱动程序与类扩展在创建 NETADAPTER 对象时之间的交互。

显示 MBB 客户端驱动程序的 NETADAPTER 创建和激活的示意图。

EvtDevicePrepareHardware 成功完成时,MBBCx 将启动为主要 PDP 上下文/默认 EPS 持有者创建 NETADAPTER 对象的流。

每当应用程序请求按需连接时, WwanSvc 就会触发为辅助 PDP 上下文/专用 EPS 持有者创建 NETADAPTER 对象的流。

NETADAPTER 对象的生存期

当客户端驱动程序创建的 NETADAPTER 对象不再使用时,MBBCx 将自动销毁该对象。 例如,在停用其他 PDP 上下文/EPS 持有者后,就会发生这种情况。 MBBCx 客户端驱动程序不得在所创建的 NETADAPTER 对象上调用 WdfObjectDelete

如果客户端驱动程序需要清理绑定到 NETADAPTER 对象的上下文数据,则应在调用 NetAdapterCreate 时在对象属性结构中提供 EvtDestroyCallback 函数。

MBB 设备的电源管理

对于电源管理,客户端驱动程序应 像其他类型的 NetAdapterCx 客户端驱动程序一样使用 NETPOWERSETTINGS 对象。

处理设备服务会话

当应用程序将 DSS 数据向下发送到调制解调器设备时,MBBCx 会调用客户端驱动程序的 EvtMbbDeviceSendServiceSessionData 回调函数。 然后,客户端驱动程序应以异步方式将数据发送到设备,并在发送完成后调用 MbbDeviceSendDeviceServiceSessionDataComplete ,以便 MBBCx 可以释放为数据分配的内存。

相反,客户端驱动程序调用 MbbDeviceReceiveDeviceServiceSessionData ,以通过 MBBCx 将任何数据传递到应用程序。

Windows 驱动程序符合性要求