windows USB读卡器驱动详解

本文档详细介绍了在Windows 2000及更高版本操作系统中开发USB读卡器驱动的过程,包括初始化请求、配置设备、批量传输管理、错误恢复、中断管道管理以及与用户程序交互的步骤。开发涉及读取设备描述符、选择配置、创建URB请求、读取配置描述符、选择接口和端点等操作。此外,还讨论了如何处理中断管道和批量传输的错误,以及如何设计驱动程序接口供上层应用程序调用。
摘要由CSDN通过智能技术生成

目标

windows 2000及以上版本的操作系统中,开发usb读卡器驱动。实现数据批量传输功能,同时需要根据特定的协议(协议可自定义)进行通信。实现一个基于此usb驱动的动态库(统一接口),供上层应用程序调用。

具体功能包括:查询IC卡类型、读扇区数据、写扇区数据、删除IC卡数据、USB热插拔。

开发环境

操作系统:windows xp

开发软件:DDKdriverStudio

调试工具:Ellisys USB分析仪,Debug view, irptrace, driverMonitor, SymLinks

基本技能

熟悉usb2.0协议,熟悉windows下驱动开发流程(包括windows驱动调试技术、内存管理、驱动程序的同步、IRP、分层驱动模型、设备的即插即用等)。

与传统PC总线(PCI总线)设备的驱动程序相比,USB设备驱动程序从不直接与硬件对话。相反,它仅靠创建URB(USB请求块)并把URB提交到总线驱动程序就可完成硬件操作。

可以把USBD.SYS看作是接受URB的实体,向USBD的调用被转化为带有主功能代码为IRP_MJ_INTERNAL_DEVICE_CONTROLIRP。然后USBD再调度总线时间,发出URB中指定的操作。

初始化请求

为了创建一个URB,你首先应该为URB分配内存,然后调用初始化例程把URB结构中的各个域填入请求要求的内容,例如,当你为响应IRP_START_DEVICE请求而配置设备时,首要的任务就是读取该设备的设备描述符。下面代码片段可以完成这个任务:

USB_DEVICE_DESCRIPTOR dd;

URB urb;

UsbBuildGetDescriptorRequest(&urb,

                         sizeof(_URB_CONTROL_DESCRIPTOR_REQUEST),

                         USB_DEVICE_DESCRIPTOR_TYPE,

                         0,

                         0,

                            &dd,

                         NULL,

                         sizeof(dd),

                         NULL);

我们首先声明一个局部变量urb来保存URB数据结构。URBUSBDI.H中声明,是一个多子结构的联合,我们将使用UrbControlDescriptorRequest子结构,它的类型是_URB_CONTROL_DESCRIPTOR_REQUEST。使用自动变量当然是可以的,但你事先必须了解系统堆栈上是否有足够的空间装下最大的URB,并且在这个URB被完成前,你不能离开当前函数,否则自动变量将被释放。

当然,你还可以在系统堆上为URB动态地分配内存:

PURB urb = (PURB) ExAllocatePool(NonPagedPool,  sizeof(_URB_CONTROL_DESCRIPTOR_REQUEST));

if (!urb)

      return  STATUS_INSUFFICIENT_RESOURCES;

UsbBuildGetDescriptorRequest(urb, ...);

...

ExFreePool(urb);

UsbBuildGetDescriptorRequest看上去象一个正常的服务例程,实际上它是一个宏(USBDLIB.H中声明),用于生成读描述符请求子结构各个域的初始化语句。在DDK头文件中定义了这些创建各种URB的宏,见表1。因为它们是预处理宏,所以在它们的参数中应避免使用有侧效的表达式。

1用于创建URB的辅助宏

辅助宏

事务类型

UsbBuildInterruptOrBulkTransferRequest

对中断或批量端点的输入和输出

UsbBuildGetDescriptorRequest

端点0GET_DESCRIPTOR控制请求

UsbBuildGetStatusRequest

对设备、接口、端点的GET_STATUS请求

UsbBuildFeatureRequest

对设备、接口、端点的SET_FEATURECLEAR_FEATURE请求

