sosojohn
论坛版主
论坛版主
  • 注册日期2006-01-29
  • 最后登录2021-06-25
  • 粉丝0
  • 关注1
  • 积分1047分
  • 威望535点
  • 贡献值1点
  • 好评度178点
  • 原创分0分
  • 专家分0分
  • 社区居民
阅读:2368回复:3

USB设备识别-草案

楼主#
更多 发布于:2007-01-19 13:12
在涉及USB设备或USB设备相关的项目开发中,难免会涉及到:
如何识别出插入的USB设备为自己而不是别的厂商?
插入多个USB设备,如何准确实现数据传输等问题。

本帖,以USB的设备识别为题,结合自己的VxClient,以伪代码的形式,和大家一同探索:USB的识别问题。由于水平有限,难免存有不足之处,望同行指正!

1。原理:
代码:总线驱动程序(DDK\Kernel\serenum)
书籍:WDM开发指南

2。流程:
(以伪代码为路线)
#include "VxClient.h"          // our device extension where

#pragma warning(error:4100)   // Unreferenced formal parameter
#pragma warning(error:4101)   // Unreferenced local variable

//
//  TAG identifying memory VxClient allocates
//
#define POOL_TAG   'fFtS'


#if WINVER == 0x0500

//
//  These macros are used to test, set and clear flags respectively
//

#ifndef FlagOn
#define FlagOn(_F,_SF)        ((_F) & (_SF))
#endif

#ifndef BooleanFlagOn
#define BooleanFlagOn(F,SF)   ((BOOLEAN)(((F) & (SF)) != 0))
#endif

#ifndef SetFlag
#define SetFlag(_F,_SF)       ((_F) |= (_SF))
#endif

#ifndef ClearFlag
#define ClearFlag(_F,_SF)     ((_F) &= ~(_SF))
#endif


#define RtlInitEmptyUnicodeString(_ucStr,_buf,_bufSize) \
    ((_ucStr)->Buffer = (_buf), \
     (_ucStr)->Length = 0, \
     (_ucStr)->MaximumLength = (USHORT)(_bufSize))


#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif

#ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b))
#endif

//
//  We want ASSERT defined as an expression, which was fixed after Windows 2000
//

