plasma
驱动小牛
驱动小牛
  • 注册日期2002-02-19
  • 最后登录2008-02-27
  • 粉丝0
  • 关注0
  • 积分50分
  • 威望5点
  • 贡献值0点
  • 好评度5点
  • 原创分0分
  • 专家分0分
阅读:59763回复:169

WDM驱动程序---USB驱动开发

楼主#
更多 发布于:2002-03-11 22:54
先安装VC ++,再安装DDK。
安装DDK后,在DDK程序组下有Check和Free两个编译环境,Check环境用于编译带调试信息的驱动程序,Free则是编译正式发布版本的环境。通常情况下设备驱动程序的编译采用命令行的方式。通过一定的设置可以在VC ++的集成环境下编译。

  一般来说,成功编译一个最基本的设备驱动程序需要四类文件:
  第一个是驱动程序,即源程序文件
  第二个是RC文件
  第三个是sources文件
  第四个文件是makefile文件
sources文件和makefile文件类似,用来指定需要编译的文件以及需要连接的库文件。

一般makefile文件不用修改;RC文件、sources文件根据自己要求修改。

RC文件:
用文本编辑器编辑,不要用VC++默认方式打开!
例如98DDK中给出的BULKUSB.RC:
#include <windows.h>

#include <ntverp.h>

#define VER_FILETYPE    VFT_DLL
#define VER_FILESUBTYPE VFT2_UNKNOWN
#define VER_FILEDESCRIPTION_STR     \"I82930 Bulk IO Test Driver\"
#define VER_INTERNALNAME_STR        \"BulkUsb.sys\"
#define VER_ORIGINALFILENAME_STR    \"BulkUsb.sys\"

#include \"common.ver\"

其中,只需修改 \"I82930 Bulk IO Test Driver\"  \"BulkUsb.sys\"

RC文件、sources文件和makefile文件都很简单,在DDK samples的每个例程里都有三个这样的文件。

相关连接:

《USB应用程序开发》中,我想和网友共同探讨USB应用程序开发问题。


《D12->C51驱动程序开发》中,我想和网友共同探讨USB硬件设备开发问题。


[编辑 -  5/11/02 by  plasma]

[编辑 -  10/23/03 by  plasma]
minker
驱动牛犊
驱动牛犊
  • 注册日期2002-02-15
  • 最后登录2002-04-02
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2002-03-12 01:25
en....这是一个比较simple的问题,我第一次编译就通过了
找机会请大家吃饭
plasma
驱动小牛
驱动小牛
  • 注册日期2002-02-19
  • 最后登录2008-02-27
  • 粉丝0
  • 关注0
  • 积分50分
  • 威望5点
  • 贡献值0点
  • 好评度5点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2002-03-13 10:10
创建VC++驱动程序开发环境(在WIN98下不适用,其只能在DOS窗口中编译)
  在VC中创建makefile工程

Debug 环境配置
命 令 行:nmakedrv checked
重建选项:-namak /a
输出文件名:文件名.sys

Release 环境配置
命 令 行:nmakedrv free
重建选项:-namak /a
输出文件名:文件名.sys

[编辑 -  10/23/03 by  plasma]
plasma
驱动小牛
驱动小牛
  • 注册日期2002-02-19
  • 最后登录2008-02-27
  • 粉丝0
  • 关注0
  • 积分50分
  • 威望5点
  • 贡献值0点
  • 好评度5点
  • 原创分0分
  • 专家分0分
地板#
发布于:2002-03-13 10:21
在工程目录中创建下列4个编译配置文件

文件:nmakedrv.bat

@echo off
if \"%1\"==\"\" goto exit
rem DDK安装路径
set mDDKDir=E:\\NTDDK

if not exist %mDDKDir%\\bin\\setenv.bat goto exit
call %mDDKDir%\\bin\\setenv %mDDKDir% %1

rem 转入工程目录
E:
cd \\temp1
build -b -w %2 %3 %4 %5 %6 %7 %8 %9
:exit

注:DDK安装路径、转入工程目录需自己修改

文件:Sources

TARGETNAME=temp1
TARGETTYPE=DRIVER
DRIVERTYPE=WDM
TARGETPATH=OBJ

INCLUDES=$(BASEDIR)\\inc;
TARGETLIBS=$(DDK_LIB_PATH)\\usbd.lib

USE_MAPSYM=1

SOURCES=  \\
    script1.rc \\
    IusbDbg.c \\
    IsoUsb.c  \\
    IsoPnP.c \\
    IsoPwr.c \\
    IoctlIso.c   \\
    IsoStrm.c \\
    OcrwIso.c

NTTARGETFILES=PostBuildSteps

注:temp1 为自定义工程文件名;TARGETLIBS指用到的库列表;SOURCES源文件(不

要头文件),资源文件列表。这三处需自己修改。

下面两个文件不用修改,按此建好即可。

文件:MAKEFILE

#
# DO NOT EDIT THIS FILE!!!  Edit .\\sources. if you want to add a new

source
# file to this component.  This file merely indirects to the real make

file
# that is shared by all the driver components of the Windows NT DDK
#

!INCLUDE $(NTMAKEENV)\\makefile.def

文件:Makefile.inc

PostBuildSteps: $(TARGET)
!if \"$(DDKBUILDENV)\"==\"free\"
rebase -B 0x10000 -X . $(TARGET)
!endif
copy $(TARGET) $(WINDIR)\\system32\\drivers

注:此 copy 是将你的驱动程序复制到系统system32\\drivers目录;利于重新启动设

备时启动新的驱动程序。
plasma
驱动小牛
驱动小牛
  • 注册日期2002-02-19
  • 最后登录2008-02-27
  • 粉丝0
  • 关注0
  • 积分50分
  • 威望5点
  • 贡献值0点
  • 好评度5点
  • 原创分0分
  • 专家分0分
地下室#
发布于:2002-03-13 11:05
生成设备接口代码GUID
利用VC++工具GUIDGEN.EXE,选择GUID Format选项2.DERINE_GUID(...),然后Copy,在粘贴到你的工程中。定义自己的标识符<<name>>。
plasma
驱动小牛
驱动小牛
  • 注册日期2002-02-19
  • 最后登录2008-02-27
  • 粉丝0
  • 关注0
  • 积分50分
  • 威望5点
  • 贡献值0点
  • 好评度5点
  • 原创分0分
  • 专家分0分
5楼#
发布于:2002-03-13 11:16
创建版本资源(RC文件):
用文本编辑器编辑,不要用VC++默认方式打开!
例如98DDK中给出的BULKUSB.RC:
#include <windows.h>

#include <ntverp.h>

#define VER_FILETYPE VFT_DLL
#define VER_FILESUBTYPE VFT2_UNKNOWN
#define VER_FILEDESCRIPTION_STR \"I82930 Bulk IO Test Driver\"
#define VER_INTERNALNAME_STR \"BulkUsb.sys\"
#define VER_ORIGINALFILENAME_STR \"BulkUsb.sys\"

#include \"common.ver\"

其中,只需修改 \"I82930 Bulk IO Test Driver\" \"BulkUsb.sys\"



[编辑 -  10/23/03 by  plasma]
plasma
驱动小牛
驱动小牛
  • 注册日期2002-02-19
  • 最后登录2008-02-27
  • 粉丝0
  • 关注0
  • 积分50分
  • 威望5点
  • 贡献值0点
  • 好评度5点
  • 原创分0分
  • 专家分0分
6楼#
发布于:2002-03-13 21:12
创建安装信息文件INF

详细内容打开DDK帮助文件DDK Documentation。

下面从应用出发介绍各节

[Version]
Signature=\"$CHICAGO$\"
Class=USB
ClassGUID={745a17a0-74d3-11d0-b6fe-00a0c90f57da}
Provider=%USBDBE%
DriverVer=11/12/2001,4.10.2222.12

注:
Signature指驱动程序类型,\"$Chicago$\"表示WDM型驱动,\"$Windows NT$\"表示非WDM型驱动。
Class    指所属类,如:USB,HID,1394
Provider 指驱动程序提供者,此信息显示在设备属性的“常规”页
DriverVer指版本信息,显示在驱动程序文件详细资料窗口
ClassGUID指驱动程序运行的驱动程序堆栈类属,它决定了驱动程序所能完成的功能。缺省为虚拟设备。对于USB类:
ClassGUID={36FC9E60-C465-11CF-8056-444553540000}

[编辑 -  3/25/02 作者: plasma]
henrry
驱动牛犊
驱动牛犊
  • 注册日期2001-12-18
  • 最后登录2013-06-22
  • 粉丝0
  • 关注0
  • 积分7分
  • 威望43点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
7楼#
发布于:2002-03-14 09:52
非常不错的经验吗!虽然我平时不爱用集成环境编译驱动程序,看到PLASMA这么用心地为大家提供经验,我都忍不住想给他加分了。

:)
NO
plasma
驱动小牛
驱动小牛
  • 注册日期2002-02-19
  • 最后登录2008-02-27
  • 粉丝0
  • 关注0
  • 积分50分
  • 威望5点
  • 贡献值0点
  • 好评度5点
  • 原创分0分
  • 专家分0分
8楼#
发布于:2002-03-24 15:13
代码内存管理
#pragma data_seg(\"INIT\")
//可废弃数据,程序运行后这部分程序或数据占用的内存被释放
#pragma data_seg ()

#pragma data_seg (\"PAGE\")
//可放入分页内存数据,程序运行后这部分程序或数据占用的内存可被移入硬盘虚拟内存中,可以减少物理内存的占用,只是再次运行可能影响速度。
#pragma data_seg ()
plasma
驱动小牛
驱动小牛
  • 注册日期2002-02-19
  • 最后登录2008-02-27
  • 粉丝0
  • 关注0
  • 积分50分
  • 威望5点
  • 贡献值0点
  • 好评度5点
  • 原创分0分
  • 专家分0分
9楼#
发布于:2002-03-25 15:49
驱动程序启动时的入口点函数DriverEntry主要工作是初始化DeviceObject的回调函数指针,DeviceObject将保存在系统中。最主要应初始化四部分:

#pragma data_seg(\"INIT\")
NTSTATUS DriverEntry(
    IN PDRIVER_OBJECT DeviceObject,
    IN PUNICODE_STRING RegistryPath
)
{
    NTSTATUS ntStatus = STATUS_SUCCESS;
 
    // 卸载函数
    DriverObject->DriverUnload = Unload;

    // Windows应用程序交互函数
    DriverObject->MajorFunction[IRP_MJ_CREATE] = win32_Create;
    DriverObject->MajorFunction[IRP_MJ_WRITE] = win32_Write;
    DriverObject->MajorFunction[IRP_MJ_READ] = win32_Read;
    DriverObject->MajorFunction[IRP_MJ_CLOSE] = win32_Close;
    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = win32_ProcessIOCTL;

    // 即插即用、电源管理、系统控制函数
    DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = sys_ProcessSysControlIrp;
    DriverObject->MajorFunction[IRP_MJ_PNP] = PnP_ProcessPnPIrp;
    DriverObject->MajorFunction[IRP_MJ_POWER] = pwr_ProcessPowerIrp;

    // 添加设备
    DriverObject->DriverExtension->AddDevice = PnPAddDevice;
    return ntStatus;
}
#pragma data_seg ()

附:

DriverExtension 结构

DRIVER_EXTENSION
{
    // Back pointer to Driver Object
    struct _DRIVER_OBJECT *DriverObject;

    PDRIVER_ADD_DEVICE AddDevice;

    ULONG Count;

    UNICODE_STRING ServiceKeyName;
    // Note: any new shared fields get added here.
}

DriverObject结构

DRIVER_OBJECT {
    CSHORT Type;
    CSHORT Size;

    PDEVICE_OBJECT DeviceObject;
    ULONG Flags;

    PVOID DriverStart;
    ULONG DriverSize;
    PVOID DriverSection;
    PDRIVER_EXTENSION DriverExtension;

    UNICODE_STRING DriverName;

    PUNICODE_STRING HardwareDatabase;

    PFAST_IO_DISPATCH FastIoDispatch;

    PDRIVER_INITIALIZE DriverInit;
    PDRIVER_STARTIO DriverStartIo;
    PDRIVER_UNLOAD DriverUnload;
    PDRIVER_DISPATCH MajorFunction[主功能函数码];
}