UsbBuildSelectConfigurationRequest

SET_CONFIGURATION

UsbBuildSelectInterfaceRequest

SET_INTERFACE

UsbBuildVendorRequest

任何厂商定义的控制请求

在前面的代码片段中,我们指定把设备描述符信息接收到一个局部变量(dd)中,其地址和长度我们在参数中都提供了。涉及到数据传输的URB可以指定两种方式的非分页数据缓冲区。你可以象上面代码那样指定缓冲区的虚拟地址和长度。另一种方法是提供一个内存描述符列表(MDL),但事先必须调用MmProbeAndLockPages函数对这个MDL进行探测并锁定(probe-and-lock)

发送URB

创建完URB后,你需要创建并发送一个内部I/O控制(IOCTL)请求到USBD驱动程序,USBD驱动程序位于驱动程序层次结构的低端。在大多数情况下,你需要等待设备回应,可以使用下面辅助函数:

NTSTATUS usb_icSubmitUrbSynch(

    IN  PUSB_IC_DEVICE_EXTENSION   DeviceExtension,

    IN  PURB                        Urb

    )

{

     NTSTATUS            status;

     PIRP                irp;

     IO_STATUS_BLOCK     ioStatus;

     KEVENT              event;               

     PIO_STACK_LOCATION  irpStack;

 

     usb_icDebugPrint(DBG_IO, DBG_INFO, __FUNCTION__"++");

 

     KeInitializeEvent(&event, NotificationEvent, FALSE);    ß 1

 

    irp =  IoBuildDeviceIoControlRequest(                  ß 2

             IOCTL_INTERNAL_USB_SUBMIT_URB,

             DeviceExtension->LowerDeviceObject,

             NULL,

             0,

             NULL,

             0,

            TRUE,

             &event,

             &ioStatus

             );

 

    if (irp  != NULL)

    {

         irpStack = IoGetNextIrpStackLocation(irp);                   

         irpStack->Parameters.Others.Argument1 = Urb;                 ß 3

 

         status = IoCallDriver(DeviceExtension->LowerDeviceObject, irp);  ß 4

        if  (status == STATUS_PENDING)

        {

             KeWaitForSingleObject(

                 &event,

                 Executive,

                 KernelMode,

                 FALSE,

                 NULL

                 );

            

             status = ioStatus.Status;   

        }

    }

    else

    {

         status = STATUS_INSUFFICIENT_RESOURCES;

    }

 

     usb_icDebugPrint(DBG_IO, DBG_INFO, __FUNCTION__"--. STATUS  %x", status);

 

    return  status;

}

1.  我们将等待URB完成,所以我们必须先创建一个内核事件对象。

2. 创建内部IOCTL请求最简单的的方法是调用IoBuildDeviceIoControlRequest函数,第一个参数(IOCTL_INTERNAL_USB_SUBMIT_URB)指出I/O控制代码。第二个参数(DeviceExtension->LowerDeviceObject)指定接收请求的设备对象;IoBuildDeviceIoControlRequest使用这个指针来决定需要接收多少个堆栈单元。接下来的四个参数描述输入输出缓冲区,提交这种URB并不需要这些信息,所以例子中将它们置成NULL0值。第七个参数为TRUE,它指出我们创建的是IRP_MJ_INTERNAL_DEVICE_CONTROL请求而不是IRP_MJ_DEVICE_CONTROL请求。最后两个参数指出等待URB完成的事件和一个接收该操作最终状态的结构IO_STATUS_BLOCK

3.  被提交的URB的地址被填入Parameters.OthersArgument1域。对于普通的IOCTL请求,该偏移对应OutputBufferLength域。

4.  我们用IoCallDriver把请求发送到下一层驱动程序。USBD将处理该URB请求并完成,然后I/O管理器将那个IRP删除并置事件信号。由于我们没有提供自己的完成例程,所以不能确定I/O管理器在所有可能的完成情况下都置事件信号。我们仅当低级派遣例程返回STATUS_PENDING时才等待那个事件。

配置

USB

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值