#ifdef ASSERT
#undef ASSERT
#if DBG
#define ASSERT( exp ) \
    ((!(exp)) ? \
        (RtlAssert( #exp, __FILE__, __LINE__, NULL ),FALSE) : \
        TRUE)
#else
#define ASSERT( exp ) ((void) 0)
#endif
#endif        

#define ExFreePoolWithTag( a, b ) ExFreePool( (a) )

#endif /* WINVER == 0x0500 */


#define RtlInitEmptyUnicodeString(_ucStr,_buf,_bufSize) \
    ((_ucStr)->Buffer = (_buf), \
     (_ucStr)->Length = 0, \
     (_ucStr)->MaximumLength = (USHORT)(_bufSize))

#define IS_MY_DEVICE_OBJECT(_devObj) \
    (((_devObj) != NULL) && \
     ((_devObj)->DriverObject == gVxClientDriverObject) && \
      ((_devObj)->DeviceExtension != NULL))


#define IS_MY_CONTROL_DEVICE_OBJECT(_devObj) \
    (((_devObj) == gVxClientControlDeviceObject) ? \
            (ASSERT(((_devObj)->DriverObject == gVxClientDriverObject) && \
                    ((_devObj)->DeviceExtension == NULL)), TRUE) : \
            FALSE)


// 全局变量
UNICODE_STRING    GlobalRegistryPath;

//
//  Holds pointer to the driver object for this driver
//

PDRIVER_OBJECT  gVxClientDriverObject = NULL;

//
//  Holds pointer to the device object that represents this driver and is used
//  by external programs to access this driver.  This is also known as the
//  "control device object".
//

PDEVICE_OBJECT    gVxClientControlDeviceObject = NULL;


FAST_MUTEX        gVxClientAttachLock;

#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, DriverEntry)

#if DBG && WINVER >= 0x0501
#pragma alloc_text(PAGE, DriverUnload)
#endif

#pragma alloc_text(PAGE, VxClientCreate)
#pragma alloc_text(PAGE, VxClientClose)
#pragma alloc_text(PAGE, VxClientWrite)
#pragma alloc_text(PAGE, VxClientRead)
#pragma alloc_text(PAGE, VxClientDeviceIoControl)

#endif

extern "C"
NTSTATUS
DriverEntry(
    IN    PDRIVER_OBJECT    DriverObject,
    IN    PUNICODE_STRING    RegistryPath
    )
{
    NTSTATUS    status = STATUS_SUCCESS;

    USHORT        regPathLen;
    ULONG            ulIndex;

    regPathLen = RegistryPath->Length;
    GlobalRegistryPath.MaximumLength = regPathLen + sizeof(UNICODE_NULL);
    GlobalRegistryPath.Lenth = regPathLen;
    GlobalRegistryPath.Buffer = ExAllocatePoolWithTag(
                                        PagedPoll,
                                        GlobalRegistryPath.MaximumLength,
                                        POOL_TAG
                                        );
    if (GlobalRegistryPath.Buffer == NULL)
  {
        KdPrint(("Couldn't allocate pool for registry path!\n"));
        return STATUS_INSUFFICIENT_RESOURCES;
   }

    RtlCopyUnicodeString(&GlobalRegistryPath, RegistryPath);//GlobalRegistryPath

  
  //保存我们的驱动对象,及设置UNLOAD例程
    gVxClientDriverObject = DriverObject;

#if    DBG
    KdPrint(("VxClient Checked!");
    gVxClientDriverObject->DriverUnload = DriverUnload;
else
    KdPrint(("VxClient Checked!");
#endif


#define SYS_DEVICE_NAME "\\Device\\VxClient"
#define DOS_DEVICE_NAME "\\??\\VxClient"

    UNICODE_STRING nameString, linkName;
    RtlInitUnicodeString( &nameString, SYS_DEVICE_NAME);
    RtlInitUnicodeString( &linkName, DOS_DEVICE_NAME);

    status = IoCreateDevice( DriverObject,
                             0,                      //has no device extension
                             &nameString,
                                                          FILE_DEVICE_UNKNOWN,
                             FILE_DEVICE_SECURE_OPEN,
                             FALSE,
                             &gVxClientControlDeviceObject);      
    if (!NT_SUCCESS( status ))
    {
        KdPrint(( "VxClient!DriverEntry: Error creating control device object \"%wZ\", status=%08x\n", &nameString, status ));
        return status;
    }
    
    KdPrint(("Creating symbolic link");
  status = IoCreateSymbolicLink( &linkString, &nameString );
  if (!NT_SUCCESS(status))
    {
        IoDeleteSymbolicLink( &linkString );
        status = IoCreateSymbolicLink( &linkString, &nameString );
        if (!NT_SUCCESS(status))
        {
            IoDeleteDevice(gVxClientControlDeviceObject);
            KdPrint(( "VxClient!DriverEntry: Error creating Symbolic Link status=%08x\n",status ));
            return status;
        }
    }
    /*分发例程暂时不处理
    DriverObject->MajorFunction[IRP_MJ_CREATE]= VxClientCreate;
    DriverObject->MajorFunction[IRP_MJ_CLOSE]    = VxClientClose;
    DriverObject->MajorFunction[IRP_MJ_WRTIE]    = VxClientWrite;
    DriverObject->MajorFunction[IRP_MJ_READ]    = VxClientRead;
    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = VxClientDeviceIoControl;
    */
    status = RegisterForPnpNotification(DriverObject);
    if (!NT_SUCCESS(status))
    {
        KdPrint(( "VxClient!DriverEntry: Error registering Pnp change notification, status=%08x\n", status ));
        IoDeleteDevice(gVxClientDriverObject);
        return status;
    }
    //做些初始化工作....有待整理
  ClearFlag( gVxClientControlDeviceObject->Flags, DO_DEVICE_INITIALIZING );
    KdPrint(("VxClient!DriverEntry:Completed!!"));
    return status;
}

NTSTATUS
RegisterForPnpNotification(
    IN    PDRIVER_OBJECT DriverObject
    )
{
    PAGED_CODE();
    KdPrint(("RegisterForPnpNotification"));
    NTSTATUS status = IoRegisterPlugPlayNotification( EventCategoryDeviceInterfaceChange,
        PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
        (PVOID)&GUID_CLASS_INPUT, DriverObject,
        PnpDicnCallback, DriverObject,//注册PnpInterfaceChangeEvent回调函数
        &diNotificationEntry);
    return status;
}

NTSTATUS
PnpDicnCallback(
    IN    PVOID    NotificationStructure,
    IN    PVOID    Context
    )
{
    PAGED_CODE();
    PDRIVER_INTERFACE_CHANGE_NOTIFICATION dicn = (PDRIVER_INTERFACE_CHANGE_NOTIFICATION)NotificationStructure;
    PDRIVER_OBJECT DriverObject = (PDRIVER_OBJECT)Context;

    if(IsEqualGUID(dicn->Event, GUID_DEVICE_INTERFFACE_ARRIVAL))    //analyse and deal with dicn
    {
        KdPrint(("new Device arrvial : dicn->SymbolicLinkNam\"%wZ\"",&dicn->SymbolicLinkName));
        CreateDevice(DriverObject,dicn->SymbolicLinkName);
    }
    else if(IsEqualGUID(dicn->Event, GUID->DEVICE_INTERFACE_REMOVAL))
    {
        KdPrint(("new Device removal : dicn->SymbolicLinkName\"%wZ\"",&dicn->SymbolicLinkName));
        DeleteDevice(DriverObject,dicn->SymbolicLinkName);
    }
    return STATUS_SUCCESS;
}

void
CreateDevice(
    IN    PDRIVER_OBJECT    DriverObject,
    IN    PUNICODE_STRING    HidSymLinkName
    )
{

    PFILE_OBJECT    HidFileObject = NULL;
    PDEVICE_OBJECT    HidDevice;
    PDEVICE_OBJECT    newHidDeviceObject;

    PAGED_CODE();

    NTSTATUS status = IoGetDeviceObjectPointer( HidSymLinkName, FILE_ALL_ACCESS,
        &HidFileObject, &HidDevice);
    if(!NT_SUCCESS(status))
    {
        KdPrint(("IoGetDeviceObjectPointer failed!"));
        return;
    }
    ObDereference(HidFileObject):

    PHIDP_PREPARSED_DATA HidPreparsedData = NULL;
    USHORT    HidInputReportLen,HidOutputLen;
    if(!GetCapabilities(HidDevice,HidPreparsedData,HidInputReportLen,HidOutputReportLen))
    {    
        KdPrint(("GetCapabilites failed!"));
        ExFreePool(HidPreparsedData);
        return;
    }
    //got capabilities of the hid_device

    PWSTR HidSymLinkNameBuffer = (PWSTR)ExAllocatePool( NonPagedPool,HidSymLinkName->MaximumLength);
    if( HidSymLinkNameBuffer==NULL)
    {
        ExFreePool(HidPreparsedData);
        return;
    }

    status = ObReferenceObjectByPointer(HidDevice, FILE_ALL_ACCESS, NULL, KernelMode);
    if(!NT_SUCCESS(status))
    {
        KdPrint(("ObReferenceObjectByPointer failed"));
        ExFreePool(HidSymLinkNameBuffer);
        ExFreePool(HidPreparsedData);
        return;
    }

  status = IoCreateDevice( DriverObject,
                             sizeof( HIDVX_DEVICE_EXTENSION ),
                             NULL,                          
                                                          FILE_DEVICE_UNKNOWN,//DeviceType,
                             0,
                             FALSE,
                             &newHidDeviceObject );
  //newDeviceObject 存放在HIDX_DEVICE_EXTENSION中
    //HIDX_DEVICE_EXTENSION 说明:CDO与DO都使用这个结构,目的就是形成一个链表,这样,我们就可以通过
    //CDO(父)来操作DO(子)
    
  if (!NT_SUCCESS( status ))
    {
        IoDeleteDevice(newHidDeviceObject);
        ExFreePool(HidSymLinkNameBuffer);
        ExFreePool(HidPreparsedData);
        ObDereferenceObject(HidDevice);
    return status;
  }

    //基本设置
    PHIDVX_DEVICE_EXTENSION devExt = (PHIDVX_DEVICE_EXTENSION)newHidDeviceObject->DeviceExtension;
    devExt->HidDevice = HidDevice;
    devExt->HidPreparsedData = HidPreparsedData;
    devExt->HidInputReportLen = HidInputReportLen;
    devExt->HidOutputReportLen = HidOutputReportLen;
    devExt->HidMaxReportLen = 0;
    devExt->HidIrp = NULL;
    devExt->HidReport = NULL;
    devExt->HidReportMdl = NULL;

    devExt->HidSymLinkName.Length = 0;
    devExt->HidSymLinkName.MaximumLength = HidSymLinkName->MaximumLength;
    devExt->HidSymLinkName.Buffer = HidSymLinkNameBuffer;
    RtlCopyUnicodeString( &devExt->HidSymLinkName, HidSymLinkName);

    newHidDeviceObject->Flags |= DO_BUFFERED_IO;
    
    //由于采用不AttachTo的方式,所以自己设定StackSize的大小
    newHidDeviceObject->StackSize = HidDevice->StackSize + 1;
    //OK后,清除DO_DEVICE_INITIALIZING标志,表明设备已经准备好了。可以使用了
    newHidDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
    KdPrint(("Child Device created OK"));
}
alpha315
驱动牛犊
驱动牛犊
  • 注册日期2008-07-24
  • 最后登录2009-04-02
  • 粉丝0
  • 关注0
  • 积分11分
  • 威望64点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2009-03-30 15:19
多谢楼主,对我帮助很大。
alpha315
驱动牛犊
驱动牛犊
  • 注册日期2008-07-24
  • 最后登录2009-04-02
  • 粉丝0
  • 关注0
  • 积分11分
  • 威望64点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2009-03-30 12:58
已解决
wanted999
驱动牛犊
驱动牛犊
  • 注册日期2006-03-28
  • 最后登录2012-08-13
  • 粉丝0
  • 关注0
  • 积分519分
  • 威望429点
  • 贡献值0点
  • 好评度48点
  • 原创分0分
  • 专家分0分
地板#
发布于:2007-05-30 09:41
谢谢指教!
游客

返回顶部