主功能函数码

IRP_MJ_CREATE
IRP_MJ_CREATE_NAMED_PIPE
IRP_MJ_CLOSE
IRP_MJ_READ
IRP_MJ_WRITE
IRP_MJ_QUERY_INFORMATION
IRP_MJ_SET_INFORMATION
IRP_MJ_QUERY_EA
IRP_MJ_SET_EA
IRP_MJ_FLUSH_BUFFERS
IRP_MJ_QUERY_VOLUME_INFORMATION
IRP_MJ_SET_VOLUME_INFORMATION
IRP_MJ_DIRECTORY_CONTROL
IRP_MJ_FILE_SYSTEM_CONTROL
IRP_MJ_DEVICE_CONTROL
IRP_MJ_INTERNAL_DEVICE_CONTROL
IRP_MJ_SHUTDOWN
IRP_MJ_LOCK_CONTROL
IRP_MJ_CLEANUP
IRP_MJ_CREATE_MAILSLOT
IRP_MJ_QUERY_SECURITY
IRP_MJ_SET_SECURITY
IRP_MJ_POWER
IRP_MJ_SYSTEM_CONTROL
IRP_MJ_DEVICE_CHANGE
IRP_MJ_QUERY_QUOTA
IRP_MJ_SET_QUOTA
IRP_MJ_PNP
注意:IRP_MJ_PNP_POWER 已并入 IRP_MJ_PNP
plasma
驱动小牛
驱动小牛
  • 注册日期2002-02-19
  • 最后登录2008-02-27
  • 粉丝0
  • 关注0
  • 积分50分
  • 威望5点
  • 贡献值0点
  • 好评度5点
  • 原创分0分
  • 专家分0分
10楼#
发布于:2002-03-27 21:13
DriverEntry运行后,运行添加设备函数PnPAddDevice

例程如下:

NTSTATUS PnPAddDevice(
    IN PDRIVER_OBJECT DriverObject,
    IN PDEVICE_OBJECT PhysicalDeviceObject)
{
    NTSTATUS                ntStatus = STATUS_SUCCESS;
    PDEVICE_OBJECT          FDO = NULL;
    PDEVICE_EXTENSION       deviceExtension;
    USBD_VERSION_INFORMATION versionInformation;
    ULONG i;
    ntStatus = IoCreateDevice (DriverObject,
                       sizeof (DEVICE_EXTENSION),
                       NULL,
                       FILE_DEVICE_UNKNOWN,
                       0,
                       FALSE,// Not exclusive
                       &FDO);
    if (NT_SUCCESS(ntStatus)) {
        deviceExtension = (PDEVICE_EXTENSION) (FDO->DeviceExtension);
      ntStatus = IoRegisterDeviceInterface(
               PhysicalDeviceObject,
               (LPGUID)&GUID_CLASS_I82930_BULK,
               NULL,
               &deviceExtension->DeviceLinkNameBuffer);
      if (NT_SUCCESS(ntStatus)) {
         ntStatus = IoSetDeviceInterfaceState(&deviceExtension->DeviceLinkNameBuffer, TRUE);
      }
        if (!NT_SUCCESS(ntStatus)) {IoDeleteDevice(FDO);return ntStatus;}

        deviceExtension->MaximumTransferSize =  BULKUSB_MAX_TRANSFER_SIZE ;

        KeInitializeEvent(&deviceExtension->RemoveEvent, NotificationEvent, FALSE);
        KeInitializeEvent(&deviceExtension->SelfRequestedPowerIrpEvent, NotificationEvent, FALSE);
        KeInitializeEvent(&deviceExtension->StagingDoneEvent, NotificationEvent, FALSE);
        KeInitializeEvent(&deviceExtension->NoPendingIoEvent, NotificationEvent, FALSE);

      KeInitializeSpinLock (&deviceExtension->IoCountSpinLock);
        KeInitializeSpinLock(&deviceExtension->FastCompleteSpinlock);

        FDO->Flags |= DO_DIRECT_IO;
        FDO->Flags |= DO_POWER_PAGABLE;

        deviceExtension->PhysicalDeviceObject=PhysicalDeviceObject;
        // 放入 PDO 到设备堆栈
        deviceExtension->TopOfStackDeviceObject =
            IoAttachDeviceToDeviceStack(FDO, PhysicalDeviceObject);

        AddDevice_QueryCapabilities(deviceExtension->TopOfStackDeviceObject,
                                 &deviceExtension->DeviceCapabilities);

        deviceExtension->PowerDownLevel = PowerDeviceUnspecified; // init to disabled
        for (i=PowerSystemSleeping1; i<= PowerSystemSleeping3; i++) {
            if ( deviceExtension->DeviceCapabilities.DeviceState[ i ] < PowerDeviceD3)
                    deviceExtension->PowerDownLevel = deviceExtension->DeviceCapabilities.DeviceState[ i ];
        }
        Pub_IncrementIoCount(FDO);
    }
    USBD_GetUSBDIVersion(&versionInformation);
    if( NT_SUCCESS( ntStatus))
    {
        NTSTATUS actStat;
        // try to power down device until IO actually requested
        actStat = Usb_SelfSuspendOrActivate( FDO, TRUE);
        FDO->Flags &= ~DO_DEVICE_INITIALIZING;
    }
    return ntStatus;
}

NTSTATUS AddDevice_QueryCapabilities(
    IN PDEVICE_OBJECT       LowerDeviceObject,
    IN PDEVICE_CAPABILITIES DeviceCapabilities)
{
    PIO_STACK_LOCATION nextStack;
    PIRP irp;
    NTSTATUS ntStatus;
    KEVENT event;

    irp = IoAllocateIrp(LowerDeviceObject->StackSize, FALSE);
    if (!irp) {
        return STATUS_INSUFFICIENT_RESOURCES;
    }
    // Preinit the device capability structures appropriately.
    RtlZeroMemory( DeviceCapabilities, sizeof(DEVICE_CAPABILITIES));
    DeviceCapabilities->Size = sizeof(DEVICE_CAPABILITIES);
    DeviceCapabilities->Version = 1;
    DeviceCapabilities->Address = -1;
    DeviceCapabilities->UINumber = -1;
    // IoGetNextIrpStackLocation gives a higher level driver access to the next-lower
    // driver\'s I/O stack location in an IRP so the caller can set it up for the lower driver.
    nextStack = IoGetNextIrpStackLocation(irp);
    nextStack->MajorFunction= IRP_MJ_PNP;
    nextStack->MinorFunction= IRP_MN_QUERY_CAPABILITIES;

    // init an event to tell us when the completion routine\'s been called
    KeInitializeEvent(&event, NotificationEvent, FALSE);

    // Set a completion routine so it can signal our event when
    //  the next lower driver is done with the Irp
    IoSetCompletionRoutine(irp,
                           Pub_IrpCompletionRoutine,
                           &event,  // pass the event as Context to completion routine
                           TRUE,    // invoke on success
                           TRUE,    // invoke on error
                           TRUE);   // invoke on cancellation of the Irp
    // set our pointer to the DEVICE_CAPABILITIES struct
    nextStack->Parameters.DeviceCapabilities.Capabilities = DeviceCapabilities;
    // preset the irp to report not supported
    irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
    ntStatus = IoCallDriver(LowerDeviceObject,irp);
    if (ntStatus == STATUS_PENDING) {
       // wait for irp to complete
       KeWaitForSingleObject(
            &event,
            Suspended,//暂停
            KernelMode,
            FALSE,
            NULL);
       ntStatus = irp->IoStatus.Status;
    }
    IoFreeIrp(irp);
    return ntStatus;
}

[编辑 -  3/29/02 作者: plasma]
huxo
驱动牛犊
驱动牛犊
  • 注册日期2001-11-07
  • 最后登录2004-09-18
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
11楼#
发布于:2002-03-27 21:59
不错,很不错,加油干!
你有一个苹果,我有一个苹果,交换了还是一个苹果。 你有一个技术,我有一个技术,交换了是两个技术。
yy1125322
驱动牛犊
驱动牛犊
  • 注册日期2002-03-06
  • 最后登录2004-10-13
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
12楼#
发布于:2002-03-28 13:21
我是新手,plasma所说的有一定了解,但他总结的很好,对了后却又帮助,非常感谢plasma的热心,希望有更多的机会指教。
realtim
驱动牛犊
驱动牛犊
  • 注册日期2002-02-08
  • 最后登录2002-03-08
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
13楼#
发布于:2002-03-28 17:42
那个.rc文件是干嘛用的,我好像没有用它,就一个.c,一个
makefile,一个source。也能正常编译并运行。
plasma
驱动小牛
驱动小牛
  • 注册日期2002-02-19
  • 最后登录2008-02-27
  • 粉丝0
  • 关注0
  • 积分50分
  • 威望5点
  • 贡献值0点
  • 好评度5点
  • 原创分0分
  • 专家分0分
14楼#
发布于:2002-03-28 18:05
文件.rc是资源文件中的version信息,包含软件开发者信息、版本信息、软件运行环境信息(NT,win98,win2000)等。
plasma
驱动小牛
驱动小牛
  • 注册日期2002-02-19
  • 最后登录2008-02-27
  • 粉丝0
  • 关注0
  • 积分50分
  • 威望5点
  • 贡献值0点
  • 好评度5点
  • 原创分0分
  • 专家分0分
15楼#
发布于:2002-03-28 21:01
运行添加设备函数PnPAddDevice后,运行即插即用函数中启动设备消息。

例程如下:

NTSTATUS PnP( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{

    PIO_STACK_LOCATION irpStack;
    PDEVICE_EXTENSION deviceExtension;
    NTSTATUS ntStatus = STATUS_SUCCESS;
    NTSTATUS waitStatus;
    PDEVICE_OBJECT stackDeviceObject;
    KEVENT startDeviceEvent;

    irpStack = IoGetCurrentIrpStackLocation (Irp);

    deviceExtension = DeviceObject->DeviceExtension;
    stackDeviceObject = deviceExtension->TopOfStackDeviceObject;

   // inc the FDO device extension\'s pending IO count for this Irp
    Pub_IncrementIoCount(DeviceObject);

    switch (irpStack->MinorFunction) {
    case IRP_MN_START_DEVICE:


        KeInitializeEvent(&startDeviceEvent, NotificationEvent, FALSE);
        IoCopyCurrentIrpStackLocationToNext(Irp);

        IoSetCompletionRoutine(Irp,
                               Pub_IrpCompletionRoutine,
                               &startDeviceEvent,  // pass the event to the completion routine as the Context
                               TRUE,    // invoke on success
                               TRUE,    // invoke on error
                               TRUE);   // invoke on cancellation

        ntStatus = IoCallDriver(stackDeviceObject,
                                Irp);

        // if PDO is not done yet, wait for the event to be set in our completion routine
        if (ntStatus == STATUS_PENDING) {
             // wait for irp to complete

            waitStatus = KeWaitForSingleObject(
                &startDeviceEvent,
                Suspended,
                KernelMode,
                FALSE,
                NULL);
        }
//===============================================================
        ntStatus = Usb_StartDevice(DeviceObject);
        Irp->IoStatus.Status = ntStatus;

      IoCompleteRequest (Irp,
                     IO_NO_INCREMENT);

      Pub_DecrementIoCount(DeviceObject);
      return ntStatus;  // end, case IRP_MN_START_DEVICE

    case IRP_MN_QUERY_STOP_DEVICE:

        if (!deviceExtension->DeviceStarted) { // if get when never started, just pass on
            IoSkipCurrentIrpStackLocation (Irp);
            ntStatus = IoCallDriver (deviceExtension->TopOfStackDeviceObject, Irp);
            Pub_DecrementIoCount(DeviceObject);
            return ntStatus;
        }
        // fail the request if we have any read/write IRPS pending
        if( deviceExtension->PendingIoCount > 1) {
            ntStatus = STATUS_UNSUCCESSFUL;
        }
        else {
             deviceExtension->StopDeviceRequested = TRUE;
             ntStatus = STATUS_SUCCESS;
        }
        Irp->IoStatus.Status = ntStatus;
        break;

    case IRP_MN_CANCEL_STOP_DEVICE:

        if (!deviceExtension->DeviceStarted) { // if get when never started, just pass on
            IoSkipCurrentIrpStackLocation (Irp);
            ntStatus = IoCallDriver (deviceExtension->TopOfStackDeviceObject, Irp);
            Pub_DecrementIoCount(DeviceObject);
            return ntStatus;
        }

      // Reset this flag so new IOCTL and IO Irp processing will be re-enabled
        deviceExtension->StopDeviceRequested = FALSE;
        break;

    case IRP_MN_STOP_DEVICE:
        Usb_CancelPendingIo(DeviceObject);
//=====================================================
        ntStatus = Usb_StopDevice(DeviceObject);
        Irp->IoStatus.Status = ntStatus;
        break;
    case IRP_MN_QUERY_REMOVE_DEVICE:
        if (!deviceExtension->DeviceStarted) { // if get when never started, just pass on
            IoSkipCurrentIrpStackLocation (Irp);
            ntStatus = IoCallDriver (deviceExtension->TopOfStackDeviceObject, Irp);
            Pub_DecrementIoCount(DeviceObject);

            return ntStatus;
        }

        deviceExtension->RemoveDeviceRequested = TRUE;

        waitStatus = KeWaitForSingleObject(
                    &deviceExtension->NoPendingIoEvent,
                    Suspended,
                    KernelMode,
                    FALSE,
                    NULL);

        Irp->IoStatus.Status = ntStatus;
        break;

    case IRP_MN_CANCEL_REMOVE_DEVICE:

        if (!deviceExtension->DeviceStarted) { // if get when never started, just pass on
            IoSkipCurrentIrpStackLocation (Irp);
            ntStatus = IoCallDriver (deviceExtension->TopOfStackDeviceObject, Irp);
            Pub_DecrementIoCount(DeviceObject);
            return ntStatus;
        }

      // Reset this flag so new IOCTL and IO Irp processing will be re-enabled
        deviceExtension->RemoveDeviceRequested = FALSE;

        break;

   case IRP_MN_SURPRISE_REMOVAL:
      // 意外删除
      Pub_DecrementIoCount(DeviceObject);

      deviceExtension->DeviceRemoved = TRUE;

      // 取消未完成的IO请求,取消管道
      //====================================
      Usb_CancelPendingIo(DeviceObject);
      Usb_AbortPipes(DeviceObject);

      Irp->IoStatus.Status = STATUS_SUCCESS;

      IoCopyCurrentIrpStackLocationToNext(Irp);

      ntStatus = IoCallDriver(stackDeviceObject,Irp);
      return ntStatus;

    case IRP_MN_REMOVE_DEVICE:

        Pub_DecrementIoCount(DeviceObject);

        deviceExtension->DeviceRemoved = TRUE;
        Usb_CancelPendingIo(DeviceObject);
      Usb_AbortPipes(DeviceObject);
        IoCopyCurrentIrpStackLocationToNext(Irp);

        Irp->IoStatus.Status = STATUS_SUCCESS;
        ntStatus = IoCallDriver(stackDeviceObject,
                                Irp);

        Pub_DecrementIoCount(DeviceObject);

        KeWaitForSingleObject(
                    &deviceExtension->RemoveEvent,
                    Suspended,
                    KernelMode,
                    FALSE,
                    NULL);
//==========================================
        PnP_RemoveDevice(DeviceObject);

        IoDetachDevice(deviceExtension->TopOfStackDeviceObject);

        IoDeleteDevice (DeviceObject);
        return ntStatus;
    default:
      ;
    }


    if (!NT_SUCCESS(ntStatus)) {

      // if anything went wrong, return failure  without passing Irp down
        Irp->IoStatus.Status = ntStatus;
      IoCompleteRequest (Irp,IO_NO_INCREMENT);
      Pub_DecrementIoCount(DeviceObject);
      return ntStatus;
    }
    IoCopyCurrentIrpStackLocationToNext(Irp);
    // All PNP_POWER messages get passed to the TopOfStackDeviceObject
    // we were given in PnPAddDevice
    ntStatus = IoCallDriver(stackDeviceObject,Irp);
    Pub_DecrementIoCount(DeviceObject);
    return ntStatus;
}

NTSTATUS Usb_StartDevice(IN  PDEVICE_OBJECT DeviceObject)
{
    PDEVICE_EXTENSION deviceExtension;
    NTSTATUS ntStatus;
    PUSB_DEVICE_DESCRIPTOR deviceDescriptor = NULL;
    PURB urb;
    ULONG siz;

    deviceExtension = DeviceObject->DeviceExtension;
    urb = ExAllocatePool(NonPagedPool,
                         sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
    if (urb) {

        siz = sizeof(USB_DEVICE_DESCRIPTOR);

        deviceDescriptor = ExAllocatePool(NonPagedPool,
                                          siz);
        if (deviceDescriptor) {

            UsbBuildGetDescriptorRequest(urb,
                         (USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST),
                         USB_DEVICE_DESCRIPTOR_TYPE,
                         0,
                         0,
                         deviceDescriptor,
                         NULL,
                         siz,
                         NULL);
         //===============================
            ntStatus = Usb_CallUSBD(DeviceObject, urb);
            if (NT_SUCCESS(ntStatus)) {
            }
        } else {
         // if we got here we failed to allocate deviceDescriptor
            ntStatus = STATUS_INSUFFICIENT_RESOURCES;
        }

        if (NT_SUCCESS(ntStatus)) {
            deviceExtension->UsbDeviceDescriptor = deviceDescriptor;
        } else if (deviceDescriptor) {
            ExFreePool(deviceDescriptor);
        }

        ExFreePool(urb);

    } else {
      // if we got here we failed to allocate the urb
        ntStatus = STATUS_INSUFFICIENT_RESOURCES;
    }

    if (NT_SUCCESS(ntStatus)) {//==============================
        ntStatus = Usb_ConfigureDevice(DeviceObject);
    }

    if (NT_SUCCESS(ntStatus)) {
        deviceExtension->DeviceStarted = TRUE;
    }
    return ntStatus;
}

NTSTATUS Usb_StopDevice(IN  PDEVICE_OBJECT DeviceObject)
{
    PDEVICE_EXTENSION deviceExtension;
    NTSTATUS ntStatus = STATUS_SUCCESS;
    PURB urb;
    ULONG siz;
    deviceExtension = DeviceObject->DeviceExtension;
    //
    // Send the select configuration urb with a NULL pointer for the configuration
    // handle. This closes the configuration and puts the device in the \'unconfigured\'
    // state.
    //
    siz = sizeof(struct _URB_SELECT_CONFIGURATION);
    urb = ExAllocatePool(NonPagedPool,siz);
    if (urb) {
        UsbBuildSelectConfigurationRequest(urb,
                                          (USHORT) siz,
                                          NULL);
        ntStatus = Usb_CallUSBD(DeviceObject, urb);
        ExFreePool(urb);
    } else {
        ntStatus = STATUS_INSUFFICIENT_RESOURCES;
    }
    if (NT_SUCCESS(ntStatus)) {
        deviceExtension->DeviceStarted = FALSE;
    }
    deviceExtension->StopDeviceRequested = FALSE;
    return ntStatus;
}

NTSTATUS Pub_IrpCompletionRoutine(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp,
    IN PVOID Context)
{
    PKEVENT event = Context;

    // Set the input event
    KeSetEvent(event,
               1,       // Priority increment  for waiting thread.
               FALSE);  // Flag this call is not immediately followed by wait.

    // This routine must return STATUS_MORE_PROCESSING_REQUIRED because we have not yet called
    // IoFreeIrp() on this IRP.
    return STATUS_MORE_PROCESSING_REQUIRED;

}
// 取消位处理的 IO
BOOLEAN Usb_CancelPendingIo(IN PDEVICE_OBJECT DeviceObject)
{
   PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
    PUCHAR pCon =  (PUCHAR) deviceExtension->PendingIoIrps;
   ULONG i = 0;
   PIRP Irp;
   USHORT uDriverCancel = 0;  // count cancelled via iocancelirp()
   BOOLEAN cRes;
    NTSTATUS ntStatus, waitStatus;

   // nothing pending
   if ( !deviceExtension->PendingIoIrps)
      return FALSE;

    // the BULKUSB_RW_CONTEXT array is terminated by an entry with a NULL Irp
   for ( i = 0; ((PUSB_RW_CONTEXT)pCon)->Irp ;  i++) {

      Irp = ((PUSB_RW_CONTEXT) pCon)->Irp;
      //
      // Since IoCallDriver has been called on this request, we call IoCancelIrp
      //  and let our completion routine handle it
      //
      cRes = IoCancelIrp(Irp);
      // if cancel call failed, they all will, so dump out
      if (!cRes)
         break;

        uDriverCancel++; // flag we tried to cancel at least one


        // point to next context struct in array
        pCon +=  sizeof( USB_RW_CONTEXT);
    } // end, for


    if (uDriverCancel && cRes) {

      // We only get here if we cancelled at least one and all cancellations were successfull.
        // Wait on the event set on last cancel in BulkUsb_AsyncReadWriteComplete();
        waitStatus = KeWaitForSingleObject(
                       &deviceExtension->StagingDoneEvent,
                       Suspended,
                       KernelMode,
                       FALSE,
                       NULL);
    }
    return (BOOLEAN) uDriverCancel;                                  
}

//取消管道
NTSTATUS Usb_AbortPipes(IN PDEVICE_OBJECT DeviceObject)
{
    NTSTATUS ntStatus = STATUS_SUCCESS;
    PURB urb;
    PDEVICE_EXTENSION deviceExtension;
   ULONG i;

    PUSBD_INTERFACE_INFORMATION interface;
   PUSB_PIPEINFO PipeInfo;

    deviceExtension = DeviceObject->DeviceExtension;
    interface = deviceExtension->UsbInterface;

    for (i=0; i<interface->NumberOfPipes; i++) {

        PipeInfo =  &deviceExtension->PipeInfo[ i ]; // PUSB_PIPEINFO  PipeInfo;

      if (PipeInfo->fPipeOpened) { // we set this if open, clear if closed
         urb = ExAllocatePool(NonPagedPool,
                         sizeof(struct _URB_PIPE_REQUEST));

         if (urb) {

            urb->UrbHeader.Length = (USHORT) sizeof (struct _URB_PIPE_REQUEST);
            urb->UrbHeader.Function = URB_FUNCTION_ABORT_PIPE;
            urb->UrbPipeRequest.PipeHandle =
               interface->Pipes[ i ].PipeHandle;

            ntStatus = Usb_CallUSBD(DeviceObject, urb);

            ExFreePool(urb);

         } else {
            ntStatus = STATUS_INSUFFICIENT_RESOURCES;
            break;
         }
         if (!(NT_SUCCESS(ntStatus))) {
            // if we failed, dump out
            break;
         }
         else {
            PipeInfo->fPipeOpened = FALSE; // mark the pipe \'closed\'

            deviceExtension->OpenPipeCount--;
         }
      } // end, if pipe open
   } // end, for all pipes
    return ntStatus;
}


NTSTATUS PnP_RemoveDevice(IN  PDEVICE_OBJECT DeviceObject)
{
    PDEVICE_EXTENSION deviceExtension;
    NTSTATUS ntStatus = STATUS_SUCCESS;
    deviceExtension = DeviceObject->DeviceExtension;
    ntStatus = IoSetDeviceInterfaceState(&deviceExtension->DeviceLinkNameBuffer, FALSE);

    if (deviceExtension->UsbDeviceDescriptor) {
        ExFreePool(deviceExtension->UsbDeviceDescriptor);
        deviceExtension->UsbDeviceDescriptor = NULL;
    }
    if (deviceExtension->PipeInfo) {

        ExFreePool(deviceExtension->PipeInfo);
        deviceExtension->PipeInfo = NULL;
    }
    if (deviceExtension->UsbInterface) {
        ExFreePool(deviceExtension->UsbInterface);
        deviceExtension->UsbInterface = NULL;
    }
    if (deviceExtension->UsbConfigurationDescriptor) {
        ExFreePool(deviceExtension->UsbConfigurationDescriptor);
        deviceExtension->UsbConfigurationDescriptor = NULL;
    }
    if ( deviceExtension->PendingIoIrps) {
        ExFreePool(deviceExtension->PendingIoIrps);
        deviceExtension->PendingIoIrps = NULL;
    }
    if ( deviceExtension->PendingIoIrps) {
        RtlFreeUnicodeString(&deviceExtension->DeviceLinkNameBuffer);
    }
    return ntStatus;
}

NTSTATUS Usb_ConfigureDevice(
    IN  PDEVICE_OBJECT DeviceObject
)
{
    PDEVICE_EXTENSION deviceExtension;
    NTSTATUS ntStatus;
    PURB urb;
    ULONG siz;

    deviceExtension = DeviceObject->DeviceExtension;
    urb = ExAllocatePool(NonPagedPool,
                         sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
   if ( !urb)
      return STATUS_INSUFFICIENT_RESOURCES;
   // When USB_CONFIGURATION_DESCRIPTOR_TYPE is specified for DescriptorType
   // in a call to UsbBuildGetDescriptorRequest(),
   // all interface, endpoint, class-specific, and vendor-specific descriptors
   // for the configuration also are retrieved.
   // The caller must allocate a buffer large enough to hold all of this
   // information or the data is truncated without error.
   // Therefore the \'siz\' set below is just a \'good guess\', and we may have to retry

    siz = sizeof(USB_CONFIGURATION_DESCRIPTOR) + 512;  

   // We will break out of this \'retry loop\' when UsbBuildGetDescriptorRequest()
   // has a big enough deviceExtension->UsbConfigurationDescriptor buffer not to truncate
   while( 1) {

      deviceExtension->UsbConfigurationDescriptor = ExAllocatePool(NonPagedPool, siz);

      if ( !deviceExtension->UsbConfigurationDescriptor) {
          ExFreePool(urb);
         return STATUS_INSUFFICIENT_RESOURCES;
      }

      UsbBuildGetDescriptorRequest(urb,
          (USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST),
          USB_CONFIGURATION_DESCRIPTOR_TYPE,
          0,
          0,
          deviceExtension->UsbConfigurationDescriptor,
          NULL,
          siz,
          NULL);

      ntStatus = Usb_CallUSBD(DeviceObject, urb);
      // if we got some data see if it was enough.
      // NOTE: we may get an error in URB because of buffer overrun
      if (urb->UrbControlDescriptorRequest.TransferBufferLength>0 &&
            deviceExtension->UsbConfigurationDescriptor->wTotalLength > siz) {

         siz = deviceExtension->UsbConfigurationDescriptor->wTotalLength;
         ExFreePool(deviceExtension->UsbConfigurationDescriptor);
         deviceExtension->UsbConfigurationDescriptor = NULL;
      } else {
         break;
      }
   }

    ExFreePool(urb);
//==================================================
    ntStatus = Usb_SelectInterface(DeviceObject,
        deviceExtension->UsbConfigurationDescriptor);
    return ntStatus;
}

NTSTATUS Usb_SelectInterface(
    IN PDEVICE_OBJECT DeviceObject,
    IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor
)
{
    PDEVICE_EXTENSION deviceExtension;
    NTSTATUS ntStatus;
    PURB urb = NULL;
    ULONG i;
    PUSB_INTERFACE_DESCRIPTOR interfaceDescriptor = NULL;
   PUSBD_INTERFACE_INFORMATION Interface = NULL;
    USHORT siz;
    PUCHAR pInf;

    deviceExtension = DeviceObject->DeviceExtension;

    urb = USBD_CreateConfigurationRequest(ConfigurationDescriptor, &siz);

    if (urb) {

      interfaceDescriptor =
            USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor,
                          ConfigurationDescriptor, //search from start of config  descriptro
                          -1,   // interface number not a criteria; we only support one interface
                          -1,   // not interested in alternate setting here either
                          -1,   // interface class not a criteria
                          -1,   // interface subclass not a criteria
                          -1    // interface protocol not a criteria
);

      if ( !interfaceDescriptor) {
         ExFreePool(urb);
         return STATUS_INSUFFICIENT_RESOURCES;
      }

        Interface = &urb->UrbSelectConfiguration.Interface;

        deviceExtension->PipeInfo = ExAllocatePool(
            NonPagedPool,
            Interface->NumberOfPipes * sizeof ( USB_PIPEINFO));
    
        if ( !deviceExtension->PipeInfo) {
          return STATUS_INSUFFICIENT_RESOURCES;
        }

        RtlZeroMemory(deviceExtension->PipeInfo,
            Interface->NumberOfPipes * sizeof ( USB_PIPEINFO));

        pInf = (PUCHAR) deviceExtension->PipeInfo;

        for (i=0; i< Interface->NumberOfPipes; i++) {
            Interface->Pipes[ i ].MaximumTransferSize = deviceExtension->MaximumTransferSize;
            ( (PUSB_PIPEINFO) pInf)->fPipeOpened = FALSE;
            pInf += sizeof ( USB_PIPEINFO);
        }

        UsbBuildSelectConfigurationRequest(urb,
                                          (USHORT) siz,
                                          ConfigurationDescriptor);


        ntStatus = Usb_CallUSBD(DeviceObject, urb);

        deviceExtension->UsbConfigurationHandle =
            urb->UrbSelectConfiguration.ConfigurationHandle;

    } else {
        ntStatus = STATUS_INSUFFICIENT_RESOURCES;
    }
    if (NT_SUCCESS(ntStatus)) {
        // Save the configuration handle for this device
        deviceExtension->UsbConfigurationHandle =
            urb->UrbSelectConfiguration.ConfigurationHandle;

        deviceExtension->UsbInterface = ExAllocatePool(NonPagedPool,
                                                    Interface->Length);
        if (deviceExtension->UsbInterface) {
            RtlCopyMemory(deviceExtension->UsbInterface, Interface, Interface->Length);
            }
    }
    if (urb) {
        ExFreePool(urb);
    }
    return ntStatus;
}
//发送URB
NTSTATUS Usb_CallUSBD(
    IN PDEVICE_OBJECT DeviceObject,
    IN PURB Urb
)
{
    NTSTATUS ntStatus, status = STATUS_SUCCESS;
    PDEVICE_EXTENSION deviceExtension;
    PIRP irp;
    KEVENT event;
    IO_STATUS_BLOCK ioStatus;
    PIO_STACK_LOCATION nextStack;

    deviceExtension = DeviceObject->DeviceExtension;
    // issue a synchronous request
    KeInitializeEvent(&event, NotificationEvent, FALSE);

    irp = IoBuildDeviceIoControlRequest(
                IOCTL_INTERNAL_USB_SUBMIT_URB,
                deviceExtension->TopOfStackDeviceObject, //Points to the next-lower driver\'s device object
                NULL, // optional input bufer; none needed here
                0,     // input buffer len if used
                NULL, // optional output bufer; none needed here
                0,    // output buffer len if used
                TRUE, // If InternalDeviceControl is TRUE the target driver\'s Dispatch
                  //  outine for IRP_MJ_INTERNAL_DEVICE_CONTROL or IRP_MJ_SCSI
                 // is called; otherwise, the Dispatch routine for
                 // IRP_MJ_DEVICE_CONTROL is called.
                &event,     // event to be signalled on completion
                &ioStatus);  // Specifies an I/O status block to be set when the request is completed the lower driver.

    if (!irp) {
        return STATUS_INSUFFICIENT_RESOURCES;
    }
    //
    // Call the class driver to perform the operation.  If the returned status
    // is PENDING, wait for the request to complete.
    //

    nextStack = IoGetNextIrpStackLocation(irp);
    //
    // pass the URB to the USB driver stack
    //
    nextStack->Parameters.Others.Argument1 = Urb;

    ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, irp);
    if (ntStatus == STATUS_PENDING) {
        status = KeWaitForSingleObject(
                       &event,
                       Suspended,
                       KernelMode,
                       FALSE,
                       NULL);
    } else {
        ioStatus.Status = ntStatus;
    }
    // USBD maps the error code for us
    ntStatus = ioStatus.Status;
    return ntStatus;
}

VOID Pub_IncrementIoCount(IN PDEVICE_OBJECT DeviceObject)
{
    PDEVICE_EXTENSION deviceExtension;
    deviceExtension = DeviceObject->DeviceExtension;
    InterlockedIncrement(&deviceExtension->PendingIoCount);
}

LONG Pub_DecrementIoCount(IN PDEVICE_OBJECT DeviceObject)
{
    PDEVICE_EXTENSION deviceExtension;
    LONG ioCount;
    //KIRQL             oldIrql;
    deviceExtension = DeviceObject->DeviceExtension;
   //KeAcquireSpinLock (&deviceExtension->IoCountSpinLock, &oldIrql);
    ioCount = InterlockedDecrement(&deviceExtension->PendingIoCount);
    if (ioCount==1) {
        // trigger no pending io
        KeSetEvent(&deviceExtension->NoPendingIoEvent,
                   1,
                   FALSE);
    }
    if (ioCount==0) {
        // trigger remove-device event
        KeSetEvent(&deviceExtension->RemoveEvent,1,FALSE);
    }
   //KeReleaseSpinLock (&deviceExtension->IoCountSpinLock, oldIrql);
    return ioCount;
}

BOOLEAN Pub_CanAcceptIoRequests(
    IN PDEVICE_OBJECT DeviceObject
)
{
    PDEVICE_EXTENSION deviceExtension;
   BOOLEAN fCan = FALSE;

    deviceExtension = DeviceObject->DeviceExtension;

   //flag set when processing IRP_MN_REMOVE_DEVICE
    if ( !deviceExtension->DeviceRemoved &&
       // device must be started( enabled)
       deviceExtension->DeviceStarted &&
        // flag set when driver has answered success to IRP_MN_QUERY_REMOVE_DEVICE
       !deviceExtension->RemoveDeviceRequested &&
       // flag set when driver has answered success to IRP_MN_QUERY_STOP_DEVICE
       !deviceExtension->StopDeviceRequested){
         fCan = TRUE;
   }
   return fCan;
}


[编辑 -  3/29/02 作者: plasma]
plasma
驱动小牛
驱动小牛
  • 注册日期2002-02-19
  • 最后登录2008-02-27
  • 粉丝0
  • 关注0
  • 积分50分
  • 威望5点
  • 贡献值0点
  • 好评度5点
  • 原创分0分
  • 专家分0分
16楼#
发布于:2002-03-28 21:05
电源管理:主要是处理远程唤醒、设置设备电源状态

例程如下:

NTSTATUS pwr(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP           Irp)
{

    PIO_STACK_LOCATION irpStack;
    NTSTATUS ntStatus = STATUS_SUCCESS;
    PDEVICE_EXTENSION deviceExtension;
    BOOLEAN fGoingToD0 = FALSE;
    POWER_STATE sysPowerState, desiredDevicePowerState;
    KEVENT event;
    deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
    irpStack = IoGetCurrentIrpStackLocation (Irp);
    Pub_IncrementIoCount(DeviceObject);

    switch (irpStack->MinorFunction) {
    case IRP_MN_WAIT_WAKE:
      // A driver sends IRP_MN_WAIT_WAKE to indicate that the system should
      // wait for its device to signal a wake event. The exact nature of the event
      // is device-dependent.
      // Drivers send this IRP for two reasons:
      // 1) To allow a device to wake the system
      // 2) To wake a device that has been put into a sleep state to save power
      //    but still must be able to communicate with its driver under certain circumstances.
      // When a wake event occurs, the driver completes the IRP and returns
      // STATUS_SUCCESS. If the device is sleeping when the event occurs,
      // the driver must first wake up the device before completing the IRP.
      // In a completion routine, the driver calls PoRequestPowerIrp to send a
      // PowerDeviceD0 request. When the device has powered up, the driver can
      //  handle the IRP_MN_WAIT_WAKE request.

        // deviceExtension->DeviceCapabilities.DeviceWake specifies the lowest device power state (least powered)
        // from which the device can signal a wake event
        deviceExtension->PowerDownLevel = deviceExtension->DeviceCapabilities.DeviceWake;


        if  ((PowerDeviceD0 == deviceExtension->CurrentDevicePowerState)  ||
              (deviceExtension->DeviceCapabilities.DeviceWake > deviceExtension->CurrentDevicePowerState)) {
         //
         //    STATUS_INVALID_DEVICE_STATE is returned if the device in the PowerD0 state
         //    or a state below which it can support waking, or if the SystemWake state
         //    is below a state which can be supported. A pending IRP_MN_WAIT_WAKE will complete
         //    with this error if the device\'s state is changed to be incompatible with the wake
         //    request.

            //  If a driver fails this IRP, it should complete the IRP immediately without
            //  passing the IRP to the next-lower driver.
            ntStatus = STATUS_INVALID_DEVICE_STATE;
            Irp->IoStatus.Status = ntStatus;
            IoCompleteRequest (Irp,IO_NO_INCREMENT);
            Pub_DecrementIoCount(DeviceObject);
            return ntStatus;
        }

        // flag we\'re enabled for wakeup
        deviceExtension->EnabledForWakeup = TRUE;

        // init an event for our completion routine to signal when PDO is done with this Irp
        KeInitializeEvent(&event, NotificationEvent, FALSE);

       // If not failing outright, pass this on to our PDO for further handling
        IoCopyCurrentIrpStackLocationToNext(Irp);

        // Set a completion routine so it can signal our event when
        //  the PDO is done with the Irp
        IoSetCompletionRoutine(Irp,
                               Pub_IrpCompletionRoutine,
                               &event,  // pass the event to the completion routine as the Context
                               TRUE,    // invoke on success
                               TRUE,    // invoke on error
                               TRUE);   // invoke on cancellation

        PoStartNextPowerIrp(Irp);
        ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject,
                                Irp);

         // if PDO is not done yet, wait for the event to be set in our completion routine
        if (ntStatus == STATUS_PENDING) {
             // wait for irp to complete

            NTSTATUS waitStatus = KeWaitForSingleObject(
                &event,
                Suspended,
                KernelMode,
                FALSE,
                NULL);
        }

      // now tell the device to actually wake up
      Usb_SelfSuspendOrActivate(DeviceObject, FALSE);

        // flag we\'re done with wakeup irp
        deviceExtension->EnabledForWakeup = FALSE;

        Pub_DecrementIoCount(DeviceObject);
        break;
    case IRP_MN_SET_POWER:
        {

      // The system power policy manager sends this IRP to set the system power state.
      // A device power policy manager sends this IRP to set the device power state for a device.
        // Set Irp->IoStatus.Status to STATUS_SUCCESS to indicate that the device
        // has entered the requested state. Drivers cannot fail this IRP.

        switch (irpStack->Parameters.Power.Type) {
            case SystemPowerState:

                // Get input system power state
                sysPowerState.SystemState = irpStack->Parameters.Power.State.SystemState;

                // If system is in working state always set our device to D0
                //  regardless of the wait state or system-to-device state power map
                if (sysPowerState.SystemState ==  PowerSystemWorking) {
                    desiredDevicePowerState.DeviceState = PowerDeviceD0;
                } else {
                     // set to corresponding system state if IRP_MN_WAIT_WAKE pending
                    if (deviceExtension->EnabledForWakeup) { // got a WAIT_WAKE IRP pending?

                        // Find the device power state equivalent to the given system state.
                        // We get this info from the DEVICE_CAPABILITIES struct in our device
                        // extension (initialized in AddDevice())
                        desiredDevicePowerState.DeviceState =
                            deviceExtension->DeviceCapabilities.DeviceState[ sysPowerState.SystemState ];
                    } else {  
                        // if no wait pending and the system\'s not in working state, just turn off
                        desiredDevicePowerState.DeviceState = PowerDeviceD3;
                    }
                }

                //
                // We\'ve determined the desired device state; are we already in this state?
                //

                if (desiredDevicePowerState.DeviceState !=
                    deviceExtension->CurrentDevicePowerState) {


                    // No, request that we be put into this state
               // by requesting a new Power Irp from the Pnp manager
                    deviceExtension->PowerIrp = Irp;
                    ntStatus = PoRequestPowerIrp(deviceExtension->PhysicalDeviceObject,
                                   IRP_MN_SET_POWER,
                                   desiredDevicePowerState,
                           // completion routine will pass the Irp down to the PDO
                                   pwr_PoRequestCompletion,
                                   DeviceObject,
                                   NULL);

                } else {
                    // Yes, just pass it on to PDO (Physical Device Object)
                    IoCopyCurrentIrpStackLocationToNext(Irp);
                    PoStartNextPowerIrp(Irp);
                    ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject,
                                            Irp);

                    Pub_DecrementIoCount(DeviceObject);
                }
                break;
            case DevicePowerState:
                // For requests to D1, D2, or D3 (sleep or off states),
            // sets deviceExtension->CurrentDevicePowerState to DeviceState immediately.
            // This enables any code checking state to consider us as sleeping or off
            // already, as this will imminently become our state.

                // For requests to DeviceState D0 (fully on), sets fGoingToD0 flag TRUE
                // to flag that we must set a completion routine and update
            // deviceExtension->CurrentDevicePowerState there.
            // In the case of powering up to fully on, we really want to make sure
            // the process is completed before updating our CurrentDevicePowerState,
            // so no IO will be attempted or accepted before we\'re really ready.

                fGoingToD0 = pwr_SetDevicePowerState(DeviceObject,
                                irpStack->Parameters.Power.State.DeviceState);
                                // returns TRUE for D0

                IoCopyCurrentIrpStackLocationToNext(Irp);

                if (fGoingToD0) {
                    IoSetCompletionRoutine(Irp,
                           pwr_PowerIrp_Complete,
                           // Always pass FDO to completion routine as its Context;
                           // This is because the DriverObject passed by the system to the routine
                           // is the Physical Device Object (PDO) not the Functional Device Object (FDO)
                           DeviceObject,
                           TRUE,            // invoke on success
                           TRUE,            // invoke on error
                           TRUE);           // invoke on cancellation of the Irp
                }

                PoStartNextPowerIrp(Irp);
                ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject,
                                        Irp);

                if (!fGoingToD0) // completion routine will decrement
                    Pub_DecrementIoCount(DeviceObject);
                break;
            } /* case irpStack->Parameters.Power.Type */
        }
        break; /* IRP_MN_SET_POWER */
    case IRP_MN_QUERY_POWER:
      //
      // A power policy manager sends this IRP to determine whether it can change
      // the system or device power state, typically to go to sleep.
      //

        // We do nothing special here, just let the PDO handle it
        IoCopyCurrentIrpStackLocationToNext(Irp);
        PoStartNextPowerIrp(Irp);
        ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject,
                                Irp);


        Pub_DecrementIoCount(DeviceObject);

        break; /* IRP_MN_QUERY_POWER */

    default:
        //
        // All unhandled power messages are passed on to the PDO
        //
        IoCopyCurrentIrpStackLocationToNext(Irp);
        PoStartNextPowerIrp(Irp);
        ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);

        Pub_DecrementIoCount(DeviceObject);

    }
    return ntStatus;
}

