USBCCGP FDO的启动
USBCCGP FDO的启动会执行主功能号为IRP_MJ_PNP,次功功能号IRP_MN_START_DEVICE的IRP。
其函数调用关系如下:
USBCCGP_Dispatch 
        FDO_Dispatch 
                FDO_HandlePnp
                    FDO_StartDevice
函数代码如下:
fdo.c
NTSTATUS
FDO_StartDevice(
    PDEVICE_OBJECT DeviceObject,
    PIRP Irp)
{
    NTSTATUS Status;
    PFDO_DEVICE_EXTENSION FDODeviceExtension;
    /* Get device extension */
    FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
    ASSERT(FDODeviceExtension->Common.IsFDO);
    /* First start lower device */
    Status = USBCCGP_SyncForwardIrp(FDODeviceExtension->NextDeviceObject, Irp);
    if (!NT_SUCCESS(Status))
    {
        /* Failed to start lower device */
        DPRINT1("FDO_StartDevice lower device failed to start with %x\n", Status);
        return Status;
    }
    /* Get descriptors */
    Status = USBCCGP_GetDescriptors(DeviceObject);
    if (!NT_SUCCESS(Status))
    {
        /* Failed to start lower device */
        DPRINT1("FDO_StartDevice failed to get descriptors with %x\n", Status);
        return Status;
    }
    /* Get capabilities */
    Status = FDO_QueryCapabilities(DeviceObject,
                                   &FDODeviceExtension->Capabilities);
    if (!NT_SUCCESS(Status))
    {
        /* Failed to start lower device */
        DPRINT1("FDO_StartDevice failed to get capabilities with %x\n", Status);
        return Status;
    }
    /* Now select the configuration */
    Status = USBCCGP_SelectConfiguration(DeviceObject, FDODeviceExtension);
    if (!NT_SUCCESS(Status))
    {
        /* Failed to select interface */
        DPRINT1("FDO_StartDevice failed to get capabilities with %x\n", Status);
        return Status;
    }
    /* Query bus interface */
    USBCCGP_QueryInterface(FDODeviceExtension->NextDeviceObject,
                           &FDODeviceExtension->BusInterface);
    /* Now enumerate the functions */
    Status = USBCCGP_EnumerateFunctions(DeviceObject);
    if (!NT_SUCCESS(Status))
    {
        /* Failed to enumerate functions */
        DPRINT1("Failed to enumerate functions with %x\n", Status);
        return Status;
    }
    /* Sanity checks */
    ASSERT(FDODeviceExtension->FunctionDescriptorCount);
    ASSERT(FDODeviceExtension->FunctionDescriptor);
    DumpFunctionDescriptor(FDODeviceExtension->FunctionDescriptor,
                           FDODeviceExtension->FunctionDescriptorCount);
    /* Now create the pdo */
    Status = FDO_CreateChildPdo(DeviceObject);
    if (!NT_SUCCESS(Status))
    {
        /* Failed */
        DPRINT1("FDO_CreateChildPdo failed with %x\n", Status);
        return Status;
    }
    /* Inform pnp manager of new device objects */
    IoInvalidateDeviceRelations(FDODeviceExtension->PhysicalDeviceObject,
                                BusRelations);
    /* Done */
    DPRINT("[USBCCGP] FDO initialized successfully\n");
    return Status;
}
可以看到,FDO_StartDevice主要实现了以下功能:
1.将IRP下传给PDO,使PDO启动。
2.获取设备的描述符:设备描述符和配置描述符(包括接口描述符、端点描述符和其它描述符)
3.获取设备支持的特性,如电源,热插发等。
4.解析配置描述符,并获取各个子设备信息。
5.获取总线自定义的枚举设备的接口。
6.枚举子设备PDO.
7.创建子设备。
8.通知PNP管理器发备树发生变化,有新的设备产生。
IRP同步下传是能过函数USBCCGP_SyncForwardIrp实现的:
msic.c
TSTATUS
NTAPI
USBCCGP_SyncForwardIrp(
    PDEVICE_OBJECT DeviceObject,
    PIRP Irp)
{
    KEVENT Event;
    NTSTATUS Status;
    /* Initialize event */
    KeInitializeEvent(&Event, NotificationEvent, FALSE);
    /* Copy irp stack location */
    IoCopyCurrentIrpStackLocationToNext(Irp);
    /* Set completion routine */
    IoSetCompletionRoutine(Irp,
                           USBSTOR_SyncForwardIrpCompletionRoutine,
                           &Event,
                           TRUE,
                           TRUE,
                           TRUE);
    /* Call driver */
    Status = IoCallDriver(DeviceObject, Irp);
    /* Check if pending */
    if (Status == STATUS_PENDING)
    {
        /* Wait for the request to finish */
        KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
        /* Copy status code */
        Status = Irp->IoStatus.Status;
    }
    /* Done */
    return Status;
}
可能看到,创建一个事件,初始化为通知事件,默认为未激活态。
然后将当前的STACK_LOCATION拷贝到下一层,使其具有相同的STACK_LOCATION,然后设置下层完成函数为USBSTOR_SyncForwardIrpCompletionRoutine.这样当下层完成IRP时,会调用完成函数,而我们在完成函数中将事件置为激活,这样在本层驱动通过等到这个事件就可以知道下层已经完成,即设备已经启动了。
 完成函数的代码如下:
 msic.c
