WDF队列分析(2)----IoQueue的创建

如果阅读了《WDF队列分析(1)--序幕》,可能你还记得在那篇文章的结尾部分提到过进入DispatchWorker函数后,框架根据IRP类型选择不同的Package类型,进而有了不同的Dispatch函数:
    FxPackage*
    GetDispatchPackage(
        __in UCHAR MajorFunction
        )
    {
        switch (MajorFunction) {
        case IRP_MJ_CREATE:
            return (FxPackage*) m_PkgGeneral;

        case IRP_MJ_READ:
            return (FxPackage*) m_PkgIo;

        case IRP_MJ_SYSTEM_CONTROL:
            return (FxPackage*) m_PkgWmi;

        case IRP_MJ_PNP:
        case IRP_MJ_POWER:
            if (m_PkgPnp != NULL) {
                return (FxPackage*) m_PkgPnp;
            }
            else {
                return (FxPackage*) m_PkgDefault;
            }
            break;

        default:
            return (FxPackage*) m_PkgDefault;
        }
    }
当时我们的关注点其实集中在DriverObject上(派遣函数属于驱动对象的一部分),在本篇中,我们会把关注点转移到DeviceObject。
    开始之前先回顾一下函数DispatchWorker的结尾部分,MS用到了链式表达式:
    return Device->GetDispatchPackage(
        irp.GetMajorFunction()
        )->Dispatch(Irp);
GetDispatchPackage返回4种FxPackage的派生类对象,因此上面的语句可以看作是下列语句的变种:
return Device->m_PkgPnp->Dispath(Irp);
链式语句的前半部分:Device->m_PkgPnp暗示我们m_PkgPnp是FxDevice的类成员,同理像m_PkgGeneral/m_PkgIo等变量都是FxDevice的类成员。
class FxDevice : public FxDeviceBase {
...
public:

    FxPkgIo*            m_PkgIo;
    FxPkgPnp*           m_PkgPnp;
    FxPkgGeneral*       m_PkgGeneral;
    FxWmiIrpHandler*    m_PkgWmi;
    FxDefaultIrpHandler* m_PkgDefault;
...
}; //framework\shared\inc\private\common\FxDevice.cpp
    既然这几个成员变量是指针类型的,那么,在设备对象创建时它们应该执行了初始化操作(否则早蓝屏了),以m_PkgIo/m_PkgPnp为关键字在SourceInsight中查找引用,将在FxDevice::Initialize/FxDevice::FdoInitialize等函数中找到对这些变量的初始化赋值。
