USB WDM驱动开发实例 bulkusb

简介: <p style="color: rgb(51, 51, 51); font-family: Arial; font-size: 14px; line-height: 26px;">参考书籍<<Windows驱动开发技术详解>></p><p style="color: rgb(51, 51, 51); font-family: Arial; font-size: 14

参考书籍<<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);

 

[cpp]  view plain copy
  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, ("///////////////////////////////////////////\n"));  
  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)在设备扩展中留出两字段,分别存当前状态和之前状态。

[cpp]  view plain copy
  1. // current state of device  
  2.    DEVSTATE DeviceState;  
  3.   
  4.    // state prior to removal query  
  5.    DEVSTATE PrevDevState;  


(1、2)在初始化时

(1、3)在改变时

通过以下宏来改变状态

[cpp]  view plain copy
  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

[cpp]  view plain copy
  1. //  
  2.    // 读设备描述符,配置描述符并选择接口描述符  
  3.    //  
  4.   
  5.    ntStatus = ReadandSelectDescriptors(DeviceObject);  
  6.   
  7.    if(!NT_SUCCESS(ntStatus)) {  
  8.   
  9.        BulkUsb_DbgPrint(1, ("ReadandSelectDescriptors failed\n"));  
  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

[cpp]  view plain copy
  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的使用:

[cpp]  view plain copy
  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\n"));  
  9.    }  
  10.   
  11.    BulkUsb_AbortPipes(DeviceObject);  

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

[cpp]  view plain copy
  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来读取设备描述符

[cpp]  view plain copy
  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\n"));  
  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\n"));  
  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\n"));  
  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\n"));  
  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\n"));  
  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到下层,设置完成例程,等待完成。
[cpp]  view plain 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间隔);

[cpp]  view plain copy
  1. if(DeviceExtension->SSEnable) {  
  2.   
  3.        BulkUsb_DbgPrint(3, ("Set the timer to fire DPCs\n"));  
  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\n"));  
  13.    }  

这里补充定时器的使用:

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

A、初始化定时器

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

[cpp]  view plain copy
  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状态。判断方法如下:

[cpp]  view plain copy
  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

[cpp]  view plain copy
  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;  


 

[cpp]  view plain copy
  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传到栈下面:

[cpp]  view plain copy
  1. ntStatus = IoCallDriver(DeviceExtension->TopOfStackDeviceObject, irp);  

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

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

[cpp]  view plain copy
  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后得到

[cpp]  view plain copy
  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 )

 

[cpp]  view plain copy
  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。(重点)

 

[cpp]  view plain copy
  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配置描述符,以得到一个指定的接口,可改变的设备类子类或协议代码。

 

[cpp]  view plain copy
  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)表满足所有;

[cpp]  view plain copy
  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\n"));  
  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的列表入口来终止。

[cpp]  view plain copy
  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。

 

[cpp]  view plain copy
  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\n"));  
  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全程中,创建功能设备对象,然后将该对象挂载在总线设备对象之上,从而形成设备栈。

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

[cpp]  view plain copy
  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\n"));  
  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\n"));  
  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\n", 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\n"));  
  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来临时,将当前状态记录成停止状态。

它的处理函数是:

[cpp]  view plain copy
  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\n"));  
  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\n"));  
  113.       
  114.     return ntStatus;  
  115. }  


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

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

[cpp]  view plain copy
  1. KeClearEvent(&deviceExtension->NoDpcWorkItemPendingEvent);  

 

 

 

3、4、3  IRP_MN_SURPRISE_REMOVAL

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

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

[cpp]  view plain copy
  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\n"));  
  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\n"));  
  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\n"));  
  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:

 

[cpp]  view plain copy
  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\n"));  
  54.   
  55.     if(deviceExtension->DeviceState != Working) {  
  56.   
  57.         BulkUsb_DbgPrint(1, ("Invalid device state\n"));  
  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\n"));  
  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\n"));  
  94.   
  95.             ntStatus = STATUS_INVALID_HANDLE;  
  96.             goto BulkUsb_DispatchReadWrite_Exit;  
  97.         }  
  98.     }  
  99.     else   
  100.     {  
  101.   
  102.         BulkUsb_DbgPrint(1, ("Invalid handle\n"));  
  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\n"));  
  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\n"));  
  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\n"));  
  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\n"));  
  162.     }  
  163.     else  
  164.     {  
  165.   
  166.         urbFlags |= USBD_TRANSFER_DIRECTION_OUT;  
  167.         BulkUsb_DbgPrint(3, ("Write operation\n"));  
  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\n"));  
  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\n"));  
  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\n", 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\n"));  
  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\n"));  
  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\n"));  
  331.   
  332.     return ntStatus;  
  333. }  

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

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

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

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

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

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

 

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

[cpp]  view plain copy
  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所讲)传递给总线管理器;

 

[cpp]  view plain copy
  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);  


 

[cpp]  view plain copy
  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  读写完成的例子程是

 