NTSTATUS pwr_PoRequestCompletion(
    IN PDEVICE_OBJECT       DeviceObject,
    IN UCHAR                MinorFunction,
    IN POWER_STATE          PowerState,
    IN PVOID                Context,
    IN PIO_STATUS_BLOCK     IoStatus)
{
    PIRP irp;
    PDEVICE_EXTENSION deviceExtension;
    PDEVICE_OBJECT deviceObject = Context;
    NTSTATUS ntStatus;

    deviceExtension = deviceObject->DeviceExtension;
    irp = deviceExtension->PowerIrp;
    ntStatus = IoStatus->Status;

    IoCopyCurrentIrpStackLocationToNext(irp);

    // Calling PoStartNextPowerIrp() indicates that the driver is finished
    // with the previous power IRP, if any, and is ready to handle the next power IRP.
    // It must be called for every power IRP.Although power IRPs are completed only once,
    // typically by the lowest-level driver for a device, PoStartNextPowerIrp must be called
    // for every stack location. Drivers must call PoStartNextPowerIrp while the current IRP
    // stack location points to the current driver. Therefore, this routine must be called
    // before IoCompleteRequest, IoSkipCurrentStackLocation, and PoCallDriver.

    PoStartNextPowerIrp(irp);

    // PoCallDriver is used to pass any power IRPs to the PDO instead of IoCallDriver.
    // When passing a power IRP down to a lower-level driver, the caller should use
    // IoSkipCurrentIrpStackLocation or IoCopyCurrentIrpStackLocationToNext to copy the IRP to
    // the next stack location, then call PoCallDriver. Use IoCopyCurrentIrpStackLocationToNext
    // if processing the IRP requires setting a completion routine, or IoSkipCurrentStackLocation
    // if no completion routine is needed.

    PoCallDriver(deviceExtension->TopOfStackDeviceObject,irp);

    Pub_DecrementIoCount(deviceObject);

    deviceExtension->PowerIrp = NULL;
    return ntStatus;
}

