编写Windows 的usb驱动程序教程Windows 是微软推出的功能强大的嵌入式操作系统,国内采用此操作系统的厂商已经很多了,本文就以windows 为例,简单介绍一下如何开发windows 下的USB驱动程序。
Windows 的USB系统软件分为两层: USB Client设备驱动程序和底层的Windows CE实现的函数层。
USB设备驱动程序主要负责利用系统提供的底层接口配置设备,和设备进行通讯。
底层的函数提本身又由两部分组成,通用串行总线驱动程序(USBD)模块和较低的主控制器驱动程序(HCD)模块。
HCD负责最最底层的处理,USBD模块实现较高的USBD函数接口。
USB设备驱动主要利用 USBD接口函数和他们的外围设备打交道。
USB设备驱动程序主要和USBD打交道,所以我们必须详细的了解USBD提供的函数。
主要的传输函数有:abourttransfer issuecontroltransferclosetransfer issuein te rruptransfergetisochresult issueisochtransfergettransferstatus istransfercompleteissuebulktransfer issuevendortransfer主要的用于打开和关闭usbd和usb设备之间的通信通道的函数有:abortpipetransfers closepipeisdefaultpipehalted ispipehaltedopenpipe resetdefaultpiperesetpipe相应的打包函数接口有:getframelength getframenumber releaseframelengthcontrolsetframelength takeframelengthcontrol取得设置设备配置函数:clearfeature setdescriptorgetdescriptor setfeaturegetinterface setinterfacegetstatus syncframe与usb进行交互的实现方法相关的多任务函数:findinterface registerclient device idgetdeviceinfo registerclientsettingsgetusbdversion registernotificationroutineloadgenericinterface driver translatestringdescropenclientregisterkey unregisternotificationroutine常见的Windows 下USB的设备驱动程序的编写有以下几种方法:●流式接口函数这种驱动程序主要呈现流式函数接口,主要输出XXX_Init,XXX_Deinit,XXX_Open,XXX_Close,XXX_Open,XXX_Close,XXX_Read,XXX_Write,XX X_Seek, XXX_IOControl,XXX_PowerUp,XXX_PowerDown等流式接口,注意上述的几个接口一定都要输出,另外XXX必须为三个字符,否则会出错。
但是此类的驱动程序不是通过设备管理接口来加载的,所以必须手工的调用RegisterDevice()和 DeregisterDevice()函数来加载和卸载驱动程序。
用户可以将此类的设备作为标准的文件来操作,只要调用相应的文件操作就可以和驱动程序打交道。
●使用现有的Window 的应用程序接口此类设备主要是利用Windows 中已经有了现成的函数接口,例如USB Mass Storage Disk,它主要利用现有的Windows 中已经有的可安装文件系统接口,呈现给系统可用的文件系统,对于用户来讲,它是透明的,用户仅仅感觉在操作一个文件夹。
●创建指定到特定的USBD的用户指定的API这种方法在USBD呈现设备时不需要任何限制,主要是特制的提供API给用户,一般不太常见。
USB设备驱动程序必须输出的函数有:● USBDeviecAttach当USB设备连接到计算机上时,USBD模块就会调用此函数,这个函数主要用于初始化USB设备,取得USB设备信息,配置USB设备,并且申请必需的资源。
● USBInstallDriver主要用于创建一个驱动程序加载所需的注册表信息,例如读写超时,设备名称等。
● USBUninstallDriver主要用于释放驱动程序所占用的资源,以及删除USBInstallDriver函数创建的注册表等。
上述的三个函数接口是所有的USB驱动程序必须提供的,缺一不可。
另外比较重要的是USB设备驱动程序的注册表配置,一般的USB设备驱动程序的注册表配置HKEY_LOCAL_MACHINE\Drivers\USB \LoadClients下,每个驱动程序的子键都有Group1_ID\Group2_ID\Group3_ID\Driver name格式,如果注册表信息与USB设备信息符合,USBD就会加载此驱动程序。
否则设备的子键应该由供应商,设备类和协议信息通过下划线组成。
例如你有个PDA设备,它具有一个USB接口,它的供应厂商ID假设为0x0888,设备ID 为0x0999,没有使用特殊的协议,那么它的加载注册表应该写为:[HKEY_LOCAL_MACHINE\Drivers\USB\LoadClients\2184_2457\Default\Default\PDA] "DLL"="pdausb.dll"需要注意的是注册表构成都是十进制数值来标识的,注意一下十进制和十六进制的转换。
有了这些基本信息,就可以编写USB设备了。
首先,必须输出USBD要求调用的三个函数,首先到设备插入到USB端口时,USBD会调用USBDeviceAttach()函数,相应的代码如下:extern c boolusbdeviceattach(usb_handlehdevice, // usb设备句柄lpcusb_funcslpusbfuncs, // usbdi的函数集合lpcusb_interfacelpinterface, // 设备接口描述信息lpcwstrszuniquedriverid, // 设备id描述字符串。
lpboolfacceptcontrol, // 返回true,标识我们可以控制此设备,反之表示不能控制dworddwunused){*facceptcontrol = false;// 我们的鼠标设备有特定的描述信息,要检测是否是我们的设备。
if (lpinterface == null)return false;// 打印相关的usb设备接口描述信息。
debugmsg(zone_init,(text(usbmouse: deviceattach, if %u, #ep:%u, class:%u, sub:%u,prot:%urn),lpinterface->descriptor.binterfacenumber,lpinterface->descriptor.bnumendpoints,lpinterface->descriptor.binterfaceclass,lpinterface->descriptor.binterfacesubcl ass,lpinterface->descriptor.binterfaceprotocol));// 初试数据usb鼠标类,产生一个接受usb鼠标数据的线程cmouse * pmouse = new cmouse(hdevice, lpusbfuncs, lpinterface);if (pmouse == null)return false;if (!pmouse->initialize()){delete pmouse;return false;}// 注册一个监控usb设备事件的回调函数,用于监控usb设备是否已经拔掉。
(*lpusbfuncs->lpregisternotificationroutine)(hdevice,usbdevicenotifications, pmouse);*facceptcontrol = true;return true;}第二个函数是 usbinstalldriver()函数,一些基本定义如下:constwchargcszregisterclientdriverid[] = lregisterclientdriverid;constwchargcszregisterclientsettings[] = lregisterclientsettings;constwchargcszunregisterclientdriverid[] = lunregisterclientdriverid;constwchargcszunregisterclientsettings[] = lunregisterclientsettings;constwchargcszmousedriverid[] = lgeneric_sample_mouse_driver;函数接口如下:extern c boolusbinstalldriver(lpcwstrszdriverlibfile) // @parm [in] - contains client driver dll name {bool fret = false;hinstancehinst = loadlibrary(lusbd.dll);// 注册usb设备信息if(hinst){lpregister_client_driver_idpregisterid = (lpregister_client_driver_id)getprocaddress(hinst, gcszregisterclientdriverid);lpregister_client_settingspregistersettings =(lpregister_client_settings) getprocaddress(hinst, gcszregisterclientsettings);if(pregisterid && pregistersettings){usb_driver_settingsdriversettings;driversettings.dwcount = sizeof(driversettings);// 设置我们的特定的信息。