_Must_inspect_result_
NTSTATUS
FxDevice::_Create(
    __in PFX_DRIVER_GLOBALS FxDriverGlobals,
    __in PWDFDEVICE_INIT* DeviceInit,
    __in_opt PWDF_OBJECT_ATTRIBUTES DeviceAttributes,
    __out FxDevice** Device
    )
{
...
    status = pDevice->Initialize(pInit, DeviceAttributes);
    switch (pInit->InitType) {
    case FxDeviceInitTypeFdo:
        status = pDevice->FdoInitialize(pInit);
        break;

    case FxDeviceInitTypePdo:
        status = pDevice->PdoInitialize(pInit);
        break;

    case FxDeviceInitTypeControlDevice:
        status = pDevice->ControlDeviceInitialize(pInit);
        break;

    default:
        break;
    }
...
    if (pDevice->IsPnp()) {
...
        pDevice->m_PkgPnp->FinishInitialize(pInit);
    }
    pInit->CreatedDevice = pDevice;
Done:
    *Device = pDevice;
    return status;
}
在函数FxDevice::_Create中,框架将新创建的FxDevice对象通过FxDevice::Initialize函数做了简单的初始化工作,然后根据调用WdfDeviceCreate时传入的WDFDEVICE_INIT结构,按PDO/FDO/CDO/FiDO的分类对FxDevice再次设置。
_Must_inspect_result_
NTSTATUS
FxDevice::Initialize(
    __in PWDFDEVICE_INIT DeviceInit,
    __in_opt PWDF_OBJECT_ATTRIBUTES DeviceAttributes
    )
{
	...
    m_PkgDefault = new (pGlobals) FxDefaultIrpHandler(pGlobals, (CfxDevice*)this);
    if (m_PkgDefault == NULL) {
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    InstallPackage(m_PkgDefault);

    if (DeviceInit->InitType == FxDeviceInitTypeControlDevice) {
        m_Legacy = TRUE;
    }
...

    Mx::MxInitializeNPagedLookasideList(&m_RequestLookasideList,
                                    NULL,
                                    NULL,
                                    0,
                                    m_RequestLookasideListElementSize,
                                    pGlobals->Tag,
                                    0);
    // Init device's auto_forward_cleanup_close.
    ConfigureAutoForwardCleanupClose(DeviceInit);

    //
    // Create, close, cleanup, shutdown
    //
    m_PkgGeneral = new(pGlobals) FxPkgGeneral(pGlobals, this);
    if (m_PkgGeneral == NULL) {
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    InstallPackage(m_PkgGeneral);
...
    
    // IO package handles reads, writes, internal and external IOCTLs
    m_PkgIo = new(pGlobals) FxPkgIo(pGlobals, (CfxDevice*) this);

    if (m_PkgIo == NULL) {
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    InstallPackage(m_PkgIo);
...

    return STATUS_SUCCESS;
}
FxDevice::Initialize初始化了m_PkgDefault/m_PkgIo/m_PkgGeneral 3个成员变量,换言之,目前驱动程序已经具备除了IRP_MJ_Pnp/Power之外的所有IRP处理能力。但是,这只是通用的配置,就同一个IRP,位于同一设备栈上的不同类型的设备对象有不同的处理方式:如对于IRP_MJ_PNP&IRP_MN_QUERY事件,FiDo和FDO可能选择向下传递该IRP,而PDO会枚举并返回总线上的设备信息。所以,WDF这种一揽子的做法肯定不合适,所以需要根据设备类型进一步细分。
    划分的依据用到了WDFDEVICE_INIT结构,结构中的DeviceType域用于上述目的。
typedef struct WDFDEVICE_INIT *PWDFDEVICE_INIT;

    在创建设备对象的时候,会设置WDFDEVICE_INIT结构。默认情况下WDFDEVICE_INIT!DeviceType是Fdo(附注:这句话我没有在源码中核对过,但是toast使用的是默认设置,所以这么猜测)。默认值往往不够应付多变的情况,这时候就可以通过其他函数为WDFDEVICE_INIT!DeviceType指定其他类型,如toast的过滤驱动在调用WdfDeviceCreate前如此操作:

NTSTATUS
FilterEvtDeviceAdd(
    IN WDFDRIVER        Driver,
    IN PWDFDEVICE_INIT  DeviceInit
    )
{
    PAGED_CODE ();
    //查看WdfFdoInitSetFilter定义,它仅仅将DeviceInit->Fdo.Filter置为TRUE;
    WdfFdoInitSetFilter(DeviceInit);

    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, FILTER_EXTENSION);
    status = WdfDeviceCreate(&DeviceInit, &deviceAttributes, &device);

}

至于Pdo和Cdo(cdo是Wdf中提出的概念,其实对应于内核服务"legacy device"),又可分别参考toast\kmdf\static\buspdo.c的实现:

NTSTATUS
Bus_CreatePdo(
    __in WDFDEVICE  Device,
    __in PWCHAR     HardwareIds,
    __in ULONG      SerialNo
)
{
    pDeviceInit = WdfPdoInitAllocate(Device);

    WdfDeviceInitSetDeviceType(pDeviceInit, FILE_DEVICE_BUS_EXTENDER);
}

以及ioctl\kmdf\nonpnp.c

NTSTATUS
DriverEntry(
    IN OUT PDRIVER_OBJECT   DriverObject,
    IN PUNICODE_STRING      RegistryPath
    )
{
    status = WdfDriverCreate(DriverObject,
                            RegistryPath,
                            &attributes,
                            &config,
                            &hDriver);
							
    pInit = WdfControlDeviceInitAllocate(
                            hDriver,
                            &SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RW_RES_R
                            );

    status = NonPnpDeviceAdd(hDriver, pInit);
}
现在WDF可根据WDFDEVICE_INIT!DeviceType的值,进行二度加工了。由于IRP_MJ_PNP消息过于复杂,所以我将在下一篇以IRP_MJ_READ为列,尝试分析m_PkgIo变量及相应的FdoInitialize函数。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值