NTSTATUS pwr_PowerIrp_Complete(
    IN PDEVICE_OBJECT NullDeviceObject,
    IN PIRP Irp,
    IN PVOID Context)
{
    NTSTATUS ntStatus = STATUS_SUCCESS;
    PDEVICE_OBJECT deviceObject;
    PIO_STACK_LOCATION irpStack;
    PDEVICE_EXTENSION deviceExtension;

    deviceObject = (PDEVICE_OBJECT) Context;
    deviceExtension = (PDEVICE_EXTENSION) deviceObject->DeviceExtension;

    //  If the lower driver returned PENDING, mark our stack location as pending also.
    if (Irp->PendingReturned) {
        IoMarkIrpPending(Irp);
    }

    irpStack = IoGetCurrentIrpStackLocation (Irp);

    // We can assert that we\'re a  device powerup-to D0 request,
    // because that was the only type of request we set a completion routine
    // for in the first place

    // Now that we know we\'ve let the lower drivers do what was needed to power up,
    //  we can set our device extension flags accordingly
    deviceExtension->CurrentDevicePowerState = PowerDeviceD0;

    Irp->IoStatus.Status = ntStatus;

    Pub_DecrementIoCount(deviceObject);
    return ntStatus;
}

NTSTATUS Usb_SelfSuspendOrActivate(
    IN PDEVICE_OBJECT DeviceObject,
    IN BOOLEAN fSuspend)
{
    NTSTATUS ntStatus = STATUS_SUCCESS;

    POWER_STATE PowerState;
    PDEVICE_EXTENSION deviceExtension;

    deviceExtension = DeviceObject->DeviceExtension;

    if (!Pub_CanAcceptIoRequests(DeviceObject)) {
        ntStatus = STATUS_DELETE_PENDING;
        return ntStatus;
    }
     // don\'t do anything if any System-generated Device Pnp irps are pending
    if (NULL != deviceExtension->PowerIrp) {
        return ntStatus;
    }

    // don\'t do anything if any self-generated Device Pnp irps are pending
    if (deviceExtension->SelfPowerIrp) {
        return ntStatus;
    }
    // don\'t auto-suspend if any pipes are open
    if (fSuspend && (0 != deviceExtension->OpenPipeCount)) {
        return ntStatus;
    }
    // don\'t auto-activate if no pipes are open
    if (!fSuspend && (0 == deviceExtension->OpenPipeCount)) {
        return ntStatus;
    }
    // dont do anything if registry CurrentControlSet\\Services\\IsoUsb\\Parameters\\PowerDownLevel
    //  has been set to  zero, PowerDeviceD0 (1), or a bogus high value
    if ((deviceExtension->PowerDownLevel == PowerDeviceD0) ||
         (deviceExtension->PowerDownLevel == PowerDeviceUnspecified)  ||
         (deviceExtension->PowerDownLevel >= PowerDeviceMaximum)) {
        return ntStatus;
    }
    if (fSuspend)
        PowerState.DeviceState = deviceExtension->PowerDownLevel;
    else
        PowerState.DeviceState = PowerDeviceD0;  // power up all the way; we\'re probably just about to do some IO
    
   ntStatus = pwr_SelfRequestPowerIrp(DeviceObject, PowerState);
    return ntStatus;
}


