iniwf

风是温柔的,雨是伤心的,云是快乐的,月是多情的,爱是迷失的,恋是醉人的,情是难忘的,天是长久的,地是永恒的

驱动开发之五 --- TDI之六 【译文】

转自http://hi.baidu.com/combojiang/blog/item/835622dcef3123a4cd1166c6.html

同样的使用TDI_RECEIVE来完成数据接收。然而我们却没有用它来实现。实际上,如果你注意到,你可以创建回调来通知你数据或者其他事件什么时候到达。这就是我们所做的。我实现了一个API包装函数来创建任意的事件句柄。如下:


NTSTATUS TdiFuncs_SetEventHandler(PFILE_OBJECT pfoTdiFileObject, 

            LONG InEventType, PVOID InEventHandler, PVOID InEventContext) 



    NTSTATUS NtStatus 
= STATUS_INSUFFICIENT_RESOURCES; 

    PIRP pIrp; 

    IO_STATUS_BLOCK IoStatusBlock 
= {0}

    PDEVICE_OBJECT pTdiDevice; 

    LARGE_INTEGER TimeOut 
= {0}

    UINT NumberOfSeconds 
= 60*3

    TDI_COMPLETION_CONTEXT TdiCompletionContext; 


    KeInitializeEvent(
&TdiCompletionContext.kCompleteEvent, 

                               NotificationEvent, FALSE); 


    
/* 

     * The TDI Device Object is required to send these 

     *                       requests to the TDI Driver. 

     
*/
 


    pTdiDevice 
= IoGetRelatedDeviceObject(pfoTdiFileObject); 

     

    
/* 

     * Step 1: Build the IRP. TDI defines several macros and functions 

     *         that can quickly create IRP's, etc. for variuos purposes.   

     *         While this can be done manually it's easiest to use the macros. 

     * 

     
*/
 

    pIrp 
= TdiBuildInternalDeviceControlIrp(TDI_SET_EVENT_HANDLER, 

            pTdiDevice, pfoConnection, 
&TdiCompletionContext.kCompleteEvent, 

            
&IoStatusBlock); 


    
if(pIrp) 

    


        
/* 

         * Step 2: Set the IRP Parameters 

         
*/
 


        TdiBuildSetEventHandler(pIrp, pTdiDevice, pfoTdiFileObject, 

                NULL, NULL, InEventType, InEventHandler, InEventContext); 


        NtStatus 
= IoCallDriver(pTdiDevice, pIrp); 


       
/* 

         * If the status returned is STATUS_PENDING this means that 

         * the IRP will not be completed synchronously and the driver has 

         * queued the IRP for later processing. This is fine but we do not 

         * want to return this thread, we are a synchronous call so we want 

         * to wait until it has completed. The EVENT that we provided 

         * will be set when the IRP completes. 

         
*/
 


        
if(NtStatus == STATUS_PENDING) 

        


            KeWaitForSingleObject(
&TdiCompletionContext.kCompleteEvent, 

                                    Executive, KernelMode, FALSE, NULL); 


            
/* 

             * Find the Status of the completed IRP 

             
*/
 

     

            NtStatus 
= IoStatusBlock.Status; 

        }
 


    }
 


    
return NtStatus; 

}
 



使用这个函数实现回调的代码如下:

 Collapse

NtStatus 
= TdiFuncs_SetEventHandler( 

                  pTdiExampleContext
->TdiHandle.pfoTransport, 

                  TDI_EVENT_RECEIVE, 

                  TdiExample_ClientEventReceive, 

                  (PVOID)pTdiExampleContext); 

   

 


NTSTATUS TdiExample_ClientEventReceive(PVOID TdiEventContext, 

                         CONNECTION_CONTEXT ConnectionContext, 

                         ULONG ReceiveFlags, 

                         ULONG BytesIndicated, 

                         ULONG BytesAvailable, 

                         ULONG 
*BytesTaken, 

                         PVOID Tsdu, 

                         PIRP 
*IoRequestPacket) 



    NTSTATUS NtStatus 
= STATUS_SUCCESS; 

    UINT uiDataRead 
= 0

    PTDI_EXAMPLE_CONTEXT pTdiExampleContext 
= 

                        (PTDI_EXAMPLE_CONTEXT)TdiEventContext; 

    PIRP pIrp; 


    DbgPrint(
"TdiExample_ClientEventReceive 0x%0x, %i, %i\n"

                  ReceiveFlags, BytesIndicated, BytesAvailable); 



    
*BytesTaken = BytesAvailable; 

     

    
/* 

     * This implementation is extremely simple. We do not queue 

     * data if we do not have an IRP to put it there. We also 

    * assume we always get the full data packet sent every recieve. 

     * These are Bells and Whistles that can easily be added to 

     * any implementation but would help to make the implementation 

     * more complex and harder to follow the underlying idea. Since 

     * those essentially are common-sense add ons they are ignored and 

     * the general implementation of how to Queue IRP's and 

     * recieve data are implemented. 

     * 

     
*/
 


    pIrp 
= HandleIrp_RemoveNextIrp(pTdiExampleContext->pReadIrpListHead); 


    
if(pIrp) 

    


        PIO_STACK_LOCATION pIoStackLocation 
= 

                              IoGetCurrentIrpStackLocation(pIrp); 


        uiDataRead 
= 

               BytesAvailable 
> pIoStackLocation->Parameters.Read.Length ? 

               pIoStackLocation
->Parameters.Read.Length : BytesAvailable; 


        pIrp
->Tail.Overlay.DriverContext[0= NULL; 


        RtlCopyMemory(pIrp
->AssociatedIrp.SystemBuffer, Tsdu, uiDataRead); 


        pIrp
->IoStatus.Status      = NtStatus; 

        pIrp
->IoStatus.Information = uiDataRead; 


        IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT); 

    }
 


    
/* 

     * The I/O Request can be used to recieve the rest of the data.   

     * We are not using it in this example however and will actually 

     * be assuming that we always get all the data. 

     * 

     
*/
 

    
*IoRequestPacket = NULL; 


    
return NtStatus; 

}
 

不要对HandleIrp_RemoveNextIrp产生恐惧,我们会在本篇后面部分讲怎样排队IRP请求。
 

posted on 2009-03-23 22:07 iniwf 阅读(471) 评论(0)  编辑 收藏 引用 所属分类: 驱动


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


导航

统计

常用链接

留言簿(2)

随笔分类

随笔档案

收藏夹

IT技术

积分与排名

最新评论

阅读排行榜

评论排行榜