微软设备团队很高兴地宣布为Windows驱动程序开发人员发布一个开源框架——驱动程序模块框架(DMF)。使用DMF,不仅可以轻松地开发简单且结构化的Windows驱动程序框架(WDF)驱动程序,还可以在驱动程序之间共享代码。
多年来,Surface 团队开发了许多产品,如 Pro,Studio,Laptop,Book,具有独特创新的硬件功能。为了实现这些功能,我们经常需要编写驱动程序和固件。尽管这些产品在与硬件接口方面具有共性,但各个产品团队独立工作,从头开始构建自己的驱动程序,或者根据他们对现有代码的认识进行复制,并根据他们的需求进行修改。这确实有助于满足他们的直接业务优先级,但却导致了巨大的代码重复和维护开销。具有不同经验水平的开发人员经常创建许多不同的解决方案来解决相同的问题,并且代码结构和质量堪忧。
大约三年前,该团队决定全面审视为各种 Surface 产品编写驱动程序,并开始尝试以最大程度重用代码的方式重构代码,以提高团队的效率,可维护性和可扩展性。建立新产品。
我们首先将驱动程序中的各个功能分解为可共享的代码库。这种迭代尝试催生了 DMF 的创建:WDF 的扩展,并提供了一个名为 DMF 模块的新 WDF 对象库。 模块允许以结构化方式让 WDF 和硬件彼此交互。
如今,团队中的所有 WDF 驱动程序都是使用 DMF 编写的。模块经过良好测试,可以在以后重复使用或扩展,以满足新的要求。除了具有良好架构的驱动程序之外,错误修复现在也很有效。模块中的错误修复会自动应用于使用该模块构建的所有驱动程序。
作为开源工作的一部分,我们共享了许多模块,为常见问题提供解决方案。
首先让我们看一下 WDF 驱动程序的典型设计.
在此设计中,驱动程序在设备上下文中处于维护状态,并且代码被分成访问设备上下文并在它们之间进行通信的单元。作为驱动程序开发人员,你负责确保对设备上下文的访问进行同步,并在单元相互通信时遵守严格的锁定层次结构,以避免损坏和死锁。当 WDF 调用驱动程序时,你还要负责根据需要将工作分派给每个单元。因为很难知道通信的流程,并保持对设备上下文的正确同步访问。
如果要在另一个驱动程序中重用 FIFO 代码。在提取代码和用于存储状态的字段之前,您需要了解单元之间的复杂交互。而这在很多时候往往容易出错。
现在让我们使用 DMF 来改进架构。这里的驱动程序是使用客户端模块和几个预构建的通用实用程序模块构建的。我们将参考使用 Module 作为客户端驱动程序的代码。在 WDF 和各个模块之间,有一个中间层(DMF)来绑定模块并将 WDF 事件分派给每个模块。现在,模块以明确定义的方式相互通信并与客户端驱动程序通信,如箭头所示。而不是所有模块共享设备上下文,每个模块使用自己的上下文区域来维护其状态。
以下是传统的 WDF 和基于 DMF 的 WDF 驱动程序之间的一些关键区别:
WDF 与 DMF通信,DMF 与驱动程序通信。
设备上下文(用绿色表示)独立存在于每个模块和特定于客户端的驱动程序代码中。每个较小的设备上下文仅包含该模块所需的元素。没有模块可以访问另一个模块的设备上下文。
WDF 回调(用红色表示)现在独立存在于每个模块和特定于客户端的代码中。WDF 调用客户端驱动程序。DMF 拦截调用并将其分派到实例化模块树中的每个模块。每个模块根据需要处理每个回调。最后,DMF 将回调分派到客户机驱动程序的回调。
最后,注意箭头。箭头特别地显示了模块之间的流和特定于客户端的代码。在本例中,特定于客户端的代码只能与三个模块通信:ACPI、Button 和 Stream。它不能与 GPIO、FIFO、List 或线程通信。ACPI 不能与 FIFO 等进行通信。即使不查看源代码,我们也对这个驱动程序中的数据流有很好的了解。
总之,每个模块都是一个独立的单元。它有自己的代码、上下文和回调。这使得代码易于重用。以这种方式组织驱动程序可以解决许多问题。
DMF 遵循 WDF 的设计和交互模式。DMF 不会替换 WDF,也不会限制驱动程序直接使用 OS 接口。DMF 使你可以更轻松地将设备驱动程序必须执行的任务分解为更小的单元。然后,执行单个任务的那些较小的自包含单元可以被编写为模块。
1.DMF 模块使用与现有 WDF 对象一致的交互模式。就像任何 WDF 对象一样,一个 DMF 模块包含:
有一个 CONFIG 结构,方法和事件回调。
可以作为其他 WDF 对象的子节点,用于生命周期管理
2.客户端驱动程序中的模块被组织成由 DMF 内核所维护的树结构。内核负责创建、打开、关闭和销毁模块。反过来,每个模块负责分配和释放自身的资源。
3.彼此互为兄妹的模块无法直接通信。只有处于父子关系中的模块才能相互通信;只有父模块可以与其子模块通信(回调除外)。
4.可扩展模块以满足新的要求,或者可通过组合多个模块来创建新模块。
5.模块设计类似于面向对象编程模式中的类。如果你熟悉通用可扩展固件接口(UEFI)的驱动程序执行环境(DXE),你会发现它与模块的相似性。)
DMF Module | C++ 中类似概念 |
Module | C++ 对象 |
Module Context | C++ 对象的私有数据(成员)。同时这也与 WDF 驱动中的“device context”类似 |
Module Config | C++ 对象的构造函数的参数 |
Module Public Methods | C++ 对象的公共函数 |
Module Private Methods | C++ 对象的私有函数 |
Module Handle | C++ 中的"this"指针 |
Client driver | 实例化 C++ 对象的代码 |
6.每个模块都有自己的锁。每个模块负责对其私有上下文进行加锁。因此,锁定是粒状的,但同时又是高效且易于理解的。
7.模块可以由客户端驱动器或其他模块使用; 与使用它们的代码无关。
8.模块可以使用任意数量的子模块。反过来,子模块可以使用任意数量的子模块。
9. DMF为许多驱动器例程提供了默认实现,例如DriverEntry、AddDevice、WDF Queue创建,因此可以使用尽可能少的代码创建简单的驱动器(也称为Container驱动器)。
10.客户端驱动器只需要实例化驱动器所需的模块。所需的子模块(如果有的话)由DMF代表驱动器来自动实例化。
2KB项目(www.2kb.com,源码交易平台),提供担保交易、源码交易、虚拟商品、在家创业、在线创业、任务交易、网站设计、软件设计、网络兼职、站长交易、域名交易、链接买卖、网站交易、广告买卖、站长培训、建站美工等服务