NTSTATUS pwr_SelfRequestPowerIrp(
    IN PDEVICE_OBJECT DeviceObject,
    IN POWER_STATE PowerState
)
{
    NTSTATUS ntStatus = STATUS_SUCCESS;
    PDEVICE_EXTENSION deviceExtension;
    PIRP pIrp = NULL;

    deviceExtension =  DeviceObject->DeviceExtension;

    // This should have been reset in completion routine
    if (deviceExtension->CurrentDevicePowerState ==  PowerState.DeviceState)
        return STATUS_SUCCESS;  // nothing to do

    Pub_IncrementIoCount(DeviceObject);

   // flag we\'re handling a self-generated power irp
    deviceExtension->SelfPowerIrp = TRUE;

   // actually request the Irp
    ntStatus = PoRequestPowerIrp(deviceExtension->PhysicalDeviceObject,
                         IRP_MN_SET_POWER,
                         PowerState,
                         pwr_PoSelfRequestCompletion,
                         DeviceObject,
                         NULL);


    if  (ntStatus == STATUS_PENDING) {
        // status pending is the return code we wanted

        // We only need to wait for completion if we\'re powering up
        if ((ULONG) PowerState.DeviceState < deviceExtension->PowerDownLevel) {

            NTSTATUS waitStatus;

            waitStatus = KeWaitForSingleObject(
                           &deviceExtension->SelfRequestedPowerIrpEvent,
                           Suspended,
                           KernelMode,
                           FALSE,
                           NULL);

        }

        ntStatus = STATUS_SUCCESS;
        deviceExtension->SelfPowerIrp = FALSE;
    }
    else {
        // The return status was not STATUS_PENDING; any other codes must be considered in error here;
        //  i.e., it is not possible to get a STATUS_SUCCESS  or any other non-error return from this call;
           ;
    }
    return ntStatus;
}

NTSTATUS pwr_PoSelfRequestCompletion(
    IN PDEVICE_OBJECT       DeviceObject,
    IN UCHAR                MinorFunction,
    IN POWER_STATE          PowerState,
    IN PVOID                Context,
    IN PIO_STATUS_BLOCK     IoStatus
)
{
    PDEVICE_OBJECT deviceObject = Context;
    PDEVICE_EXTENSION deviceExtension = deviceObject->DeviceExtension;
    NTSTATUS ntStatus = IoStatus->Status;

    // we should not be in the midst of handling a system-generated power irp

    // We only need to set the event if we\'re powering up;
    // No caller waits on power down complete
    if ((ULONG) PowerState.DeviceState < deviceExtension->PowerDownLevel) {

        // Trigger Self-requested power irp completed event;
        //  The caller is waiting for completion
        KeSetEvent(&deviceExtension->SelfRequestedPowerIrpEvent, 1, FALSE);
    }

    Pub_DecrementIoCount(deviceObject);
    return ntStatus;
}

BOOLEAN pwr_SetDevicePowerState(
    IN PDEVICE_OBJECT DeviceObject,
    IN DEVICE_POWER_STATE DeviceState
)
{
    NTSTATUS ntStatus = STATUS_SUCCESS;
    PDEVICE_EXTENSION deviceExtension;
    BOOLEAN fRes = FALSE;

    deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;

    switch (DeviceState) {
    case PowerDeviceD3:

        //
        // Device will be going OFF,
      // TODO: add any needed device-dependent code to save state here.
      //  (We have nothing to do in this sample)
        deviceExtension->CurrentDevicePowerState = DeviceState;
        break;

    case PowerDeviceD1:
    case PowerDeviceD2:
        // power states D1,D2 translate to USB suspend
        deviceExtension->CurrentDevicePowerState = DeviceState;
        break;
    case PowerDeviceD0:
        // We\'ll need to finish the rest in the completion routine;
        //   signal caller we\'re going to D0 and will need to set a completion routine
        fRes = TRUE;
        // Caller will pass on to PDO (Physical Device object)
        break;
    default:
      ;
    }
    return fRes;
}


[编辑 -  3/29/02 作者: plasma]
plasma
驱动小牛
驱动小牛
  • 注册日期2002-02-19
  • 最后登录2008-02-27
  • 粉丝0
  • 关注0
  • 积分50分
  • 威望5点
  • 贡献值0点
  • 好评度5点
  • 原创分0分
  • 专家分0分
17楼#
发布于:2002-03-28 21:14
驱动程序与Windows应用程序交互:打开文件、关闭文件、读、写

例程如下:

NTSTATUS win32_Create(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)
{
    NTSTATUS ntStatus = STATUS_SUCCESS;
    PFILE_OBJECT fileObject;
    PIO_STACK_LOCATION irpStack;
    PDEVICE_EXTENSION deviceExtension;
    ULONG i, ix;
   NTSTATUS actStat;
    PUSBD_INTERFACE_INFORMATION interface;
   PUSBD_PIPE_INFORMATION PipeInfo;
    PUSB_PIPEINFO ourPipeInfo = NULL;

    deviceExtension = DeviceObject->DeviceExtension;
    interface = deviceExtension->UsbInterface;
    Pub_IncrementIoCount(DeviceObject);

    if (!Pub_CanAcceptIoRequests(DeviceObject)) {
        ntStatus = STATUS_DELETE_PENDING;
        goto done;
    }
    irpStack = IoGetCurrentIrpStackLocation (Irp);
    fileObject = irpStack->FileObject;
    // fscontext is null for device
    fileObject->FsContext = NULL;
    if (0 == fileObject->FileName.Length) // this is the case if opening device as opposed to pipe
        goto done;      // nothing more to do
    ourPipeInfo = win32_PipeWithName(DeviceObject, &fileObject->FileName);
    if (!ourPipeInfo) {
        ntStatus = STATUS_INVALID_PARAMETER;
        goto done;
    }
   // init status to bad; will set good in below loop on success
   ntStatus = STATUS_INSUFFICIENT_RESOURCES;
   for (i=0; i<interface->NumberOfPipes; i++) {
      PipeInfo =  &interface->Pipes[ i ]; // PUSBD_PIPE_INFORMATION  PipeInfo;
        if (ourPipeInfo == &deviceExtension->PipeInfo[ i ]) {
         // found a match
         fileObject->FsContext = PipeInfo;
         ourPipeInfo->fPipeOpened = TRUE; // set flag for opened
         ntStatus = STATUS_SUCCESS;
         deviceExtension->OpenPipeCount++;
         // try to power up device if its not in D0
         actStat = Usb_SelfSuspendOrActivate(DeviceObject, FALSE);
         break;
      }
   }
done:
    Irp->IoStatus.Status = ntStatus;
    Irp->IoStatus.Information = 0;
    IoCompleteRequest (Irp,IO_NO_INCREMENT);
    Pub_DecrementIoCount(DeviceObject);                              
    return ntStatus;
}

NTSTATUS win32_Read(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)
{
   NTSTATUS ntStatus;
/**/
   ntStatus = Iso_ReadWrite(DeviceObject,
                              Irp,
                              TRUE);   // false to write, true to read
/** /
   ntStatus = Bulk_ReadWrite(DeviceObject,
                              Irp,
                              TRUE);   // false to write, true to read
/**/
    return ntStatus;                                  
}

NTSTATUS win32_Write(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)
{  
   NTSTATUS ntStatus;
/**/
   ntStatus = Iso_ReadWrite(DeviceObject,
                             Irp,
                             FALSE);   // false to write, true to read
/** /
   ntStatus = Bulk_ReadWrite(DeviceObject,
                              Irp,
                              FALSE);   // false to write, true to read
/**/
    return ntStatus;                                  
}

NTSTATUS win32_Close(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)
{
    NTSTATUS ntStatus;
   NTSTATUS actStat;
    PFILE_OBJECT fileObject;
    PIO_STACK_LOCATION irpStack;
    PDEVICE_EXTENSION deviceExtension;
    PUSBD_PIPE_INFORMATION pipeHandle = NULL;
    PUSB_PIPEINFO pipeInfo = NULL;
    Pub_IncrementIoCount(DeviceObject);

    deviceExtension = DeviceObject->DeviceExtension;
    irpStack = IoGetCurrentIrpStackLocation (Irp);
    fileObject = irpStack->FileObject;

    if (fileObject->FsContext) {
        // closing pipe handle
        pipeHandle =  fileObject->FsContext;
        pipeInfo = win32_PipeWithName(DeviceObject, &fileObject->FileName);
        if (NULL == pipeInfo)
            goto done;
      if (pipeInfo->fPipeOpened) { // set if opened
         // may have been aborted
         deviceExtension->OpenPipeCount--;
         pipeInfo->fPipeOpened = FALSE;
      }
      else {
         // pipe was already closed; this can only be if we got a sudden REMOVE_DEVICE
      }
    }
done:
   Pub_DecrementIoCount(DeviceObject);
    Irp->IoStatus.Status = STATUS_SUCCESS;
    Irp->IoStatus.Information = 0;
    ntStatus = Irp->IoStatus.Status;
    IoCompleteRequest (Irp,IO_NO_INCREMENT);
   // try to power down device if this is the last pipe
   actStat = Usb_SelfSuspendOrActivate(DeviceObject, TRUE);
    return ntStatus;
}