NTSTATUS
NTAPI
USBSTOR_SyncForwardIrpCompletionRoutine(
    PDEVICE_OBJECT DeviceObject,
    PIRP Irp,
    PVOID Context)
{
    if (Irp->PendingReturned)
    {
        KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, FALSE);
    }
    return STATUS_MORE_PROCESSING_REQUIRED;
}
附相关函数源代码:
IoCopyCurrentIrpStackLocationToNext
FORCEINLINE
VOID
IoCopyCurrentIrpStackLocationToNext(
    _Inout_ PIRP Irp
)
/*--
Routine Description:
    This routine is invoked to copy the IRP stack arguments and file
    pointer from the current IrpStackLocation to the next
    in an I/O Request Packet (IRP).
    If the caller wants to call IoCallDriver with a completion routine
    but does not wish to change the arguments otherwise,
    the caller first calls IoCopyCurrentIrpStackLocationToNext,
    then IoSetCompletionRoutine, then IoCallDriver.
Arguments:
    Irp - Pointer to the I/O Request Packet.
Return Value:
    None.
--*/
{
    PIO_STACK_LOCATION irpSp;
    PIO_STACK_LOCATION nextIrpSp;
    irpSp = IoGetCurrentIrpStackLocation(Irp);
    nextIrpSp = IoGetNextIrpStackLocation(Irp);
    RtlCopyMemory( nextIrpSp, irpSp, FIELD_OFFSET(IO_STACK_LOCATION, CompletionRoutine));
    nextIrpSp->Control = 0;
}
可以看到,就是从IO_STACK_LOCATION结构体CompletionRoutine这个成员以前的所有数据复制,而不是全部复制。
注意:FILE_OFFSET
这里有一个宏
FILE_OFFSET,定义如下:#define FIELD_OFFSET(type, field) ((LONG)(LONG_PTR)&(((type *)0)->field))其功能就是计算某个成员相对其结构体的偏移量。
IoSetCompletionRoutine
VOID
IoSetCompletionRoutine(
    _In_ PIRP Irp,
    _In_opt_ PIO_COMPLETION_ROUTINE CompletionRoutine,
    _In_opt_ __drv_aliasesMem PVOID Context,
    _In_ BOOLEAN InvokeOnSuccess,
    _In_ BOOLEAN InvokeOnError,
    _In_ BOOLEAN InvokeOnCancel
    )
//++
//
// Routine Description:
//
//     This routine is invoked to set the address of a completion routine which
//     is to be invoked when an I/O packet has been completed by a lower-level
//     driver.
//
// Arguments:
//
//     Irp - Pointer to the I/O Request Packet itself.
//
//     CompletionRoutine - Address of the completion routine that is to be
//         invoked once the next level driver completes the packet.
//
//     Context - Specifies a context parameter to be passed to the completion
//         routine.
//
//     InvokeOnSuccess - Specifies that the completion routine is invoked when the
//         operation is successfully completed.
//
//     InvokeOnError - Specifies that the completion routine is invoked when the
//         operation completes with an error status.
//
//     InvokeOnCancel - Specifies that the completion routine is invoked when the
//         operation is being canceled.
//
// Return Value:
//
//     None.
//
//--
{
    PIO_STACK_LOCATION irpSp;
    NT_ASSERT( (InvokeOnSuccess || InvokeOnError || InvokeOnCancel) ? (CompletionRoutine != NULL) : TRUE );
    irpSp = IoGetNextIrpStackLocation(Irp);
    irpSp->CompletionRoutine = CompletionRoutine;
    irpSp->Context = Context;
    irpSp->Control = 0;
    if (InvokeOnSuccess) {
        irpSp->Control = SL_INVOKE_ON_SUCCESS;
    }
    if (InvokeOnError) {
        irpSp->Control |= SL_INVOKE_ON_ERROR;
    }
    if (InvokeOnCancel) {
        irpSp->Control |= SL_INVOKE_ON_CANCEL;
    }
}
通过分析IoSetCompletionRoutine这个函数,可以看到设置的完成函数并不是设置本层的STACK_LOCATION,而是下一层的。因为设置完成函数就是为了等待下层IRP完成的返回。
至于是什么时候完成,可以通过分析IoCompleteRequest,这里就不再深究了。
 USB通用驱动源码分析
			USB通用驱动源码分析
			