[cpp]  view plain copy
  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\n"));  
  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...\n"));  
  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\n", ntStatus));  
  115.     }  
  116.       
  117.     if(rwContext) {  
  118.   
  119.         //  
  120.         // dump rwContext  
  121.         //  
  122.         BulkUsb_DbgPrint(3, ("rwContext->Urb             = %X\n",   
  123.                              rwContext->Urb));  
  124.         BulkUsb_DbgPrint(3, ("rwContext->Mdl             = %X\n",   
  125.                              rwContext->Mdl));  
  126.         BulkUsb_DbgPrint(3, ("rwContext->Length          = %d\n",   
  127.                              rwContext->Length));  
  128.         BulkUsb_DbgPrint(3, ("rwContext->Numxfer         = %d\n",   
  129.                              rwContext->Numxfer));  
  130.         BulkUsb_DbgPrint(3, ("rwContext->VirtualAddress  = %X\n",   
  131.                              rwContext->VirtualAddress));  
  132.         BulkUsb_DbgPrint(3, ("rwContext->DeviceExtension = %X\n",   
  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\n"));  
  144.   
  145.     return ntStatus;  
  146. }  


 


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

 

[plain]  view plain copy
  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项.

相关文章
|
10月前
|
存储 Linux 开发者
【Linux学习笔记】设备驱动模型详解——总线、设备、驱动和类
设备驱动是计算机系统中的重要组成部分,它们允许操作系统与硬件交互。设备驱动模型是一种通用的抽象框架,用于描述操作系统如何管理硬件设备。这里我们将介绍设备驱动模型中的四个关键概念:总线、设备、驱动和类。
485 0
|
11月前
|
Web App开发 芯片
USB2S可编程USB转串口适配器的开发原理
USB2S可编程USB转串口适配器的开发原理主要涉及USB接口协议、USB控制器芯片以及串口通信协议等方面。
USB2S可编程USB转串口适配器的开发原理
|
11月前
|
XML 测试技术 网络安全
开发工具:USB转IIC/I2C/SPI/UART适配器模块可编程开发板
总的思路是通过USB或者UART接口发送一些协议字符串,由模块转换成上面几种接口的硬件时序电信号,实现与这几种接口芯片、设备的快速测试。 首先声明一下,大家都是搞硬件开发的,这几种接口当然是很简单的事,但有些时候对于一个新的设备或者芯片的测试,有个现成的工具当然更顺手,节省时间,也更可靠嘛。
|
11月前
|
XML 测试技术 网络安全
开发调试工具:可编程USB转IIC/I2C/SPI/UART适配器模块开发板
发个方便测试I2C、SPI、1Wire接口的工具模块 总的思路是通过USB或者UART接口发送一些协议字符串,由模块转换成上面几种接口的硬件时序电信号,实现与这几种接口芯片、设备的快速测试。
|
11月前
|
XML 传感器 数据格式
可编程 USB 转串口适配器开发板主要开发测试作用
上面写的东西不少,其实这个模块用法特别简单,拿到套件和专门的工具软件后一分钟都不需要就完全明白了,如果想编写自己的xml驱动,随便打开一个照葫芦画瓢,然后另存就行。
RK3399平台开发系列讲解(高速设备驱动篇)6.61、USB如何模拟HID设备
RK3399平台开发系列讲解(高速设备驱动篇)6.61、USB如何模拟HID设备
119 0
RK3399平台开发系列讲解(高速设备驱动篇)6.61、USB如何模拟HID设备
|
Linux 开发工具 git
嵌入式linux/鸿蒙开发板(IMX6ULL)开发(三十)LED模板驱动程序的改造:总线设备驱动模型
嵌入式linux/鸿蒙开发板(IMX6ULL)开发(三十)LED模板驱动程序的改造:总线设备驱动模型
189 1
嵌入式linux/鸿蒙开发板(IMX6ULL)开发(三十)LED模板驱动程序的改造:总线设备驱动模型
|
Linux 开发工具 git
嵌入式linux/鸿蒙开发板(IMX6ULL)开发(三十六)GPIO和Pinctrl子系统的使用(下)
嵌入式linux/鸿蒙开发板(IMX6ULL)开发(三十六)GPIO和Pinctrl子系统的使用
255 0
嵌入式linux/鸿蒙开发板(IMX6ULL)开发(三十六)GPIO和Pinctrl子系统的使用(下)
|
Linux 芯片
嵌入式linux/鸿蒙开发板(IMX6ULL)开发(三十六)GPIO和Pinctrl子系统的使用(上)
嵌入式linux/鸿蒙开发板(IMX6ULL)开发(三十六)GPIO和Pinctrl子系统的使用
239 0
嵌入式linux/鸿蒙开发板(IMX6ULL)开发(三十六)GPIO和Pinctrl子系统的使用(上)
|
Linux 开发工具 git
嵌入式linux/鸿蒙开发板(IMX6ULL)开发(三十二)LED模板驱动程序的改造:设备树
嵌入式linux/鸿蒙开发板(IMX6ULL)开发(三十二)LED模板驱动程序的改造:设备树
273 1
嵌入式linux/鸿蒙开发板(IMX6ULL)开发(三十二)LED模板驱动程序的改造:设备树