zoukankan      html  css  js  c++  java
  • USB WDM驱动开发实例 bulkusb 分类: USB OTG驱动 2015-06-12 10:00 186人阅读 评论(0) 收藏

    参考书籍<<Windows驱动开发技术详解>>


    1、该示例介绍如何进行USB驱动的开发。

    它全面地支持了即插即用的处理,

    也很全面地支持了电源管理,同时很好地支持了USB设备的bulk读写.

    如果从头开发 USB 驱动,往往很难达到USB驱动的稳定性,所以建议在此驱动修改基础上进行USB驱动开发。

     

     

    2、功能驱动与物理总线驱动

    程序员不需要了解USB如何将请求化成数据包等细节,只需要指定何种管道,发送何种数据即可。

    当功能驱动想向某个管道发出读写请求时,首先构造请求发给USB总线驱动。这种请求是标准的USB请求,称为URB(USB Request Block)。

    它被USB总线驱动所解释,进而转化成请求发给HOST驱动或者USB HUB驱动。

    3、实现过程

    3、1 构造USB请求包

    USB驱动与USB设备通信时,如在控制管道中获取设备描述符、配置描述符、端点描述符、或在Bulk管道中获取大量数据,

    都是通过创建USB请求包(URB)来完成的。URB中填充需要对USB的请求,然后将URB作为IRP一个参数传递给底层的USB总线驱动。

    3、1、1  在DriverEntry中给了对应IRP_MJ_PNP的回调函数

     DriverObject->MajorFunction[IRP_MJ_PNP]            = BulkUsb_DispatchPnP;

    3、1、2   BulkUsb_DispatchPnP的实现

    BulkUsb_DispatchPnP为即插即用分发函数.

    在 case IRP_MN_START_DEVICE时有处理函数ntStatus = HandleStartDevice(DeviceObject, Irp);

     

    1. NTSTATUS  
    2. BulkUsb_DispatchPnP(  
    3.     IN PDEVICE_OBJECT DeviceObject,  
    4.     IN PIRP           Irp  
    5.     )  
    6. /*++ 
    7.   
    8. Routine Description: 
    9.  
    10.    即插即用分发函数. 
    11.     Most of these requests the driver will completely ignore. 
    12.     In all cases it must pass on the IRP to the lower driver. 
    13.  
    14. Arguments: 
    15.  
    16.     DeviceObject - pointer to a device object. 
    17.  
    18.     Irp - 指向一个I/O请求包 
    19.  
    20. Return Value: 
    21.  
    22.     NT status value 
    23.  
    24. --*/  
    25. {  
    26.     PIO_STACK_LOCATION irpStack;  
    27.     PDEVICE_EXTENSION  deviceExtension;  
    28.     KEVENT             startDeviceEvent;  
    29.     NTSTATUS           ntStatus;  
    30.   
    31.     //  
    32.     // 初始化变量  
    33.     //  
    34.   
    35.     irpStack = IoGetCurrentIrpStackLocation(Irp);  
    36.     deviceExtension = DeviceObject->DeviceExtension;  
    37.   
    38.     //  
    39.     // 如查它被移除,那么Irp失败  
    40.   
    41.   
    42.     if(Removed == deviceExtension->DeviceState)   
    43.     {  
    44.   
    45.         ntStatus = STATUS_DELETE_PENDING;  
    46.   
    47.         Irp->IoStatus.Status = ntStatus;  
    48.         Irp->IoStatus.Information = 0;  
    49.   
    50.         IoCompleteRequest(Irp, IO_NO_INCREMENT);  
    51.   
    52.         return ntStatus;  
    53.     }  
    54.   
    55.     BulkUsb_DbgPrint(3, ("/////////////////////////////////////////// "));  
    56.     BulkUsb_DbgPrint(3, ("BulkUsb_DispatchPnP::"));  
    57.     // 提升I/O计数.  
    58.     BulkUsb_IoIncrement(deviceExtension);  
    59.   
    60.     if(irpStack->MinorFunction == IRP_MN_START_DEVICE)  
    61.     {  
    62.   
    63.         ASSERT(deviceExtension->IdleReqPend == 0);  
    64.     }  
    65.     else   
    66.     {  
    67.   
    68.         if(deviceExtension->SSEnable) {  
    69.   
    70.             CancelSelectSuspend(deviceExtension);  
    71.         }  
    72.     }  
    73.   
    74.     BulkUsb_DbgPrint(2, (PnPMinorFunctionString(irpStack->MinorFunction)));  
    75.   
    76.     switch(irpStack->MinorFunction)   
    77.     {  
    78.   
    79.     case IRP_MN_START_DEVICE:  
    80.           
    81.         ntStatus = HandleStartDevice(DeviceObject, Irp);  
    82.   
    83.         break;  
    84.   
    85.     case IRP_MN_QUERY_STOP_DEVICE:  
    86.   
    87.         //  
    88.         // if we cannot stop the device, we fail the query stop irp  
    89.         //  
    90.   
    91.         ntStatus = CanStopDevice(DeviceObject, Irp);  
    92.   
    93.         if(NT_SUCCESS(ntStatus)) {  
    94.   
    95.             ntStatus = HandleQueryStopDevice(DeviceObject, Irp);  
    96.   
    97.             return ntStatus;  
    98.         }  
    99.         break;  
    100.   
    101.     case IRP_MN_CANCEL_STOP_DEVICE:  
    102.   
    103.         ntStatus = HandleCancelStopDevice(DeviceObject, Irp);  
    104.   
    105.         break;  
    106.        
    107.     case IRP_MN_STOP_DEVICE:  
    108.   
    109.         ntStatus = HandleStopDevice(DeviceObject, Irp);  
    110.   
    111.         BulkUsb_DbgPrint(3, ("BulkUsb_DispatchPnP::IRP_MN_STOP_DEVICE::"));  
    112.         BulkUsb_IoDecrement(deviceExtension);  
    113.   
    114.         return ntStatus;  
    115.   
    116.     case IRP_MN_QUERY_REMOVE_DEVICE:  
    117.   
    118.         //  
    119.         // if we cannot remove the device, we fail the query remove irp  
    120.         //  
    121.         ntStatus = HandleQueryRemoveDevice(DeviceObject, Irp);  
    122.   
    123.         return ntStatus;  
    124.   
    125.     case IRP_MN_CANCEL_REMOVE_DEVICE:  
    126.   
    127.         ntStatus = HandleCancelRemoveDevice(DeviceObject, Irp);  
    128.   
    129.         break;  
    130.   
    131.     case IRP_MN_SURPRISE_REMOVAL:  
    132.   
    133.         ntStatus = HandleSurpriseRemoval(DeviceObject, Irp);  
    134.   
    135.         BulkUsb_DbgPrint(3, ("BulkUsb_DispatchPnP::IRP_MN_SURPRISE_REMOVAL::"));  
    136.         BulkUsb_IoDecrement(deviceExtension);  
    137.   
    138.         return ntStatus;  
    139.   
    140.     case IRP_MN_REMOVE_DEVICE:  
    141.   
    142.         ntStatus = HandleRemoveDevice(DeviceObject, Irp);  
    143.   
    144.         return ntStatus;  
    145.   
    146.     case IRP_MN_QUERY_CAPABILITIES:  
    147.   
    148.         ntStatus = HandleQueryCapabilities(DeviceObject, Irp);  
    149.   
    150.         break;  
    151.   
    152.     default:  
    153.   
    154.         IoSkipCurrentIrpStackLocation(Irp);  
    155.   
    156.         ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);  
    157.   
    158.         BulkUsb_DbgPrint(3, ("BulkUsb_DispatchPnP::default::"));  
    159.         BulkUsb_IoDecrement(deviceExtension);  
    160.   
    161.         return ntStatus;  
    162.   
    163.     } // switch  
    164.   
    165. //  
    166. // complete request   
    167. //  
    168.   
    169.     Irp->IoStatus.Status = ntStatus;  
    170.     Irp->IoStatus.Information = 0;  
    171.   
    172.     IoCompleteRequest(Irp, IO_NO_INCREMENT);  
    173.   
    174. //  
    175. // decrement count  
    176. //  
    177.     BulkUsb_DbgPrint(3, ("BulkUsb_DispatchPnP::"));  
    178.     BulkUsb_IoDecrement(deviceExtension);  
    179.   
    180.     return ntStatus;  
    181. }  

    (1)一开始判断当前设备的状态,如果为Removed那么IRP失败,直接返回。

    这里讲一下设备的状态的维护方法:

    (1、1)在设备扩展中留出两字段,分别存当前状态和之前状态。

    1. // current state of device  
    2.    DEVSTATE DeviceState;  
    3.   
    4.    // state prior to removal query  
    5.    DEVSTATE PrevDevState;  


    (1、2)在初始化时

    (1、3)在改变时

    通过以下宏来改变状态

    1. #define SET_NEW_PNP_STATE(_Data_, _state_)   
    2.         (_Data_)->PrevDevState =  (_Data_)->DeviceState;  
    3.         (_Data_)->DeviceState = (_state_);  

    需更新状态信息的有以下几个地方:

    A、BulkUsb_DispatchPnP里case IRP_MN_START_DEVICE时,在选择设备描述符和选择端点完成后设置为Working

    1. //  
    2.    // 读设备描述符,配置描述符并选择接口描述符  
    3.    //  
    4.   
    5.    ntStatus = ReadandSelectDescriptors(DeviceObject);  
    6.   
    7.    if(!NT_SUCCESS(ntStatus)) {  
    8.   
    9.        BulkUsb_DbgPrint(1, ("ReadandSelectDescriptors failed "));  
    10.        return ntStatus;  
    11.    }  
    12.   
    13.    //  
    14.    // 为系统组件去打开设备句柄而使能象征链  
    15.   
    16.    ntStatus = IoSetDeviceInterfaceState(&deviceExtension->InterfaceName,   
    17.                                         TRUE);  


     

    B、BulkUsb_DispatchPnP里case IRP_MN_QUERY_STOP_DEVICE时,设置为PendingStop;  

    C、BulkUsb_DispatchPnP里case IRP_MN_STOP_DEVICE时,在取消定时器这样DPCs就不再激活后等待两个事件激活后设置为PendingStop

    1. KeCancelTimer(&deviceExtension->Timer);  
    2.   
    3.            //  
    4.            // 在设备停止后,它能被强拨了.  
    5.            // 我们设置它为0,这样我们在强拨或移除Irps时不再偿试去取消定时器 .  
    6.            // 当我们再获得设备请求时,此标志会再被初始化  
    7.            //  
    8.            deviceExtension->SSEnable = 0;  
    9.   
    10.            //  
    11.            // make sure that if a DPC was fired before we called cancel timer,  
    12.            // then the DPC and work-time have run to their completion  
    13.            //  
    14.            KeWaitForSingleObject(&deviceExtension->NoDpcWorkItemPendingEvent,   
    15.                                  Executive,   
    16.                                  KernelMode,   
    17.                                  FALSE,   
    18.                                  NULL);  
    19.   
    20.            //  
    21.            // make sure that the selective suspend request has been completed.  
    22.            //  
    23.            KeWaitForSingleObject(&deviceExtension->NoIdleReqPendEvent,   
    24.                                  Executive,   
    25.                                  KernelMode,   
    26.                                  FALSE,   
    27.                                  NULL);  

    D、BulkUsb_DispatchPnP里case IRP_MN_QUERY_REMOVE_DEVICE时,设置为PendingRemove

    E、BulkUsb_DispatchPnP里case IRP_MN_SURPRISE_REMOVAL时,设置为SurpriseRemoved

    对IRP_MN_SURPRISE_REMOVAL的处理与对IRP_MN_STOP_DEVICE的处理是很相似的,

    只不过前者情况下认为所有请求失败,处理了队列里的所有请求,且设置设备的Interface状态为失败,中止了所有Pipe的使用:

    1. ProcessQueuedRequests(deviceExtension);  
    2.   
    3.    ntStatus = IoSetDeviceInterfaceState(&deviceExtension->InterfaceName,   
    4.                                         FALSE);  
    5.   
    6.    if(!NT_SUCCESS(ntStatus)) {  
    7.   
    8.        BulkUsb_DbgPrint(1, ("IoSetDeviceInterfaceState::disable:failed "));  
    9.    }  
    10.   
    11.    BulkUsb_AbortPipes(DeviceObject);  

    而后者只是反配置了设备:

    1. ReleaseMemory(DeviceObject);  
    2.   
    3.   ntStatus = DeconfigureDevice(DeviceObject);  


    F、BulkUsb_DispatchPnP里case IRP_MN_REMOVE_DEVICE时,设置为Removed
    在这个情况下做以下事情:反注册USB插入时创建的设备对象,把此USB的FDO从设备栈中移除;
    如果之前的设备状态不是SurpriseRemoved,那么要做IRP_MN_SURPRISE_REMOVAL、IRP_MN_STOP_DEVICE两个case时做的所有事情

     

    3、1、3   HandleStartDevice的实现

    它调用ReadandSelectDescriptors来读取设备描述符

    1. NTSTATUS  
    2. HandleStartDevice(  
    3.     IN PDEVICE_OBJECT DeviceObject,  
    4.     IN PIRP              Irp  
    5.     )  
    6. /*++ 
    7.   
    8. Routine Description: 
    9.  
    10.    IRP_MN_START_DEVICE对应的处理函数 
    11.  
    12. Arguments: 
    13.  
    14.     DeviceObject - pointer to a device object. 
    15.  
    16.     Irp - I/O request packet 
    17.  
    18. Return Value: 
    19.  
    20.     NT status value 
    21.  
    22. --*/  
    23. {  
    24.     KIRQL             oldIrql;  
    25.     KEVENT            startDeviceEvent;  
    26.     NTSTATUS          ntStatus;  
    27.     PDEVICE_EXTENSION deviceExtension;  
    28.     LARGE_INTEGER     dueTime;  
    29.   
    30.     BulkUsb_DbgPrint(3, ("HandleStartDevice - begins "));  
    31.   
    32.     //  
    33.     // 初始化变量  
    34.     //  
    35.     deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;  
    36.     deviceExtension->UsbConfigurationDescriptor = NULL;  
    37.     deviceExtension->UsbInterface = NULL;  
    38.     deviceExtension->PipeContext = NULL;  
    39.   
    40.     //  
    41.     // 我们不能触摸设备 (给它发送任何非pnp 的 irps) until a  
    42.     // start device has been passed down to the lower drivers.  
    43.     // first pass the Irp down  
    44.     //  
    45.   
    46.     KeInitializeEvent(&startDeviceEvent, NotificationEvent, FALSE);  
    47.   
    48.     IoCopyCurrentIrpStackLocationToNext(Irp);  
    49.   
    50.     IoSetCompletionRoutine(Irp,   
    51.                            (PIO_COMPLETION_ROUTINE)IrpCompletionRoutine,   
    52.                            (PVOID)&startDeviceEvent,   
    53.                            TRUE,   
    54.                            TRUE,   
    55.                            TRUE);  
    56.   
    57.     ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);  
    58.   
    59.     if(ntStatus == STATUS_PENDING) {  
    60.   
    61.         KeWaitForSingleObject(&startDeviceEvent,   
    62.                               Executive,   
    63.                               KernelMode,   
    64.                               FALSE,   
    65.                               NULL);  
    66.   
    67.         ntStatus = Irp->IoStatus.Status;  
    68.     }  
    69.   
    70.     if(!NT_SUCCESS(ntStatus)) {  
    71.   
    72.         BulkUsb_DbgPrint(1, ("Lower drivers failed this Irp "));  
    73.         return ntStatus;  
    74.     }  
    75.   
    76.     //  
    77.     // 读设备描述符,配置描述符并选择接口描述符  
    78.     //  
    79.   
    80.     ntStatus = ReadandSelectDescriptors(DeviceObject);  
    81.   
    82.     if(!NT_SUCCESS(ntStatus)) {  
    83.   
    84.         BulkUsb_DbgPrint(1, ("ReadandSelectDescriptors failed "));  
    85.         return ntStatus;  
    86.     }  
    87.   
    88.     //  
    89.     // 为系统组件去打开设备句柄而使能象征链  
    90.   
    91.     ntStatus = IoSetDeviceInterfaceState(&deviceExtension->InterfaceName,   
    92.                                          TRUE);  
    93.   
    94.     if(!NT_SUCCESS(ntStatus)) {  
    95.   
    96.         BulkUsb_DbgPrint(1, ("IoSetDeviceInterfaceState:enable:failed "));  
    97.         return ntStatus;  
    98.     }  
    99.   
    100.     KeAcquireSpinLock(&deviceExtension->DevStateLock, &oldIrql);  
    101.   
    102.     SET_NEW_PNP_STATE(deviceExtension, Working);  
    103.     deviceExtension->QueueState = AllowRequests;  
    104.   
    105.     KeReleaseSpinLock(&deviceExtension->DevStateLock, oldIrql);  
    106.   
    107.     //  
    108.     // 初始化等待唤醒的标志到false  false.  
    109.     // and issue a wait wake.  
    110.       
    111.     deviceExtension->FlagWWOutstanding = 0;  
    112.     deviceExtension->FlagWWCancel = 0;  
    113.     deviceExtension->WaitWakeIrp = NULL;  
    114.       
    115.     if(deviceExtension->WaitWakeEnable) {  
    116.   
    117.         IssueWaitWake(deviceExtension);  
    118.     }  
    119.   
    120.     ProcessQueuedRequests(deviceExtension);  
    121.   
    122.   
    123.     if(WinXpOrBetter == deviceExtension->WdmVersion)  
    124.     {  
    125.   
    126.   
    127.         deviceExtension->SSEnable = deviceExtension->SSRegistryEnable;  
    128.   
    129.         //  
    130.         // set timer.for selective suspend requests  
    131.         //  
    132.   
    133.         if(deviceExtension->SSEnable) {  
    134.   
    135.             dueTime.QuadPart = -10000 * IDLE_INTERVAL;               // 5000 ms  
    136.   
    137.             KeSetTimerEx(&deviceExtension->Timer,   
    138.                          dueTime,  
    139.                          IDLE_INTERVAL,                              // 5000 ms  
    140.                          &deviceExtension->DeferredProcCall);  
    141.   
    142.             deviceExtension->FreeIdleIrpCount = 0;  
    143.         }  
    144.     }  
    145.   
    146.     BulkUsb_DbgPrint(3, ("HandleStartDevice - ends "));  
    147.   
    148.     return ntStatus;  
    149. }  


    (1) IoCopyCurrentIrpStackLocationToNext介绍:

    在下发IRP到底层驱动处理前,本层驱动必须负责设置下层IO堆栈的内容。这样下一层驱动调用IoGetCurrentIrpStackLocation()时能得到相应的数据。
    设置下层IO堆栈的内容,一般用两个函数来实现:
    IoCopyCurrentIrpStackLocationToNext( Irp )
    此函数一般用在本驱动设置了完成例程时调用,把本层IO _STACK_LOCATION 中的参数copy到下层,但与完成例程相关的参数信息例外。因为本驱动设置的完成例程只对本层驱动有效。
    IoSkipCurrentIrpStackLocationToNext(Irp)
    此函数的作用是:直接把本层驱动IO堆栈的内容设置为下层驱动IO堆栈指针的指向。因两层驱动IO堆栈的内容完全一致,省却copy过程
    (2)根据以上知识点,我们开始分析HandleStartDevice函数的实现过程:
    (2、1)把本层IO _STACK_LOCATION 中的参数copy到下层,设置完成例程,等待完成。
    1. KeInitializeEvent(&startDeviceEvent, NotificationEvent, FALSE);  
    2.   
    3.    IoCopyCurrentIrpStackLocationToNext(Irp);  
    4.   
    5.    IoSetCompletionRoutine(Irp,   
    6.                           (PIO_COMPLETION_ROUTINE)IrpCompletionRoutine,   
    7.                           (PVOID)&startDeviceEvent,   
    8.                           TRUE,   
    9.                           TRUE,   
    10.                           TRUE);  
    11.   
    12.    ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);  
    13.   
    14.    if(ntStatus == STATUS_PENDING) {  
    15.   
    16.        KeWaitForSingleObject(&startDeviceEvent,   
    17.                              Executive,   
    18.                              KernelMode,   
    19.                              FALSE,   
    20.                              NULL);  
    21.   
    22.        ntStatus = Irp->IoStatus.Status;  
    23.    }  

    (2、2)读设备描述符,配置描述符并选择接口描述符(重点,参见3、1、4 );
    (2、3)开启定时器(5S间隔);

    1. if(DeviceExtension->SSEnable) {  
    2.   
    3.        BulkUsb_DbgPrint(3, ("Set the timer to fire DPCs "));  
    4.   
    5.        dueTime.QuadPart = -10000 * IDLE_INTERVAL;               // 5000 ms  
    6.   
    7.        KeSetTimerEx(&DeviceExtension->Timer,   
    8.                     dueTime,  
    9.                     IDLE_INTERVAL,                              // 5000 ms  
    10.                     &DeviceExtension->DeferredProcCall);  
    11.   
    12.        BulkUsb_DbgPrint(3, ("IdleNotificationRequestCompete - ends "));  
    13.    }  

    这里补充定时器的使用:

    实例中用到的定时器是为了与DCP协调使用,这体现在初始化时,如下面的 A、

    A、初始化定时器

    在系统扩展中的变量DriverObject->DriverExtension->AddDevice指定的处理函数 BulkUsb_AddDevice中初始化定时器:

    1. //  
    2.            // initialize DPC  
    3.            //  
    4.            KeInitializeDpc(&deviceExtension->DeferredProcCall,   
    5.                            DpcRoutine,   
    6.                            deviceObject);  
    7.   
    8.            //  
    9.            // initialize the timer.  
    10.            // the DPC and the timer in conjunction,   
    11.            // monitor the state of the device to   
    12.            // selectively suspend the device.  
    13.            //  
    14.            KeInitializeTimerEx(&deviceExtension->Timer,  
    15.                                NotificationTimer);  

    B、启动定时器;

    它发生在两个地方:HandleStartDevice 和 SubmitIdleRequestIrp 函数设备的完成例程中。

    C、关闭定时器;

    它发生在三个地方:HandleStopDevice、HandleSurpriseRemoval、HandleRemoveDevice三个地方。

    定时器每5S后触发的事件的目的是:

    检查设备的idle状态并为设备提交一个idle请求。

    步一:检查是设备是否是suspend状态。判断方法如下:

    1. if((DeviceExtension->OpenHandleCount == 0) &&  
    2.        (DeviceExtension->OutStandingIO == 1)) {  
    3.          
    4.        return TRUE;  
    5.    }  
    6.    else {  
    7.   
    8.        return FALSE;  
    9.    }  


    OpenHandleCount 、OutStandingIO都是LONG类型,它们通过InterlockedIncrement、InterlockedDecrement来自增1与自减1;

    我们可以发现在进入每个派遣函数时,几乎都有对OutStandingIO加1,然后结束时减1,而刚开始时是1。根据条件判断,当在派遣函数中时此时是不能置为设备SUSPEND状态的。

    OpenHandleCount作为打开设备的计数,在AddDevice时是0,在Create后是加了1,这样就是设备还没有Create时是可Idle的状态。

    以上讲到的是是USB开发中用到的同步机制,它的思想与COM的计数思想是类似的。

    步二:首先调用IoAllocateWorkItem函数为work item分配内存,然后调用IoQueueWorkItem函数将任务放置到工作线程队列中;

     IO_WORKITEM 结构体是一个不透明的结构体,它描述了一个系统工作线程的工作Item。驱动可以通过IoAllocateWorkItem分配一个工作ITEM,或者驱动分配它自己的Buffer,然后调用IoInitializeWorkItem来初始化这个Buffer作为一个工作ITEM

    IoQueueWorkItem把一个回调函数绑定在一个工作ITEM中,并把它插入的队列中,等待系统工作线程来处理
     步三:处理Idle请求任务IdleRequestWorkerRoutine

      IdleRequestWorkerRoutine调用SubmitIdleRequestIrp提交Idle请求的IRP,然后将事件NoDpcWorkItemPendingEvent激活。
    步三、1     SubmitIdleRequestIrp 过程分析

    SubmitIdleRequestIrp用一个分配的回调函数例程(PUSB_IDLE_CALLBACK_INFO)一个IDLE通知的完成例程(IdleNotificationRequestComplete)建立一个IDLE请求IRP

    1. idleCallbackInfo = ExAllocatePool(NonPagedPool,   
    2.                                       sizeof(struct _USB_IDLE_CALLBACK_INFO));  
    3.   
    4.     if(idleCallbackInfo) {  
    5.   
    6.         idleCallbackInfo->IdleCallback = IdleNotificationCallback;  
    7.   
    8.         idleCallbackInfo->IdleContext = (PVOID)DeviceExtension;  
    9.   
    10.         ASSERT(DeviceExtension->IdleCallbackInfo == NULL);  
    11.   
    12.         DeviceExtension->IdleCallbackInfo = idleCallbackInfo;  


     

    1. irp = IoAllocateIrp(DeviceExtension->TopOfStackDeviceObject->StackSize,  
    2.                         FALSE);  
    3.                           
    4. nextStack = IoGetNextIrpStackLocation(irp);  
    5. nextStack->MajorFunction =   
    6.             IRP_MJ_INTERNAL_DEVICE_CONTROL;  
    7. nextStack->Parameters.DeviceIoControl.IoControlCode =   
    8.             IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION;  
    9. nextStack->Parameters.DeviceIoControl.Type3InputBuffer =  
    10.             idleCallbackInfo;  
    11. nextStack->Parameters.DeviceIoControl.InputBufferLength =  
    12.             sizeof(struct _USB_IDLE_CALLBACK_INFO);  
    13. IoSetCompletionRoutine(irp,   
    14.                        IdleNotificationRequestComplete,  
    15.                        DeviceExtension,   
    16.                        TRUE,   
    17.                        TRUE,   
    18.                        TRUE);  
    19. DeviceExtension->PendingIdleIrp = irp;  


     

    并把IRP传到栈下面:

    1. ntStatus = IoCallDriver(DeviceExtension->TopOfStackDeviceObject, irp);  

    步三、2     IDLE通知的完成例程分析

    判断IDLE请求的IRP的执行结果,如果有错误发生,那么通过PoRequestPowerIrp告诉设备栈的顶层驱动电源状态为PowerDeviceD0。

    1. powerState.DeviceState = PowerDeviceD0;  
    2.   
    3.        ntStatus = PoRequestPowerIrp(  
    4.                          DeviceExtension->PhysicalDeviceObject,   
    5.                          IRP_MN_SET_POWER,   
    6.                          powerState,   
    7.                          (PREQUEST_POWER_COMPLETE) PoIrpAsyncCompletionFunc,   
    8.                          DeviceExtension,   
    9.                          NULL);  


    PoRequestPowerIrp 分析一个电源IRP并把它发送到设备栈的顶层驱动中。

    、、、、、、

    、、、、、、

    、、、、、、

    3、1、4   ReadandSelectDescriptors的实现

    A、首先分配一个控制描述符请求的URB内存,然后再分析一个设备描述符内存PUSB_DEVICE_DESCRIPTOR

    B、 然后通过UsbBuildGetDescriptorRequest填充URB后得到

    1. #define UsbBuildGetDescriptorRequest(urb,   
    2.                                      length,   
    3.                                      descriptorType,   
    4.                                      descriptorIndex,   
    5.                                      languageId,   
    6.                                      transferBuffer,   
    7.                                      transferBufferMDL,   
    8.                                      transferBufferLength,   
    9.                                      link) {   
    10.             (urb)->UrbHeader.Function =  URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE;   
    11.             (urb)->UrbHeader.Length = (length);   
    12.             (urb)->UrbControlDescriptorRequest.TransferBufferLength = (transferBufferLength);   
    13.             (urb)->UrbControlDescriptorRequest.TransferBufferMDL = (transferBufferMDL);   
    14.             (urb)->UrbControlDescriptorRequest.TransferBuffer = (transferBuffer);   
    15.             (urb)->UrbControlDescriptorRequest.DescriptorType = (descriptorType);   
    16.             (urb)->UrbControlDescriptorRequest.Index = (descriptorIndex);   
    17.             (urb)->UrbControlDescriptorRequest.LanguageId = (languageId);   
    18.             (urb)->UrbControlDescriptorRequest.UrbLink = (link); }  


    C、请求设备描述符的URB, 将此URB请求自己封装的CallUSBD通过发送出去。

    CallUSBD用于同步地提交一个URB到栈,步骤如下:

    C、1   创建一个I/O控制码的IRP;

    C、2   通过IoGetNextIrpStackLocation得到irp的下一层设备栈,并把urb值给nextStack->Parameters.Others.Argument1;

    C、3  用IoCallDriver将irp发送到底层总线驱动上;

    C、4 由于上层无法知道底层驱动是同步还异步完成的,因此需要做一个判断.If 语句判断,当异步完成IRP时,用事件等待总线驱动完成这个IRP。(参见3、2 )

     

    1. NTSTATUS  
    2. ReadandSelectDescriptors(  
    3.     IN PDEVICE_OBJECT DeviceObject  
    4.     )  
    5. /*++ 
    6.   
    7. Routine Description: 
    8.  
    9.     配置USB设备. 
    10.     我们先获得设备描述符,配置描述符然后选择配置描述符 
    11.  
    12. Arguments: 
    13.  
    14.     DeviceObject - pointer to a device object 
    15.  
    16. Return Value: 
    17.  
    18.     NTSTATUS - NT status value. 
    19.  
    20. --*/  
    21. {  
    22.     PURB                   urb;  
    23.     ULONG                  siz;  
    24.     NTSTATUS               ntStatus;  
    25.     PUSB_DEVICE_DESCRIPTOR deviceDescriptor;  
    26.       
    27.     //  
    28.     // initialize variables  
    29.     //  
    30.   
    31.     urb = NULL;  
    32.     deviceDescriptor = NULL;  
    33.   
    34.     //  
    35.     // 1.读设备描述符  
    36.   
    37.     urb = ExAllocatePool(NonPagedPool,   
    38.                          sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));  
    39.   
    40.     if(urb)  
    41.     {  
    42.   
    43.         siz = sizeof(USB_DEVICE_DESCRIPTOR);  
    44.         deviceDescriptor = ExAllocatePool(NonPagedPool, siz);  
    45.   
    46.         if(deviceDescriptor)   
    47.         {  
    48.   
    49.             // 构造请求  
    50.             UsbBuildGetDescriptorRequest(  
    51.                     urb,   
    52.                     (USHORTsizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),  
    53.                     USB_DEVICE_DESCRIPTOR_TYPE,   
    54.                     0,   
    55.                     0,   
    56.                     deviceDescriptor,   
    57.                     NULL,   
    58.                     siz,   
    59.                     NULL);  
    60.   
    61.             // 发送请求  
    62.             ntStatus = CallUSBD(DeviceObject, urb);  
    63.   
    64.             if(NT_SUCCESS(ntStatus))  
    65.             {  
    66.   
    67.                 ASSERT(deviceDescriptor->bNumConfigurations);  
    68.                 ntStatus = ConfigureDevice(DeviceObject);      
    69.             }  
    70.                               
    71.             ExFreePool(urb);                  
    72.             ExFreePool(deviceDescriptor);  
    73.         }  
    74.         else  
    75.         {  
    76.   
    77.             BulkUsb_DbgPrint(1, ("Failed to allocate memory for deviceDescriptor"));  
    78.   
    79.             ExFreePool(urb);  
    80.             ntStatus = STATUS_INSUFFICIENT_RESOURCES;  
    81.         }  
    82.     }  
    83.     else  
    84.     {  
    85.   
    86.         BulkUsb_DbgPrint(1, ("Failed to allocate memory for urb"));  
    87.   
    88.         ntStatus = STATUS_INSUFFICIENT_RESOURCES;  
    89.     }  
    90.   
    91.     return ntStatus;  
    92. }  

     D、请求配置描述符

    读取的过程是:

    第一步:读取配置描述符的大小;

    分配的配置描述符内存大小为 sizeof(USB_CONFIGURATION_DESCRIPTOR),也是把内存绑定到URB,URB再绑到IRP,然后通过IoCallDriver提交请求;

    (实现与上步C类似)

    第二步:根据第一步得到的大小,重新分析PUSB_CONFIGURATION_DESCRIPTOR内存, 与第一步一样的方法提交。

    由于希望得到的配置描述符的大小变化了,所以得提交的请求返回的内存就是真正的配置描述符数据

    E、保存上步D得到的配置描述符指针到extension中,根据指针内容判断是否支持远程唤醒;

    F、根据返回的配置描述符数据选择其中一个Interfaces。(重点)

     

    1. NTSTATUS  
    2. SelectInterfaces(  
    3.     IN PDEVICE_OBJECT                DeviceObject,  
    4.     IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor  
    5.     )  

    F1  ConfigurationDescriptor描述符数据中通过USBD_ParseConfigurationDescriptorEx取出一个一个的PUSB_INTERFACE_DESCRIPTOR,组成链表

    USBD_ParseConfigurationDescriptorEx为DDK提供的API, 用于解析从设备返回的标准的USB配置描述符,以得到一个指定的接口,可改变的设备类子类或协议代码。

     

    1. DECLSPEC_IMPORT  
    2. PUSB_INTERFACE_DESCRIPTOR  
    3. USBD_ParseConfigurationDescriptorEx(  
    4.     IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,  
    5.     IN PVOID StartPosition,  
    6.     IN LONG InterfaceNumber,  
    7.     IN LONG AlternateSetting,  
    8.     IN LONG InterfaceClass,  
    9.     IN LONG InterfaceSubClass,  
    10.     IN LONG InterfaceProtocol  
    11.     );  


     

    ConfigurationDescriptor - 指向从设备返回的USB配置描述符, (包含所有的接口和端点描述符);
    StartPosition - 指向将要解析的配置描述符的开始位置

    InterfaceNumber - 要查找的接口号,(-1)表满足所有;
    AlternateSetting - 要查找的可改变的设备号,(-1)表满足所有;

    InterfaceClass - 要查找的类,(-1)表满足所有;
    InterfaceSubClass - 要查找的子类,(-1)表满足所有;
    InterfaceProtocol - 要查找的协议,(-1)表满足所有;

    1. tmp = interfaceList =  
    2.     ExAllocatePool(  
    3.            NonPagedPool,   
    4.            sizeof(USBD_INTERFACE_LIST_ENTRY) * (numberOfInterfaces + 1));  
    5.   
    6. if(!tmp) {  
    7.   
    8.     BulkUsb_DbgPrint(1, ("Failed to allocate mem for interfaceList "));  
    9.     return STATUS_INSUFFICIENT_RESOURCES;  
    10. }  
    11.   
    12.   
    13. while(interfaceNumber < numberOfInterfaces) {  
    14.   
    15.     interfaceDescriptor = USBD_ParseConfigurationDescriptorEx(  
    16.                                         ConfigurationDescriptor,   
    17.                                         ConfigurationDescriptor,  
    18.                                         interfaceindex,  
    19.                                         0, -1, -1, -1);  
    20.   
    21.     if(interfaceDescriptor) {  
    22.   
    23.         interfaceList->InterfaceDescriptor = interfaceDescriptor;  
    24.         interfaceList->Interface = NULL;  
    25.         interfaceList++;  
    26.         interfaceNumber++;  
    27.     }  
    28.   
    29.     interfaceindex++;  
    30. }  

    F、2   通过DDK提供的USBD_CreateConfigurationRequestEx函数,

    USBD_CreateConfigurationRequestEx函数基于传进来的接口列表,来分配并初始化一个有足够大小的URB来配置设备, 接口列表是一个连续的 USBD_INTERFACE_LIST_ENTRIES数组,每一个指定接口描述符的指针被包含在请求中,列表通过指向NULL的列表入口来终止。

    1. DECLSPEC_IMPORT  
    2. PURB  
    3. USBD_CreateConfigurationRequestEx(  
    4.     IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,  
    5.     IN PUSBD_INTERFACE_LIST_ENTRY InterfaceList  
    6.     );  


     

    F、3  把E、2返回的URB请求发送出去;把Interface信息urb->UrbSelectConfiguration.Interface保存在extension中;

    F、4  初始化BULKUSB_PIPE_CONTEXT  PipeContext



     

     

     

    3、2  然后调用CallUSBD将此请求发送出去

    URB包要和一个IRP相关联起来。这就需要IoBuildDeviceIoControlRequest创建一个I/O控制码的IRP

    然后将URB作为IRP的参数,用IoCallDriver将URB发送到底层总线驱动上。

    由于上层无法知道底层驱动是同步还异步完成的,因此需要做一个判断.If 语句判断当异步完成IRP时( if(ntStatus == STATUS_PENDING)),用事件等待总线驱动完成这个IRP。

     

    1. NTSTATUS  
    2. CallUSBD(  
    3.     IN PDEVICE_OBJECT DeviceObject,  
    4.     IN PURB           Urb  
    5.     )  
    6. /*++ 
    7.   
    8. Routine Description: 
    9.  
    10.     同步地提交一个URB到栈 
    11.  
    12. Arguments: 
    13.  
    14.     DeviceObject - pointer to device object 
    15.     Urb - USB request block 
    16.  
    17. Return Value: 
    18.  
    19. --*/  
    20. {  
    21.     PIRP               irp;  
    22.     KEVENT             event;  
    23.     NTSTATUS           ntStatus;  
    24.     IO_STATUS_BLOCK    ioStatus;  
    25.     PIO_STACK_LOCATION nextStack;  
    26.     PDEVICE_EXTENSION  deviceExtension;  
    27.   
    28.     //  
    29.     // initialize the variables  
    30.     //  
    31.   
    32.     irp = NULL;  
    33.     deviceExtension = DeviceObject->DeviceExtension;  
    34.       
    35.     KeInitializeEvent(&event, NotificationEvent, FALSE);  
    36.   
    37.     // 创建一个I/O控制码的IRP  
    38.     irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_SUBMIT_URB,   
    39.                                         deviceExtension->TopOfStackDeviceObject,  
    40.                                         NULL,   
    41.                                         0,   
    42.                                         NULL,   
    43.                                         0,   
    44.                                         TRUE,   
    45.                                         &event,   
    46.                                         &ioStatus);  
    47.   
    48.     if(!irp)   
    49.     {  
    50.   
    51.         BulkUsb_DbgPrint(1, ("IoBuildDeviceIoControlRequest failed "));  
    52.         return STATUS_INSUFFICIENT_RESOURCES;  
    53.     }  
    54.   
    55.     nextStack = IoGetNextIrpStackLocation(irp);  
    56.     ASSERT(nextStack != NULL);  
    57.     nextStack->Parameters.Others.Argument1 = Urb;  
    58.   
    59.     BulkUsb_DbgPrint(3, ("CallUSBD::"));  
    60.     BulkUsb_IoIncrement(deviceExtension);  
    61.   
    62.     // 用IoCallDriver将URB发送到底层总线驱动上   
    63.     ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, irp);  
    64.   
    65.     // 由于上层无法知道底层驱动是同步还异步完成的,因此需要做一个判断.If 语句判断当异步完成  
    66.     //  IRP时,用事件等待总线驱动完成这个IRP。  
    67.     if(ntStatus == STATUS_PENDING)  
    68.     {  
    69.   
    70.         KeWaitForSingleObject(&event,   
    71.                               Executive,   
    72.                               KernelMode,   
    73.                               FALSE,   
    74.                               NULL);  
    75.   
    76.         ntStatus = ioStatus.Status;  
    77.     }  
    78.       
    79.     BulkUsb_DbgPrint(3, ("CallUSBD::"));  
    80.     BulkUsb_IoDecrement(deviceExtension);  
    81.     return ntStatus;  
    82. }  


    3、3  USB设备初始化

    在AddDevice全程中,创建功能设备对象,然后将该对象挂载在总线设备对象之上,从而形成设备栈。

    另外为设备创建一个设备链接,便于应用程序可以找到这个设备。

    1. NTSTATUS  
    2. BulkUsb_AddDevice(  
    3.     IN PDRIVER_OBJECT DriverObject,  
    4.     IN PDEVICE_OBJECT PhysicalDeviceObject  
    5.     )  
    6. /*++ 
    7.  
    8. Description: 
    9.  
    10. Arguments: 
    11.  
    12.     DriverObject - Store the pointer to the object representing us. 
    13.  
    14.     PhysicalDeviceObject - Pointer to the device object created by the 
    15.                            undelying bus driver. 
    16.  
    17. Return: 
    18.      
    19.     STATUS_SUCCESS - if successful  
    20.     STATUS_UNSUCCESSFUL - otherwise 
    21.  
    22. --*/  
    23. {  
    24.     NTSTATUS          ntStatus;  
    25.     PDEVICE_OBJECT    deviceObject;  
    26.     PDEVICE_EXTENSION deviceExtension;  
    27.     POWER_STATE       state;  
    28.     KIRQL             oldIrql;  
    29.   
    30.     BulkUsb_DbgPrint(3, ("BulkUsb_AddDevice - begins "));  
    31.   
    32.     deviceObject = NULL;  
    33.   
    34.     ntStatus = IoCreateDevice(  
    35.                     DriverObject,                   // our driver object  
    36.                     sizeof(DEVICE_EXTENSION),       // extension size for us  
    37.                     NULL,                           // name for this device  
    38.                     FILE_DEVICE_UNKNOWN,  
    39.                     FILE_AUTOGENERATED_DEVICE_NAME, // device characteristics  
    40.                     FALSE,                          // Not exclusive  
    41.                     &deviceObject);                 // Our device object  
    42.   
    43.     if(!NT_SUCCESS(ntStatus))   
    44.     {  
    45.         //  
    46.         // returning failure here prevents the entire stack from functioning,  
    47.         // but most likely the rest of the stack will not be able to create  
    48.         // device objects either, so it is still OK.  
    49.         //                  
    50.         BulkUsb_DbgPrint(1, ("Failed to create device object "));  
    51.         return ntStatus;  
    52.     }  
    53.   
    54.     //  
    55.     // 初始化设备扩展  
    56.   
    57.     deviceExtension = (PDEVICE_EXTENSION) deviceObject->DeviceExtension;  
    58.     deviceExtension->FunctionalDeviceObject = deviceObject;  
    59.     deviceExtension->PhysicalDeviceObject = PhysicalDeviceObject;  
    60.     deviceObject->Flags |= DO_DIRECT_IO;  
    61.   
    62.     //  
    63.     // 初始化设备栈并设置设备状态  
    64.   
    65.     KeInitializeSpinLock(&deviceExtension->DevStateLock);  
    66.     INITIALIZE_PNP_STATE(deviceExtension);  
    67.   
    68.     //  
    69.     // 初始化 OpenHandleCount  
    70.     //  
    71.     deviceExtension->OpenHandleCount = 0;  
    72.   
    73.     //  
    74.     // 初始化可选的中止变量  
    75.     KeInitializeSpinLock(&deviceExtension->IdleReqStateLock);  
    76.     deviceExtension->IdleReqPend = 0;  
    77.     deviceExtension->PendingIdleIrp = NULL;  
    78.   
    79.     //  
    80.     // Hold住请求一直到设备开始  
    81.   
    82.     deviceExtension->QueueState = HoldRequests;  
    83.   
    84.     //  
    85.     // 初始化队列和队列 spin 锁  
    86.   
    87.     InitializeListHead(&deviceExtension->NewRequestsQueue);  
    88.     KeInitializeSpinLock(&deviceExtension->QueueLock);  
    89.   
    90.     //  
    91.     // 初始化可移除的事件到没信号  
    92.   
    93.     KeInitializeEvent(&deviceExtension->RemoveEvent,   
    94.                       SynchronizationEvent,   
    95.                       FALSE);  
    96.   
    97.     //  
    98.     // 初始化停止事件到有信号.  
    99.     // This event is signaled when the OutstandingIO becomes 1  
    100.     //  
    101.   
    102.     KeInitializeEvent(&deviceExtension->StopEvent,   
    103.                       SynchronizationEvent,   
    104.                       TRUE);  
    105.   
    106.     //  
    107.     // OutstandingIo count biased to 1.  
    108.     // Transition to 0 during remove device means IO is finished.  
    109.     // Transition to 1 means the device can be stopped  
    110.     //  
    111.   
    112.     deviceExtension->OutStandingIO = 1;  
    113.     KeInitializeSpinLock(&deviceExtension->IOCountLock);  
    114.   
    115.     //  
    116.     // Delegating to WMILIB  
    117.     //  
    118.     ntStatus = BulkUsb_WmiRegistration(deviceExtension);  
    119.   
    120.     if(!NT_SUCCESS(ntStatus)) {  
    121.   
    122.         BulkUsb_DbgPrint(1, ("BulkUsb_WmiRegistration failed with %X ", ntStatus));  
    123.         IoDeleteDevice(deviceObject);  
    124.         return ntStatus;  
    125.     }  
    126.   
    127.     //  
    128.     // 设置标示为 underlying PDO  
    129.     //  
    130.   
    131.     if(PhysicalDeviceObject->Flags & DO_POWER_PAGABLE) {  
    132.   
    133.         deviceObject->Flags |= DO_POWER_PAGABLE;  
    134.     }  
    135.   
    136.     //  
    137.     // Typically, the function driver for a device is its   
    138.     // power policy owner, although for some devices another   
    139.     // driver or system component may assume this role.   
    140.     // Set the initial power state of the device, if known, by calling   
    141.     // PoSetPowerState.  
    142.     //   
    143.   
    144.     deviceExtension->DevPower = PowerDeviceD0;  
    145.     deviceExtension->SysPower = PowerSystemWorking;  
    146.   
    147.     state.DeviceState = PowerDeviceD0;  
    148.     PoSetPowerState(deviceObject, DevicePowerState, state);  
    149.   
    150.     //  
    151.     // 把我们的驱动接入到设备栈  
    152.     // IoAttachDeviceToDeviceStack返回值是接入链的顶层对象  
    153.     //  This is where all the IRPs should be routed.  
    154.     //  
    155.   
    156.     deviceExtension->TopOfStackDeviceObject =   
    157.                 IoAttachDeviceToDeviceStack(deviceObject,  
    158.                                             PhysicalDeviceObject);  
    159.   
    160.     if(NULL == deviceExtension->TopOfStackDeviceObject) {  
    161.   
    162.         BulkUsb_WmiDeRegistration(deviceExtension);  
    163.         IoDeleteDevice(deviceObject);  
    164.         return STATUS_NO_SUCH_DEVICE;  
    165.     }  
    166.           
    167.     //  
    168.     // 注册设备接口  
    169.   
    170.     ntStatus = IoRegisterDeviceInterface(deviceExtension->PhysicalDeviceObject,   
    171.                                          &GUID_CLASS_I82930_BULK,   
    172.                                          NULL,   
    173.                                          &deviceExtension->InterfaceName);  
    174.   
    175.     if(!NT_SUCCESS(ntStatus))   
    176.     {  
    177.   
    178.         BulkUsb_WmiDeRegistration(deviceExtension);  
    179.         IoDetachDevice(deviceExtension->TopOfStackDeviceObject);  
    180.         IoDeleteDevice(deviceObject);  
    181.         return ntStatus;  
    182.     }  
    183.   
    184.     if(IoIsWdmVersionAvailable(1, 0x20))  
    185.     {  
    186.   
    187.         deviceExtension->WdmVersion = WinXpOrBetter;  
    188.     }  
    189.     else if(IoIsWdmVersionAvailable(1, 0x10))  
    190.     {  
    191.   
    192.         deviceExtension->WdmVersion = Win2kOrBetter;  
    193.     }  
    194.     else if(IoIsWdmVersionAvailable(1, 0x5))   
    195.     {  
    196.   
    197.         deviceExtension->WdmVersion = WinMeOrBetter;  
    198.     }  
    199.     else if(IoIsWdmVersionAvailable(1, 0x0)) {  
    200.   
    201.         deviceExtension->WdmVersion = Win98OrBetter;  
    202.     }  
    203.   
    204.     deviceExtension->SSRegistryEnable = 0;  
    205.     deviceExtension->SSEnable = 0;  
    206.   
    207.     //  
    208.     // WinXP only  
    209.     // check the registry flag -  
    210.     // whether the device should selectively  
    211.     // suspend when idle  
    212.     //  
    213.   
    214.     if(WinXpOrBetter == deviceExtension->WdmVersion)   
    215.     {  
    216.   
    217.         BulkUsb_GetRegistryDword(BULKUSB_REGISTRY_PARAMETERS_PATH,  
    218.                                  L"BulkUsbEnable",  
    219.                                  &deviceExtension->SSRegistryEnable);  
    220.   
    221.         if(deviceExtension->SSRegistryEnable) {  
    222.   
    223.             //  
    224.             // initialize DPC  
    225.             //  
    226.             KeInitializeDpc(&deviceExtension->DeferredProcCall,   
    227.                             DpcRoutine,   
    228.                             deviceObject);  
    229.   
    230.             //  
    231.             // initialize the timer.  
    232.             // the DPC and the timer in conjunction,   
    233.             // monitor the state of the device to   
    234.             // selectively suspend the device.  
    235.             //  
    236.             KeInitializeTimerEx(&deviceExtension->Timer,  
    237.                                 NotificationTimer);  
    238.   
    239.             //  
    240.             // Initialize the NoDpcWorkItemPendingEvent to signaled state.  
    241.             // This event is cleared when a Dpc is fired and signaled  
    242.             // on completion of the work-item.  
    243.             //  
    244.             KeInitializeEvent(&deviceExtension->NoDpcWorkItemPendingEvent,   
    245.                               NotificationEvent,   
    246.                               TRUE);  
    247.   
    248.             //  
    249.             // Initialize the NoIdleReqPendEvent to ensure that the idle request  
    250.             // is indeed complete before we unload the drivers.  
    251.             //  
    252.             KeInitializeEvent(&deviceExtension->NoIdleReqPendEvent,  
    253.                               NotificationEvent,  
    254.                               TRUE);  
    255.         }  
    256.     }  
    257.   
    258.     //  
    259.     // Clear the DO_DEVICE_INITIALIZING flag.  
    260.     // Note: Do not clear this flag until the driver has set the  
    261.     // device power state and the power DO flags.   
    262.     //  
    263.   
    264.     deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;  
    265.   
    266.     BulkUsb_DbgPrint(3, ("BulkUsb_AddDevice - ends "));  
    267.   
    268.     return ntStatus;  
    269. }  

    3、4 USB设备的插拔

    插拔设备会设计3个即插即用IRP,包括IRP_MN_START_DEVICE、

    IRP_MN_STOP_DEVICE 、IRP_MN_EJECT和IRP_MN_SURPRISE_REMOVAL.

    3、4、1

    IRP_MN_START_DEVICE 是当驱动争取加载并运行时,操作系统的即插即用管理器会将

    这个IRP发给设备驱动。因此当获得这个IRP后,USB驱动需要获得USB设备类别描述符,并通过这些

    描述符,从中获取有用信息,记录在设备扩展中。

    处理函数就是上面讲到的 HandleStartDevice 函数

    3、4、2

    IRP_MN_STOP_DEVICE 是设备关闭前,即插即用管理器发的IRP。USB驱动获得这个IRP时,

    应该尽快结束当前执行的IRP, 并将其逐个取消掉。别外在设备扩展中还应该有表示当前状态的变量,

    当IRP_MN_STOP_DEVICE来临时,将当前状态记录成停止状态。

    它的处理函数是:

    1. NTSTATUS  
    2. HandleStopDevice(  
    3.     IN PDEVICE_OBJECT DeviceObject,  
    4.     IN PIRP           Irp  
    5.     )  
    6. /*++ 
    7.  
    8. Routine Description: 
    9.  
    10.     This routine services Irp of minor type IRP_MN_STOP_DEVICE 
    11.  
    12. Arguments: 
    13.  
    14.     DeviceObject - pointer to device object 
    15.     Irp - I/O request packet sent by the pnp manager. 
    16.  
    17. Return Value: 
    18.  
    19.     NT status value 
    20.  
    21. --*/  
    22. {  
    23.     KIRQL             oldIrql;  
    24.     NTSTATUS          ntStatus;  
    25.     PDEVICE_EXTENSION deviceExtension;  
    26.   
    27.     BulkUsb_DbgPrint(3, ("HandleStopDevice - begins "));  
    28.   
    29.     //  
    30.     // initialize variables  
    31.     //  
    32.   
    33.     deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;  
    34.   
    35.   
    36.     if(WinXpOrBetter == deviceExtension->WdmVersion) {  
    37.   
    38.         if(deviceExtension->SSEnable) {  
    39.   
    40.             //  
    41.             // 取消定时器这样DPCs就不再激活.  
    42.             // Thus, we are making judicious usage of our resources.  
    43.             // 我们不再需要DPCs,因为设备已经停止.  
    44.             // The timers are re-initialized while handling the start  
    45.             // device irp.  
    46.             //  
    47.   
    48.             KeCancelTimer(&deviceExtension->Timer);  
    49.   
    50.             //  
    51.             // 在设备停止后,它能被强拨了.  
    52.             // 我们设置它为0,这样我们在强拨或移除Irps时不再偿试去取消定时器 .  
    53.             // 当我们再获得设备请求时,此标志会再被初始化  
    54.             //  
    55.             deviceExtension->SSEnable = 0;  
    56.   
    57.             //  
    58.             // make sure that if a DPC was fired before we called cancel timer,  
    59.             // then the DPC and work-time have run to their completion  
    60.             //  
    61.             KeWaitForSingleObject(&deviceExtension->NoDpcWorkItemPendingEvent,   
    62.                                   Executive,   
    63.                                   KernelMode,   
    64.                                   FALSE,   
    65.                                   NULL);  
    66.   
    67.             //  
    68.             // make sure that the selective suspend request has been completed.  
    69.             //  
    70.             KeWaitForSingleObject(&deviceExtension->NoIdleReqPendEvent,   
    71.                                   Executive,   
    72.                                   KernelMode,   
    73.                                   FALSE,   
    74.                                   NULL);  
    75.         }  
    76.     }  
    77.   
    78.     //  
    79.     // after the stop Irp is sent to the lower driver object,   
    80.     // the driver must not send any more Irps down that touch   
    81.     // the device until another Start has occurred.  
    82.     //  
    83.   
    84.     if(deviceExtension->WaitWakeEnable) {  
    85.       
    86.         CancelWaitWake(deviceExtension);  
    87.     }  
    88.   
    89.     KeAcquireSpinLock(&deviceExtension->DevStateLock, &oldIrql);  
    90.   
    91.     // 将当前状态记录成停止状态  
    92.     SET_NEW_PNP_STATE(deviceExtension, Stopped);  
    93.       
    94.     KeReleaseSpinLock(&deviceExtension->DevStateLock, oldIrql);  
    95.   
    96.     //  
    97.     // This is the right place to actually give up all the resources used  
    98.     // This might include calls to IoDisconnectInterrupt, MmUnmapIoSpace,   
    99.     // etc.  
    100.     //  
    101.   
    102.     ReleaseMemory(DeviceObject);  
    103.   
    104.     ntStatus = DeconfigureDevice(DeviceObject);  
    105.   
    106.     Irp->IoStatus.Status = ntStatus;  
    107.     Irp->IoStatus.Information = 0;  
    108.       
    109.     IoSkipCurrentIrpStackLocation(Irp);  
    110.     ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);  
    111.   
    112.     BulkUsb_DbgPrint(3, ("HandleStopDevice - ends "));  
    113.       
    114.     return ntStatus;  
    115. }  


     我们看到它在取消定时器后做了等待,这样能确保我们取消定时器时万一还在定时器的完成例程中时能等待例程完成,

    以免把设备停止了,可是DPC还在访问设备。所以在DPC例程中,首先做的事就是把自己的事件置为无信号

    1. KeClearEvent(&deviceExtension->NoDpcWorkItemPendingEvent);  

     

     

     

    3、4、3  IRP_MN_SURPRISE_REMOVAL

    IRP_MN_EJECT 是设备被正常弹出,而IRP_MN_SURPRISE_REMOVAL则是设备非自然弹出,

    有可能是掉电或强行拨出。在这种IRP到来时,应该强迫所有未完成的读写IRP结束并取消。

    1. NTSTATUS  
    2. HandleSurpriseRemoval(  
    3.     IN PDEVICE_OBJECT DeviceObject,  
    4.     IN PIRP           Irp  
    5.     )  
    6. /*++ 
    7.   
    8. Routine Description: 
    9.  
    10.     This routine services Irp of minor type IRP_MN_SURPRISE_REMOVAL 
    11.  
    12. Arguments: 
    13.  
    14.     DeviceObject - pointer to device object 
    15.     Irp - I/O request packet sent by the pnp manager. 
    16.  
    17. Return Value: 
    18.  
    19.     NT status value 
    20.  
    21. --*/  
    22. {  
    23.     KIRQL             oldIrql;  
    24.     NTSTATUS          ntStatus;  
    25.     PDEVICE_EXTENSION deviceExtension;  
    26.   
    27.     BulkUsb_DbgPrint(3, ("HandleSurpriseRemoval - begins "));  
    28.   
    29.     //  
    30.     // initialize variables  
    31.     //  
    32.   
    33.     deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;  
    34.   
    35.     //  
    36.     // 1. fail pending requests  
    37.     // 2. return device and memory resources  
    38.     // 3. disable interfaces  
    39.     //  
    40.   
    41.     if(deviceExtension->WaitWakeEnable) {  
    42.       
    43.         CancelWaitWake(deviceExtension);  
    44.     }  
    45.   
    46.   
    47.     if(WinXpOrBetter == deviceExtension->WdmVersion) {  
    48.   
    49.         if(deviceExtension->SSEnable) {  
    50.   
    51.             //  
    52.             // Cancel the timer so that the DPCs are no longer fired.  
    53.             // we do not need DPCs because the device has been surprise  
    54.             // removed  
    55.             //    
    56.           
    57.             KeCancelTimer(&deviceExtension->Timer);  
    58.   
    59.             deviceExtension->SSEnable = 0;  
    60.   
    61.             //    
    62.             // make sure that if a DPC was fired before we called cancel timer,  
    63.             // then the DPC and work-time have run to their completion  
    64.             //  
    65.             KeWaitForSingleObject(&deviceExtension->NoDpcWorkItemPendingEvent,   
    66.                                   Executive,   
    67.                                   KernelMode,   
    68.                                   FALSE,   
    69.                                   NULL);  
    70.   
    71.             //  
    72.             // make sure that the selective suspend request has been completed.  
    73.             //  
    74.             KeWaitForSingleObject(&deviceExtension->NoIdleReqPendEvent,   
    75.                                   Executive,   
    76.                                   KernelMode,   
    77.                                   FALSE,   
    78.                                   NULL);  
    79.         }  
    80.     }  
    81.   
    82.     KeAcquireSpinLock(&deviceExtension->DevStateLock, &oldIrql);  
    83.   
    84.     deviceExtension->QueueState = FailRequests;  
    85.     SET_NEW_PNP_STATE(deviceExtension, SurpriseRemoved);  
    86.   
    87.     KeReleaseSpinLock(&deviceExtension->DevStateLock, oldIrql);  
    88.   
    89.     ProcessQueuedRequests(deviceExtension);  
    90.   
    91.     ntStatus = IoSetDeviceInterfaceState(&deviceExtension->InterfaceName,   
    92.                                          FALSE);  
    93.   
    94.     if(!NT_SUCCESS(ntStatus)) {  
    95.   
    96.         BulkUsb_DbgPrint(1, ("IoSetDeviceInterfaceState::disable:failed "));  
    97.     }  
    98.   
    99.     BulkUsb_AbortPipes(DeviceObject);  
    100.   
    101.     Irp->IoStatus.Status = STATUS_SUCCESS;  
    102.     Irp->IoStatus.Information = 0;  
    103.   
    104.     IoSkipCurrentIrpStackLocation(Irp);  
    105.     ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);  
    106.   
    107.     BulkUsb_DbgPrint(3, ("HandleSurpriseRemoval - ends "));  
    108.   
    109.     return ntStatus;  
    110. }  

    3、4 USB设备的读写

    USB设备接口主要是为了传送数据,80%的传输是通过Bulk管道。在BulkUSB驱动中,Bulk管道的读取是在IRP_MJ_READ和IRP_MJ_WRITE的函数中。

    IRP_MJ_READ和IRP_MJ_WRITE的派遣函数我们设置为同一个BulkUsb_DispatchReadWrite:

     

    1. NTSTATUS  
    2. BulkUsb_DispatchReadWrite(  
    3.     IN PDEVICE_OBJECT DeviceObject,  
    4.     IN PIRP           Irp  
    5.     )  
    6. /*++ 
    7.   
    8. Routine Description: 
    9.  
    10.     Dispatch routine for read and write. 
    11.     This routine creates a BULKUSB_RW_CONTEXT for a read/write. 
    12.     This read/write is performed in stages of BULKUSB_MAX_TRANSFER_SIZE. 
    13.     once a stage of transfer is complete, then the irp is circulated again,  
    14.     until the requested length of tranfer is performed. 
    15.  
    16. Arguments: 
    17.  
    18.     DeviceObject - pointer to device object 
    19.     Irp - I/O request packet 
    20.  
    21. Return Value: 
    22.  
    23.     NT status value 
    24.  
    25. --*/  
    26. {  
    27.     PMDL                   mdl;  
    28.     PURB                   urb;  
    29.     ULONG                  totalLength;  
    30.     ULONG                  stageLength;  
    31.     ULONG                  urbFlags;  
    32.     BOOLEAN                read;  
    33.     NTSTATUS               ntStatus;  
    34.     ULONG_PTR              virtualAddress;  
    35.     PFILE_OBJECT           fileObject;  
    36.     PDEVICE_EXTENSION      deviceExtension;  
    37.     PIO_STACK_LOCATION     irpStack;  
    38.     PIO_STACK_LOCATION     nextStack;  
    39.     PBULKUSB_RW_CONTEXT    rwContext;  
    40.     PUSBD_PIPE_INFORMATION pipeInformation;  
    41.   
    42.     //  
    43.     // 初始化变量  
    44.     urb = NULL;  
    45.     mdl = NULL;  
    46.     rwContext = NULL;  
    47.     totalLength = 0;  
    48.     irpStack = IoGetCurrentIrpStackLocation(Irp);  
    49.     fileObject = irpStack->FileObject;  
    50.     read = (irpStack->MajorFunction == IRP_MJ_READ) ? TRUE : FALSE;  
    51.     deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;  
    52.   
    53.     BulkUsb_DbgPrint(3, ("BulkUsb_DispatchReadWrite - begins "));  
    54.   
    55.     if(deviceExtension->DeviceState != Working) {  
    56.   
    57.         BulkUsb_DbgPrint(1, ("Invalid device state "));  
    58.   
    59.         ntStatus = STATUS_INVALID_DEVICE_STATE;  
    60.         goto BulkUsb_DispatchReadWrite_Exit;  
    61.     }  
    62.   
    63.     //  
    64.     // It is true that the client driver cancelled the selective suspend  
    65.     // request in the dispatch routine for create Irps.  
    66.     // But there is no guarantee that it has indeed completed.  
    67.     // so wait on the NoIdleReqPendEvent and proceed only if this event  
    68.     // is signalled.  
    69.     //  
    70.     BulkUsb_DbgPrint(3, ("Waiting on the IdleReqPendEvent "));  
    71.       
    72.     //  
    73.     // make sure that the selective suspend request has been completed.  
    74.     //  
    75.   
    76.     if(deviceExtension->SSEnable)  
    77.     {  
    78.   
    79.         KeWaitForSingleObject(&deviceExtension->NoIdleReqPendEvent,   
    80.                               Executive,   
    81.                               KernelMode,   
    82.                               FALSE,   
    83.                               NULL);  
    84.     }  
    85.   
    86.     if(fileObject && fileObject->FsContext)   
    87.     {  
    88.   
    89.         pipeInformation = fileObject->FsContext;  
    90.   
    91.         if(UsbdPipeTypeBulk != pipeInformation->PipeType) {  
    92.               
    93.             BulkUsb_DbgPrint(1, ("Usbd pipe type is not bulk "));  
    94.   
    95.             ntStatus = STATUS_INVALID_HANDLE;  
    96.             goto BulkUsb_DispatchReadWrite_Exit;  
    97.         }  
    98.     }  
    99.     else   
    100.     {  
    101.   
    102.         BulkUsb_DbgPrint(1, ("Invalid handle "));  
    103.   
    104.         ntStatus = STATUS_INVALID_HANDLE;  
    105.         goto BulkUsb_DispatchReadWrite_Exit;  
    106.     }  
    107.   
    108.     // 设置完成例程的参数  
    109.     rwContext = (PBULKUSB_RW_CONTEXT)  
    110.                 ExAllocatePool(NonPagedPool,  
    111.                                sizeof(BULKUSB_RW_CONTEXT));  
    112.   
    113.     if(rwContext == NULL)  
    114.     {  
    115.           
    116.         BulkUsb_DbgPrint(1, ("Failed to alloc mem for rwContext "));  
    117.   
    118.         ntStatus = STATUS_INSUFFICIENT_RESOURCES;  
    119.         goto BulkUsb_DispatchReadWrite_Exit;  
    120.     }  
    121.   
    122.     if(Irp->MdlAddress)  
    123.     {  
    124.   
    125.         totalLength = MmGetMdlByteCount(Irp->MdlAddress);  
    126.     }  
    127.   
    128.     if(totalLength > BULKUSB_TEST_BOARD_TRANSFER_BUFFER_SIZE)  
    129.     {  
    130.   
    131.         BulkUsb_DbgPrint(1, ("Transfer length > circular buffer "));  
    132.   
    133.         ntStatus = STATUS_INVALID_PARAMETER;  
    134.   
    135.         ExFreePool(rwContext);  
    136.   
    137.         goto BulkUsb_DispatchReadWrite_Exit;  
    138.     }  
    139.   
    140.     if(totalLength == 0)  
    141.     {  
    142.   
    143.         BulkUsb_DbgPrint(1, ("Transfer data length = 0 "));  
    144.   
    145.         ntStatus = STATUS_SUCCESS;  
    146.   
    147.         ExFreePool(rwContext);  
    148.   
    149.         goto BulkUsb_DispatchReadWrite_Exit;  
    150.     }  
    151.   
    152.     // 设置URB标志  
    153.     urbFlags = USBD_SHORT_TRANSFER_OK;  
    154.     virtualAddress = (ULONG_PTR) MmGetMdlVirtualAddress(Irp->MdlAddress);  
    155.   
    156.     // 判断是读还是写  
    157.     if(read)   
    158.     {  
    159.   
    160.         urbFlags |= USBD_TRANSFER_DIRECTION_IN;  
    161.         BulkUsb_DbgPrint(3, ("Read operation "));  
    162.     }  
    163.     else  
    164.     {  
    165.   
    166.         urbFlags |= USBD_TRANSFER_DIRECTION_OUT;  
    167.         BulkUsb_DbgPrint(3, ("Write operation "));  
    168.     }  
    169.   
    170.     //  
    171.     // the transfer request is for totalLength.  
    172.     // we can perform a max of BULKUSB_MAX_TRANSFER_SIZE  
    173.     // in each stage.  
    174.     //  
    175.     if(totalLength > BULKUSB_MAX_TRANSFER_SIZE)   
    176.     {  
    177.   
    178.         stageLength = BULKUSB_MAX_TRANSFER_SIZE;  
    179.     }  
    180.     else   
    181.     {  
    182.   
    183.         stageLength = totalLength;  
    184.     }  
    185.   
    186.     // 建立MDL  
    187.     mdl = IoAllocateMdl((PVOID) virtualAddress,  
    188.                         totalLength,  
    189.                         FALSE,  
    190.                         FALSE,  
    191.                         NULL);  
    192.   
    193.     if(mdl == NULL)  
    194.     {  
    195.       
    196.         BulkUsb_DbgPrint(1, ("Failed to alloc mem for mdl "));  
    197.   
    198.         ntStatus = STATUS_INSUFFICIENT_RESOURCES;  
    199.   
    200.         ExFreePool(rwContext);  
    201.   
    202.         goto BulkUsb_DispatchReadWrite_Exit;  
    203.     }  
    204.   
    205.     //  
    206.     // 将新MDL进行映射  
    207.     // map the portion of user-buffer described by an mdl to another mdl  
    208.     //  
    209.     IoBuildPartialMdl(Irp->MdlAddress,  
    210.                       mdl,  
    211.                       (PVOID) virtualAddress,  
    212.                       stageLength);  
    213.   
    214.     // 申请URB数据结构  
    215.     urb = ExAllocatePool(NonPagedPool,  
    216.                          sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER));  
    217.   
    218.     if(urb == NULL)   
    219.     {  
    220.   
    221.         BulkUsb_DbgPrint(1, ("Failed to alloc mem for urb "));  
    222.   
    223.         ntStatus = STATUS_INSUFFICIENT_RESOURCES;  
    224.   
    225.         ExFreePool(rwContext);  
    226.         IoFreeMdl(mdl);  
    227.   
    228.         goto BulkUsb_DispatchReadWrite_Exit;  
    229.     }  
    230.   
    231.     // 建立Bulk管道的URB  
    232.     UsbBuildInterruptOrBulkTransferRequest(  
    233.                             urb,  
    234.                             sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),  
    235.                             pipeInformation->PipeHandle,  
    236.                             NULL,  
    237.                             mdl,  
    238.                             stageLength,  
    239.                             urbFlags,  
    240.                             NULL);  
    241.   
    242.     //  
    243.     // 设置完成例程参数  BULKUSB_RW_CONTEXT    
    244.     //  
    245.       
    246.     rwContext->Urb             = urb;  
    247.     rwContext->Mdl             = mdl;  
    248.     rwContext->Length          = totalLength - stageLength;  
    249.     rwContext->Numxfer         = 0;  
    250.     rwContext->VirtualAddress  = virtualAddress + stageLength;  
    251.     rwContext->DeviceExtension = deviceExtension;  
    252.   
    253.     //  
    254.     // use the original read/write irp as an internal device control irp  
    255.     // 设置设备堆栈  
    256.   
    257.     nextStack = IoGetNextIrpStackLocation(Irp);  
    258.     nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;  
    259.     nextStack->Parameters.Others.Argument1 = (PVOID) urb;  
    260.     nextStack->Parameters.DeviceIoControl.IoControlCode =   
    261.                                              IOCTL_INTERNAL_USB_SUBMIT_URB;  
    262.   
    263.     // 设置完成例程式  
    264.     IoSetCompletionRoutine(Irp,   
    265.                            (PIO_COMPLETION_ROUTINE)BulkUsb_ReadWriteCompletion,  
    266.                            rwContext,  
    267.                            TRUE,  
    268.                            TRUE,  
    269.                            TRUE);  
    270.   
    271.     //  
    272.     // since we return STATUS_PENDING call IoMarkIrpPending.  
    273.     // This is the boiler plate code.  
    274.     // This may cause extra overhead of an APC for the Irp completion  
    275.     // but this is the correct thing to do.  
    276.     //  
    277.   
    278.     // 将当前IRP阻塞  
    279.     IoMarkIrpPending(Irp);  
    280.   
    281.     BulkUsb_DbgPrint(3, ("BulkUsb_DispatchReadWrite::"));  
    282.     BulkUsb_IoIncrement(deviceExtension);  
    283.   
    284.     // 将IRP转发到底层USB总线驱动  
    285.     ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject,  
    286.                             Irp);  
    287.   
    288.     if(!NT_SUCCESS(ntStatus)) {  
    289.   
    290.         BulkUsb_DbgPrint(1, ("IoCallDriver fails with status %X ", ntStatus));  
    291.   
    292.         //  
    293.         // if the device was yanked out, then the pipeInformation   
    294.         // field is invalid.  
    295.         // similarly if the request was cancelled, then we need not  
    296.         // invoked reset pipe/device.  
    297.         //  
    298.         if((ntStatus != STATUS_CANCELLED) &&   
    299.            (ntStatus != STATUS_DEVICE_NOT_CONNECTED)) {  
    300.               
    301.             ntStatus = BulkUsb_ResetPipe(DeviceObject,  
    302.                                      pipeInformation);  
    303.       
    304.             if(!NT_SUCCESS(ntStatus)) {  
    305.   
    306.                 BulkUsb_DbgPrint(1, ("BulkUsb_ResetPipe failed "));  
    307.   
    308.                 ntStatus = BulkUsb_ResetDevice(DeviceObject);  
    309.             }  
    310.         }  
    311.         else {  
    312.   
    313.             BulkUsb_DbgPrint(3, ("ntStatus is STATUS_CANCELLED or "  
    314.                                  "STATUS_DEVICE_NOT_CONNECTED "));  
    315.         }  
    316.     }  
    317.   
    318.     //  
    319.     // we return STATUS_PENDING and not the status returned by the lower layer.  
    320.     //  
    321.     return STATUS_PENDING;  
    322.   
    323. BulkUsb_DispatchReadWrite_Exit:  
    324.   
    325.     Irp->IoStatus.Status = ntStatus;  
    326.     Irp->IoStatus.Information = 0;  
    327.   
    328.     IoCompleteRequest(Irp, IO_NO_INCREMENT);  
    329.   
    330.     BulkUsb_DbgPrint(3, ("BulkUsb_DispatchReadWrite - ends "));  
    331.   
    332.     return ntStatus;  
    333. }  

    (1)如果设备状态不是Working,直接返回,因为此时设备已经拔掉了;

    (2)如果应用程序要读的Pipe不是Bulk(Pipe信息从设备栈中的FileObject对象中获得),那么也直接返回;

    (3)调用MmGetMdlByteCount从Irp中的MdlAddress得到Byte数量(这个数量就是应用层想读或写的数量)及virtualAddress,然后根据它们建立MDL,

    并调用IoBuildPartialMdl将用户的Buffer将映射到新建的虚地址中;

    如果Byte数量过大或为0,那么直接返回

    1. // 建立MDL  
    2.     mdl = IoAllocateMdl((PVOID) virtualAddress,  
    3.                         totalLength,  
    4.                         FALSE,  
    5.                         FALSE,  
    6.                         NULL);  
    1. IoBuildPartialMdl(Irp->MdlAddress,  
    2.                      mdl,  
    3.                      (PVOID) virtualAddress,  
    4.                      stageLength);  

     

    (4)根据MDL建立Bulk管道的URB;

    1. // 建立Bulk管道的URB  
    2.     UsbBuildInterruptOrBulkTransferRequest(  
    3.                             urb,  
    4.                             sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),  
    5.                             pipeInformation->PipeHandle,  
    6.                             NULL,  
    7.                             mdl,  
    8.                             stageLength,  
    9.                             urbFlags,  
    10.                             NULL);  


    (5)把上面得到的URB组合成一个新的IRP(操作码为IOCTL_INTERNAL_USB_SUBMIT_URB),设置完成例程(如3、5所讲)传递给总线管理器;

     

    1. nextStack = IoGetNextIrpStackLocation(Irp);  
    2.    nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;  
    3.    nextStack->Parameters.Others.Argument1 = (PVOID) urb;  
    4.    nextStack->Parameters.DeviceIoControl.IoControlCode =   
    5.                                             IOCTL_INTERNAL_USB_SUBMIT_URB;  
    6.   
    7. // 设置完成例程式  
    8.    IoSetCompletionRoutine(Irp,   
    9.                           (PIO_COMPLETION_ROUTINE)BulkUsb_ReadWriteCompletion,  
    10.                           rwContext,  
    11.                           TRUE,  
    12.                           TRUE,  
    13.                           TRUE);  


     

    1. // 将当前IRP阻塞  
    2.    IoMarkIrpPending(Irp);  
    3.   
    4.    BulkUsb_DbgPrint(3, ("BulkUsb_DispatchReadWrite::"));  
    5.    BulkUsb_IoIncrement(deviceExtension);  
    6.   
    7. // 将IRP转发到底层USB总线驱动  
    8.    ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject,  
    9.                            Irp);  


     

     

    3、5  读写完成的例子程是

     

    1. NTSTATUS  
    2. BulkUsb_ReadWriteCompletion(  
    3.     IN PDEVICE_OBJECT DeviceObject,  
    4.     IN PIRP           Irp,  
    5.     IN PVOID          Context  
    6.     )  
    7. /*++ 
    8.   
    9. Routine Description: 
    10.  
    11.     This is the completion routine for reads/writes 
    12.     If the irp completes with success, we check if we 
    13.     need to recirculate this irp for another stage of 
    14.     transfer. In this case return STATUS_MORE_PROCESSING_REQUIRED. 
    15.     if the irp completes in error, free all memory allocs and 
    16.     return the status. 
    17.  
    18. Arguments: 
    19.  
    20.     DeviceObject - pointer to device object 
    21.     Irp - I/O request packet 
    22.     Context - context passed to the completion routine. 
    23.  
    24. Return Value: 
    25.  
    26.     NT status value 
    27.  
    28. --*/  
    29. {  
    30.     ULONG               stageLength;  
    31.     NTSTATUS            ntStatus;  
    32.     PIO_STACK_LOCATION  nextStack;  
    33.     PBULKUSB_RW_CONTEXT rwContext;  
    34.   
    35.     //  
    36.     // initialize variables  
    37.     //  
    38.     rwContext = (PBULKUSB_RW_CONTEXT) Context;  
    39.     ntStatus = Irp->IoStatus.Status;  
    40.   
    41.     UNREFERENCED_PARAMETER(DeviceObject);  
    42.     BulkUsb_DbgPrint(3, ("BulkUsb_ReadWriteCompletion - begins "));  
    43.   
    44.     //  
    45.     // successfully performed a stageLength of transfer.  
    46.     // check if we need to recirculate the irp.  
    47.     //  
    48.     if(NT_SUCCESS(ntStatus)) {  
    49.   
    50.         if(rwContext) {  
    51.   
    52.             rwContext->Numxfer +=   
    53.               rwContext->Urb->UrbBulkOrInterruptTransfer.TransferBufferLength;  
    54.           
    55.             if(rwContext->Length) {  
    56.   
    57.                 //  
    58.                 // another stage transfer  
    59.                 //  
    60.                 BulkUsb_DbgPrint(3, ("Another stage transfer... "));  
    61.   
    62.                 if(rwContext->Length > BULKUSB_MAX_TRANSFER_SIZE) {  
    63.               
    64.                     stageLength = BULKUSB_MAX_TRANSFER_SIZE;  
    65.                 }  
    66.                 else {  
    67.                   
    68.                     stageLength = rwContext->Length;  
    69.                 }  
    70.   
    71.                 IoBuildPartialMdl(Irp->MdlAddress,  
    72.                                   rwContext->Mdl,  
    73.                                   (PVOID) rwContext->VirtualAddress,  
    74.                                   stageLength);  
    75.               
    76.                 //  
    77.                 // reinitialize the urb  
    78.                 //  
    79.                 rwContext->Urb->UrbBulkOrInterruptTransfer.TransferBufferLength   
    80.                                                                   = stageLength;  
    81.                 rwContext->VirtualAddress += stageLength;  
    82.                 rwContext->Length -= stageLength;  
    83.   
    84.                 nextStack = IoGetNextIrpStackLocation(Irp);  
    85.                 nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;  
    86.                 nextStack->Parameters.Others.Argument1 = rwContext->Urb;  
    87.                 nextStack->Parameters.DeviceIoControl.IoControlCode =   
    88.                                             IOCTL_INTERNAL_USB_SUBMIT_URB;  
    89.   
    90.                 IoSetCompletionRoutine(Irp,  
    91.                                        BulkUsb_ReadWriteCompletion,  
    92.                                        rwContext,  
    93.                                        TRUE,  
    94.                                        TRUE,  
    95.                                        TRUE);  
    96.   
    97.                 IoCallDriver(rwContext->DeviceExtension->TopOfStackDeviceObject,   
    98.                              Irp);  
    99.   
    100.                 return STATUS_MORE_PROCESSING_REQUIRED;  
    101.             }  
    102.             else {  
    103.   
    104.                 //  
    105.                 // this is the last transfer  
    106.                 //  
    107.   
    108.                 Irp->IoStatus.Information = rwContext->Numxfer;  
    109.             }  
    110.         }  
    111.     }  
    112.     else {  
    113.   
    114.         BulkUsb_DbgPrint(1, ("ReadWriteCompletion - failed with status = %X ", ntStatus));  
    115.     }  
    116.       
    117.     if(rwContext) {  
    118.   
    119.         //  
    120.         // dump rwContext  
    121.         //  
    122.         BulkUsb_DbgPrint(3, ("rwContext->Urb             = %X ",   
    123.                              rwContext->Urb));  
    124.         BulkUsb_DbgPrint(3, ("rwContext->Mdl             = %X ",   
    125.                              rwContext->Mdl));  
    126.         BulkUsb_DbgPrint(3, ("rwContext->Length          = %d ",   
    127.                              rwContext->Length));  
    128.         BulkUsb_DbgPrint(3, ("rwContext->Numxfer         = %d ",   
    129.                              rwContext->Numxfer));  
    130.         BulkUsb_DbgPrint(3, ("rwContext->VirtualAddress  = %X ",   
    131.                              rwContext->VirtualAddress));  
    132.         BulkUsb_DbgPrint(3, ("rwContext->DeviceExtension = %X ",   
    133.                              rwContext->DeviceExtension));  
    134.   
    135.         BulkUsb_DbgPrint(3, ("BulkUsb_ReadWriteCompletion::"));  
    136.         BulkUsb_IoDecrement(rwContext->DeviceExtension);  
    137.   
    138.         ExFreePool(rwContext->Urb);  
    139.         IoFreeMdl(rwContext->Mdl);  
    140.         ExFreePool(rwContext);  
    141.     }  
    142.   
    143.     BulkUsb_DbgPrint(3, ("BulkUsb_ReadWriteCompletion - ends "));  
    144.   
    145.     return ntStatus;  
    146. }  


     


    4、编译过程中出来以下报错。

     

    1. 1>LINK : error LNK2001: unresolved external symbol _mainCRTStartup  
    2. 1>rwbulk.obj : error LNK2019: unresolved external symbol _printf referenced in function _OpenOneDevice@12  
    3. 1>rwbulk.obj : error LNK2019: unresolved external symbol _free referenced in function _OpenOneDevice@12  
    4. 1>rwbulk.obj : error LNK2019: unresolved external symbol _malloc referenced in function _OpenOneDevice@12  
    5. 1>rwbulk.obj : error LNK2019: unresolved external symbol _calloc referenced in function _OpenUsbDevice@8  
    6. 1>rwbulk.obj : error LNK2019: unresolved external symbol _realloc referenced in function _OpenUsbDevice@8  
    7. 1>rwbulk.obj : error LNK2019: unresolved external symbol _atoi referenced in function _parse@8  
    8. 1>rwbulk.obj : error LNK2019: unresolved external symbol __assert referenced in function _main  


     

    解决方法:在sources中添加USE_MSVCRT=1项.

    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    页面显示时间
    如何用JavaScript实现获取验证码的效果
    CSS中style用法详解
    html 样式之style属性的使用
    使用JavaScript实现弹出层效果的简单实例
    [转]创建一个JavaScript弹出DIV窗口层的效果
    eclipse环境下如何配置tomcat,并且把项目部署到Tomcat服务器上
    关于eclipse部署项目后,在tomcat中的webapps文件夹下没有项目
    jsp页面提示“Multiple annotations found at this line:
    Maven3路程(三)用Maven创建第一个web项目(1)
  • 原文地址:https://www.cnblogs.com/mao0504/p/4706400.html
Copyright © 2011-2022 走看看