/*++
Routine Description:
    Given a PUSBD_PIPE_INFORMATION, return our device extension pipe info struct
      that has this hanndle, else NULL
--*/
PUSB_PIPEINFO win32_PipeWithName(
    IN PDEVICE_OBJECT DeviceObject,
    IN PUNICODE_STRING FileName
)
{
    PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
    PUSB_PIPEINFO pipeInfo = NULL;
    ULONG i, nameLen, ix, uval , umultiplier;
   nameLen = FileName->Length;
    if (nameLen != 0) {
      // Get pipe# to open
      ix = nameLen -1;  // index last char of pipe name
      // if last char isn\'t digit, decrement till it is
      while(((FileName->Buffer[ ix ] < (WCHAR) \'0\') ||
            (FileName->Buffer[ ix ] > (WCHAR) \'9\')) && ix)
            ix--;  
      if (ix)  {  //  filename better have had at least one ascii digit!    
         //
         // A name was specified, convert it to a pipe id.
         // Parse the ansi ascii decimal 0-based pipe number
         //
         uval = 0;
         umultiplier = 1;
         // we\'re traversing least-to-most significant digits
         while(((FileName->Buffer[ ix ] >= (WCHAR) \'0\') &&
            (FileName->Buffer[ ix ] <= (WCHAR) \'9\')) && ix) {
            uval +=  (umultiplier *
                    (ULONG) (FileName->Buffer[ ix ] - (WCHAR) \'0\'));
            ix--;
            umultiplier *= 10;
            }
      }
        pipeInfo = &deviceExtension->PipeInfo[ uval ];
    }
    return pipeInfo;
}

[编辑 -  3/29/02 作者: plasma]
plasma
驱动小牛
驱动小牛
  • 注册日期2002-02-19
  • 最后登录2008-02-27
  • 粉丝0
  • 关注0
  • 积分50分
  • 威望5点
  • 贡献值0点
  • 好评度5点
  • 原创分0分
  • 专家分0分
18楼#
发布于:2002-03-28 21:19
USB批传输

例程如下:

NTSTATUS Bulk_ReadWrite(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp,
    IN BOOLEAN Read)
{
    NTSTATUS ntStatus = STATUS_SUCCESS;
    NTSTATUS resetPipeStatus;
    PFILE_OBJECT fileObject;
    PIO_STACK_LOCATION irpStack, nextStack;
    PURB urb;
    PIRP irp;
    PMDL mdl;
    PVOID va;
    CHAR stackSize;
    KIRQL OldIrql;
    BOOLEAN fRes;
    NTSTATUS waitStatus;
    ULONG i, nIrps = 0, totalLength = 0, totalIrpsNeeded, used;
    PUSBD_PIPE_INFORMATION pipeHandle = NULL;
    PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
    PUCHAR pCon =  NULL;
    ULONG ChunkSize = deviceExtension->MaximumTransferSize;
    ULONG arraySize;
    PUSB_RW_CONTEXT context = NULL;
    Irp->IoStatus.Information = 0;

    if (!Pub_CanAcceptIoRequests(DeviceObject)) {
        ntStatus = STATUS_DELETE_PENDING;
        Irp->IoStatus.Status = ntStatus;
        IoCompleteRequest (Irp, IO_NO_INCREMENT);
        return ntStatus;
    }
    if (Irp->MdlAddress) { // could be NULL for 0-len request
        totalLength = MmGetMdlByteCount(Irp->MdlAddress);
    }
    if (totalLength <= deviceExtension->MaximumTransferSize) {
        // for short or zero-len transfers, no need to do the staging; do it in a single request
        //============================================================
        return Bulk_SingleUrbReadWrite(DeviceObject, Irp, Read);
    }
    irpStack = IoGetCurrentIrpStackLocation (Irp);
    fileObject = irpStack->FileObject;
    pipeHandle =  fileObject->FsContext;
    if (!pipeHandle)
    {
       ntStatus = STATUS_INVALID_HANDLE;
       Irp->IoStatus.Status = ntStatus;
       IoCompleteRequest (Irp, IO_NO_INCREMENT);
       return ntStatus;
    }
    // submit the request to USB
    // more memory than is on our test device?
     if (totalLength > BULKUSB_TEST_BOARD_TRANSFER_BUFFER_SIZE)
    {
       ntStatus = STATUS_INVALID_PARAMETER;
       Irp->IoStatus.Status = ntStatus;
       IoCompleteRequest (Irp, IO_NO_INCREMENT);
       return ntStatus;
    }
    // calculate total # of staged irps that will be needed
    totalIrpsNeeded =  totalLength / deviceExtension->MaximumTransferSize ;
    if (totalLength % deviceExtension->MaximumTransferSize)
        totalIrpsNeeded++;
    used = 0;
    // alloc one extra for termination
    arraySize =  (totalIrpsNeeded +1) * sizeof(USB_RW_CONTEXT);
    // allocate space for an array of USB_RW_CONTEXT structs for the staged irps
    deviceExtension->PendingIoIrps = ExAllocatePool(NonPagedPool, arraySize);
    if (!deviceExtension->PendingIoIrps) {
        ntStatus = STATUS_INSUFFICIENT_RESOURCES;
        Irp->IoStatus.Status = ntStatus;
        IoCompleteRequest (Irp, IO_NO_INCREMENT);
        return ntStatus;
    }
    RtlZeroMemory(deviceExtension->PendingIoIrps, arraySize);
    // init ptr to 1st USB_RW_CONTEXT struct in array
    pCon =  (PUCHAR) deviceExtension->PendingIoIrps;
    deviceExtension->BaseIrp = Irp; // this is the original user\'s irp
    deviceExtension->StagedBytesTransferred = 0;
    deviceExtension->StagedPendingIrpCount = totalIrpsNeeded;
    // we need to build a series of irps & urbs to represent
    // this request.
    while (NT_SUCCESS(ntStatus)) {
        context =  (PUSB_RW_CONTEXT) pCon;
        irp = NULL;
        urb = NULL;
        mdl = NULL;//======================================
        if (!Pub_CanAcceptIoRequests(DeviceObject)) {
            // got sudden remove! (i.e. plug was yanked)
            ntStatus = STATUS_DELETE_PENDING;
            Irp->IoStatus.Status = ntStatus;
            break;
        }
        stackSize = (CCHAR)(deviceExtension->TopOfStackDeviceObject->StackSize + 1);
        irp = IoAllocateIrp(stackSize, FALSE);
        // Get the virtual address for the buffer described by
        // our original input Irp\'s MDL.
        va = MmGetMdlVirtualAddress(Irp->MdlAddress);
        if (irp) {
           // Each new Irp will \'see\' the entire buffer, but map it\'s IO location
           // to a single ChunkSize section within it via IoBuildPartialMdl()
           mdl = IoAllocateMdl(va,
                                totalLength,
                                FALSE,
                                FALSE,
                                irp);
        }                                    
        if (mdl) {        
            // see if we\'re done yet
            if((used + ChunkSize) > totalLength) {
                // make sure to truncate last transfer if neccy
                ChunkSize = totalLength - used;
            }
            // Map the sub-area of the full user buffer this staged Irp will be using for IO
            IoBuildPartialMdl(Irp->MdlAddress, // Points to an MDL describing the original buffer,
                                               // of which a subrange is to be mapped
                              mdl,             // our allocated target mdl
                              (PUCHAR)va + used, // base virtual address of area to be mapped
                              ChunkSize);      // size of area to be mapped

            used+=ChunkSize;//=================================
            urb = Bulk_BuildAsyncRequest(DeviceObject,
                                           irp,
                                           pipeHandle,
                                           Read);
        }
        if (urb && irp && mdl) {
            context->Urb = urb;
            context->DeviceObject = DeviceObject;
            context->Irp = irp;
            context->Mdl = mdl;
            nIrps++;
            // IoGetNextIrpStackLocation gives a higher level driver access to the next-lower
            // driver\'s I/O stack location in an IRP so the caller can set it up for the lower driver.
            nextStack = IoGetNextIrpStackLocation(irp);
            nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
            nextStack->Parameters.Others.Argument1 = urb;
            nextStack->Parameters.DeviceIoControl.IoControlCode =
                IOCTL_INTERNAL_USB_SUBMIT_URB;
            IoSetCompletionRoutine(irp,
                    Bulk_AsyncReadWrite_Complete,//===================
                    context, // pass the context array element to completion routine
                    TRUE,    // invoke on success
                    TRUE,    // invoke on error
                    TRUE);   // invoke on cancellation of the Irp
            // We keep an array of all pending read/write Irps; we may have to cancel
            // them explicitly on sudden device removal or other error
            ((PUSB_RW_CONTEXT) pCon)->Irp = irp;
            Pub_IncrementIoCount(DeviceObject);
            ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject,
             ((PUSB_RW_CONTEXT) pCon)->Irp);
        } else {
            ntStatus = STATUS_INSUFFICIENT_RESOURCES;
            break;
        }
        if (used >= totalLength) {
            break;      // we\'re done
        }
        // point to next USB_RW_CONTEXT struct
        pCon +=  sizeof(USB_RW_CONTEXT);
    } // end while
    Irp->IoStatus.Status = ntStatus;
    if (!NT_SUCCESS(ntStatus)) {
        // try to reset the pipe on error (unless device has been suddenly removed)
        if (pipeHandle  && Pub_CanAcceptIoRequests(DeviceObject)) {
            resetPipeStatus = Usb_ResetPipe(DeviceObject, pipeHandle, FALSE);
            if(!NT_SUCCESS(resetPipeStatus)) {
                // if can\'t reset pipe, try to reset device (parent port)
                resetPipeStatus = Usb_ResetDevice(DeviceObject);
            }//=================================================
        }
    } // end, if !NT_SUCCESS(ntStatus)
    if (0 == nIrps) {
        // only complete the request here if we created no staged irps
        IoCompleteRequest (Irp, IO_NO_INCREMENT);
    } else {
        // We need to protect the below  test with the spinlock because it is possible for
        // BulkUsb_AsynReadWriteComplete() to fire off while we are in this code
        KeAcquireSpinLock(&deviceExtension->FastCompleteSpinlock, &OldIrql);
        if (deviceExtension->BaseIrp) {
            //
            // Mark the original input Irp pending; it will be completed when the last staged irp
            //  is handled (in Bulk_AsyncReadWrite_Complete()).
            //
            ntStatus = STATUS_PENDING;
            Irp->IoStatus.Status = ntStatus;
            IoMarkIrpPending(Irp);
        } else {
            // It is possible for Bulk_AsyncReadWrite_Complete() to have completed the
            //  original irp before we even get here!
            // If this happens, it will have NULLED-out deviceExtension->BaseIrp.
            ntStatus = STATUS_SUCCESS;
        }
       KeReleaseSpinLock (&deviceExtension->FastCompleteSpinlock, OldIrql);
    }
    return ntStatus;
}

NTSTATUS Bulk_SingleUrbReadWrite(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp,
    IN BOOLEAN Read)
{
    int                 totalLength = 0;
    NTSTATUS            ntStatus;
    ULONG                siz;
    PURB                urb;
    PFILE_OBJECT        fileObject;
    PIO_STACK_LOCATION    irpStack, nextStack;
    PUSBD_PIPE_INFORMATION pipeHandle = NULL;
    PDEVICE_EXTENSION    deviceExtension = DeviceObject->DeviceExtension;
    // We should have already checked this in Bulk_StagedReadWrite();
    Irp->IoStatus.Information = 0;
    siz = sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER);
    irpStack = IoGetCurrentIrpStackLocation (Irp);
    fileObject = irpStack->FileObject;
    pipeHandle =  fileObject->FsContext;

    if (!pipeHandle)
    {
       ntStatus = STATUS_INVALID_HANDLE;
       Irp->IoStatus.Status = ntStatus;
       IoCompleteRequest (Irp, IO_NO_INCREMENT);
       return ntStatus;
    }
    if (Irp->MdlAddress) { // could be NULL for 0-len request
        totalLength = MmGetMdlByteCount(Irp->MdlAddress);
    }
    // Build our URB for USBD//==========================
    urb = Bulk_BuildAsyncRequest(DeviceObject,
                                           Irp,
                                           pipeHandle,
                                           Read);
    if (!urb) {  
        ntStatus = STATUS_INSUFFICIENT_RESOURCES;
        Irp->IoStatus.Status = ntStatus;
        IoCompleteRequest (Irp, IO_NO_INCREMENT);
        return ntStatus;
    }
    deviceExtension->BaseUrb = urb;  // save pointer to URb we alloced for this xfer; we free in completion routine
    //
    // Now that we have created the urb, we will send a
    // request to the USB device object.

    // Call the class driver to perform the operation.  

    // IoGetNextIrpStackLocation gives a higher level driver access to the next-lower
    // driver\'s I/O stack location in an IRP so the caller can set it up for the lower driver.
    nextStack = IoGetNextIrpStackLocation(Irp);
    //
    // pass the URB to the USB driver stack
    //
    nextStack->Parameters.Others.Argument1 = urb;
    nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
    nextStack->Parameters.DeviceIoControl.IoControlCode =
        IOCTL_INTERNAL_USB_SUBMIT_URB;
    //========================
    IoSetCompletionRoutine(
                Irp,                       // irp to use
                Bulk_SimpleReadWrite_Complete,   // routine to call when irp is done
                DeviceObject,                       // we pass our FDO as context to pass routine
                TRUE,                      // call on success
                TRUE,                      // call on error
                TRUE);                     // call on cancel
    //
    // Call IoCallDriver to send the irp to the usb port.
    //
    Pub_IncrementIoCount(DeviceObject);
    ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
    //
    // The USB driver should always return STATUS_PENDING when
    // it receives an irp with major function code IRP_MJ_WRITE or IRP_MJ_READ.
    //
    ASSERT(ntStatus == STATUS_PENDING);
    return ntStatus;
}

PURB Bulk_BuildAsyncRequest(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp,
    IN PUSBD_PIPE_INFORMATION PipeHandle,
    IN BOOLEAN Read)
{
    ULONG siz;
    ULONG length = 0;
    PURB urb = NULL;

    if (Irp->MdlAddress) { // could be NULL for 0-len request
        length = MmGetMdlByteCount(Irp->MdlAddress);
    }
    siz = sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER);
    urb = ExAllocatePool(NonPagedPool, siz);
    if (urb) {
        RtlZeroMemory(urb, siz);

        urb->UrbBulkOrInterruptTransfer.Hdr.Length = (USHORT) siz;
        urb->UrbBulkOrInterruptTransfer.Hdr.Function =
                    URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
        urb->UrbBulkOrInterruptTransfer.PipeHandle =
                   PipeHandle->PipeHandle;
        urb->UrbBulkOrInterruptTransfer.TransferFlags =
            Read ? USBD_TRANSFER_DIRECTION_IN : 0;

        // short packet is not treated as an error.
        urb->UrbBulkOrInterruptTransfer.TransferFlags |=
            USBD_SHORT_TRANSFER_OK;            
        //
        // not using linked urb\'s
        //
        urb->UrbBulkOrInterruptTransfer.UrbLink = NULL;
        urb->UrbBulkOrInterruptTransfer.TransferBufferMDL =
            Irp->MdlAddress;
        urb->UrbBulkOrInterruptTransfer.TransferBufferLength =
            length;
    }
    return urb;
}

//完成读写回调函数
NTSTATUS Bulk_AsyncReadWrite_Complete(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp,
    IN PVOID Context)
{
    NTSTATUS            ntStatus = STATUS_SUCCESS;
    PURB                urb;
    KIRQL OldIrql;
    PUSB_RW_CONTEXT context = Context;
    PIO_STACK_LOCATION    irpStack;
    PDEVICE_OBJECT      deviceObject;
    PDEVICE_EXTENSION   deviceExtension;

    // We have to get the deviceObject from the context, since the DeviceObject passed in
    //  here belongs to the next lower driver in the stack because we were invoked via
    //   IoCallDriver in Bulk_StagedReadWrite()
    deviceObject = context->DeviceObject;
    deviceExtension = deviceObject->DeviceExtension;

    // prevent Bulk_StagedReadWrite() from testing deviceExtension->BaseIrp while this routine is running
    KeAcquireSpinLock(&deviceExtension->FastCompleteSpinlock, &OldIrql);

    // Since we own the irp, the current stack location is invalid and calling IoMarkIrpPending will
    // corrupt pool.
    //  If the lower driver returned PENDING, mark our stack location as pending also.
    //if (Irp->PendingReturned) {  
    //    IoMarkIrpPending(Irp);
    //}
    urb = context->Urb;
    // decrement count of staged pending irps
    deviceExtension->StagedPendingIrpCount--;
    // decrement the driver\'s overall pending irp count
    Pub_DecrementIoCount(deviceObject);
    //
    // IoCallDriver has been called on this Irp;
    // Set the length based on the TransferBufferLength
    // value in the URB
    //
    Irp->IoStatus.Information =
        urb->UrbBulkOrInterruptTransfer.TransferBufferLength;

    ntStatus = STATUS_MORE_PROCESSING_REQUIRED;
    deviceExtension->StagedBytesTransferred +=
        urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
    IoFreeIrp(context->Irp);
    context->Irp = NULL;
    IoFreeMdl(context->Mdl);
    context->Mdl = NULL;
    if (deviceExtension->StagedPendingIrpCount == 0) {
        deviceExtension->BaseIrp->IoStatus.Status = STATUS_SUCCESS;
        deviceExtension->BaseIrp->IoStatus.Information =
            deviceExtension->StagedBytesTransferred;
        IoCompleteRequest(deviceExtension->BaseIrp,
                          IO_NO_INCREMENT);
        ExFreePool(deviceExtension->PendingIoIrps);
        deviceExtension->PendingIoIrps  = NULL;
        deviceExtension->BaseIrp = NULL;
        // the event is only waited on if Usb_CancelPendingIo() has been called
        KeSetEvent(&deviceExtension->StagingDoneEvent, 1, FALSE);
    }
    ExFreePool(urb);
    KeReleaseSpinLock (&deviceExtension->FastCompleteSpinlock, OldIrql);
    return ntStatus;
}

NTSTATUS Bulk_SimpleReadWrite_Complete(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp,
    IN PVOID Context)
{
    NTSTATUS            ntStatus = STATUS_SUCCESS;
    PURB                urb;
    PDEVICE_OBJECT      deviceObject;
    PDEVICE_EXTENSION   deviceExtension;

    deviceObject =  (PDEVICE_OBJECT) Context;
    deviceExtension = deviceObject->DeviceExtension;
    urb = deviceExtension->BaseUrb;  //get the urb we alloced for this xfer
    //  If the lower driver returned PENDING, mark our stack location as pending also.
    if (Irp->PendingReturned) {  
        IoMarkIrpPending(Irp);
    }
    // decrement the driver\'s overall pending irp count
    Pub_DecrementIoCount(deviceObject);

    Irp->IoStatus.Information =
        urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
    ntStatus = STATUS_MORE_PROCESSING_REQUIRED;

    Irp->IoStatus.Status = STATUS_SUCCESS;
    IoCompleteRequest(Irp,IO_NO_INCREMENT);
     deviceExtension->BaseUrb = NULL;
    ExFreePool(urb);
    return ntStatus;
}

[编辑 -  3/29/02 作者: plasma]
plasma
驱动小牛
驱动小牛
  • 注册日期2002-02-19
  • 最后登录2008-02-27
  • 粉丝0
  • 关注0
  • 积分50分
  • 威望5点
  • 贡献值0点
  • 好评度5点
  • 原创分0分
  • 专家分0分
19楼#
发布于:2002-03-28 21:28
驱动程序与Windows应用程序控制交互

例程如下:

NTSTATUS win32_IOCTL(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp)
{
    PIO_STACK_LOCATION irpStack;
    PVOID ioBuffer;
    ULONG inputBufferLength;
    ULONG outputBufferLength;
    PDEVICE_EXTENSION deviceExtension;
    ULONG ioControlCode;
    NTSTATUS ntStatus;
    ULONG length;
    PUCHAR pch;
    PUSB_CONFIGURATION_DESCRIPTOR configurationDescriptor;

    Pub_IncrementIoCount(DeviceObject);
    // Get a pointer to the current location in the Irp. This is where
    //     the function codes and parameters are located.
    deviceExtension = DeviceObject->DeviceExtension;

    if (!Pub_CanAcceptIoRequests(DeviceObject)) {
        ntStatus = STATUS_DELETE_PENDING;
        Irp->IoStatus.Status = ntStatus;
        Irp->IoStatus.Information = 0;

        IoCompleteRequest(Irp, IO_NO_INCREMENT);

        Pub_DecrementIoCount(DeviceObject);                          
        return ntStatus;
    }

    irpStack = IoGetCurrentIrpStackLocation (Irp);

    Irp->IoStatus.Status = STATUS_SUCCESS;
    Irp->IoStatus.Information = 0;

    // get pointers and lengths of the caller\'s (user\'s) IO buffer
    ioBuffer           = Irp->AssociatedIrp.SystemBuffer;
    inputBufferLength  = irpStack->Parameters.DeviceIoControl.InputBufferLength;
    outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;

    ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;

    switch (ioControlCode) {

    case IOCTL_ISOUSB_RESET_PIPE:
        {
            PUSBD_PIPE_INFORMATION pipe;
            PFILE_OBJECT fileObject;

            // get our context and see if it is a pipe
            fileObject = irpStack->FileObject;

            pipe = (PUSBD_PIPE_INFORMATION) fileObject->FsContext;    

            if(pipe == NULL) {
                // error, this is not a pipe
                ntStatus =
                    Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
            } else {            
                Usb_ResetPipe(DeviceObject, pipe, FALSE);
            
                ntStatus = Irp->IoStatus.Status = STATUS_SUCCESS;
            }
        }
        break;

     case IOCTL_ISOUSB_GET_CONFIG_DESCRIPTOR:

        //
        // This api returns a copy of the configuration descriptor
        // and all endpoint/interface descriptors.
        //

        //
        // inputs  - none
        // outputs - configuration descriptor plus interface
        //          and endpoint descriptors
        //

        pch = (PUCHAR) ioBuffer;

        configurationDescriptor =
            deviceExtension->UsbConfigurationDescriptor;

        if (configurationDescriptor) {
            length = configurationDescriptor->wTotalLength;
            if (outputBufferLength < length) {
// make sure caller has big enough buffer to receive
                Irp->IoStatus.Information = 0;

                ntStatus = Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
            }
            else {
                RtlCopyMemory(pch,
                              (PUCHAR) configurationDescriptor,
                              length);

                Irp->IoStatus.Information = length;

                ntStatus = Irp->IoStatus.Status = STATUS_SUCCESS;
            }
        }
        else {
            Irp->IoStatus.Information = 0;
            ntStatus = Irp->IoStatus.Status = STATUS_DEVICE_DATA_ERROR;
        }
        break;

     case IOCTL_ISOUSB_START_ISO_STREAM:

        ntStatus = Usb_StartIsoStream(DeviceObject, Irp);
        break;

    case IOCTL_ISOUSB_STOP_ISO_STREAM:

        ntStatus = Usb_StopIsoStream(DeviceObject,
                        *((PVOID *) ioBuffer),
                        Irp);
// a PISOUSB_STREAM_OBJECT passed as a blind ptr input buff from user mode        break;

     case IOCTL_ISOUSB_RESET_DEVICE:
        
        ntStatus = Usb_ResetDevice(DeviceObject);
        break;              

    default:
        ntStatus =
            Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
    }
    IoCompleteRequest (Irp,IO_NO_INCREMENT);
    Pub_DecrementIoCount(DeviceObject);                      
    return ntStatus;
}

NTSTATUS Usb_ResetDevice(IN PDEVICE_OBJECT DeviceObject)
{
    NTSTATUS ntStatus;
    ULONG portStatus;

    //
    // Check the port state, if it is disabled we will need
    // to re-enable it
    //
    ntStatus = Usb_GetPortStatus(DeviceObject, &portStatus);

    if (NT_SUCCESS(ntStatus) && !(portStatus & USBD_PORT_ENABLED) &&
        portStatus & USBD_PORT_CONNECTED) {
        //
        // port is disabled, attempt reset
        //
        ntStatus = Usb_ResetParentPort(DeviceObject);
    }
    return ntStatus;
}

NTSTATUS Usb_GetPortStatus(
    IN PDEVICE_OBJECT DeviceObject,
    IN PULONG PortStatus)
{
    NTSTATUS ntStatus, status = STATUS_SUCCESS;
    PIRP irp;
    KEVENT event;
    IO_STATUS_BLOCK ioStatus;
    PIO_STACK_LOCATION nextStack;
    PDEVICE_EXTENSION deviceExtension;
    deviceExtension = DeviceObject->DeviceExtension;
    *PortStatus = 0;
    // issue a synchronous request
    KeInitializeEvent(&event, NotificationEvent, FALSE);

    // IoBuildDeviceIoControlRequest allocates and sets up an IRP for a device control request
    irp = IoBuildDeviceIoControlRequest(
                IOCTL_INTERNAL_USB_GET_PORT_STATUS,
                deviceExtension->TopOfStackDeviceObject, //next-lower driver\'s device object, representing the target device.
                NULL, // no input or output buffers
                0,
                NULL,
                0,
                TRUE, // internal (use IRP_MJ_INTERNAL_DEVICE_CONTROL)
                &event, // event to be signalled on completion (we wait for it below)
                &ioStatus);

    //
    // Call the class driver to perform the operation.  If the returned status
    // is PENDING, wait for the request to complete.
    //

    // IoGetNextIrpStackLocation gives a higher level driver access to the next-lower
    // driver\'s I/O stack location in an IRP so the caller can set it up for the lower driver.
    nextStack = IoGetNextIrpStackLocation(irp);

    nextStack->Parameters.Others.Argument1 = PortStatus;
    ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject,irp);
    if (ntStatus == STATUS_PENDING) {
        status = KeWaitForSingleObject(
                       &event,
                       Suspended,
                       KernelMode,
                       FALSE,
                       NULL);
    } else {
        ioStatus.Status = ntStatus;
    }
    // USBD maps the error code for us
    ntStatus = ioStatus.Status;
    return ntStatus;
}

NTSTATUS Usb_ResetParentPort(IN IN PDEVICE_OBJECT DeviceObject)
{
    NTSTATUS ntStatus, status = STATUS_SUCCESS;
    PIRP irp;
    KEVENT event;
    IO_STATUS_BLOCK ioStatus;
    PIO_STACK_LOCATION nextStack;
    PDEVICE_EXTENSION deviceExtension;
    deviceExtension = DeviceObject->DeviceExtension;
    // issue a synchronous request
    irp = IoBuildDeviceIoControlRequest(
                IOCTL_INTERNAL_USB_RESET_PORT,
                deviceExtension->TopOfStackDeviceObject,
                NULL,
                0,
                NULL,
                0,
                TRUE, // internal (use IRP_MJ_INTERNAL_DEVICE_CONTROL)
                &event,
                &ioStatus);
    //
    // Call the class driver to perform the operation.  If the returned status
    // is PENDING, wait for the request to complete.
    //
    nextStack = IoGetNextIrpStackLocation(irp);
    ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject,irp);
    if (ntStatus == STATUS_PENDING) {
        status = KeWaitForSingleObject(
                       &event,
                       Suspended,
                       KernelMode,
                       FALSE,
                       NULL);
    } else {
        ioStatus.Status = ntStatus;
    }
    // USBD maps the error code for us
    ntStatus = ioStatus.Status;
    return ntStatus;
}

[编辑 -  3/29/02 作者: plasma]
上一页
游客

返回顶部