WINCE驱动程序快速入门及经验点滴
在CE中,最简单的驱动程序莫过于一个内置(Built-in)设备的流接口驱动。对于一个不支持热拔插的设备,最方便的做法就是为其实现一个内置的流接口驱动。这种驱动只需要做以下工作:
1.实现一个动态库,其中实现以下函数:
DWORD xxx_Init( LPCTSTR pContext, LPCVOID lpvBusContext);
DWORD xxx_Deinit( DWORD hDeviceContext );
DWORD xxx_Open(DWORD hDeviceContext,DWORD dwAccess, DWORD dwShareMode);
DWORD xxx_Close( DWORD hDeviceContext );
void XXX_PowerUp( DWORD hDeviceContext );
void XXX_PowerDown(DWORD hDeviceContext );
DWORD xxx_IOControl(
DWORD hDeviceContext,
DWORD dwCode,
PBYTE pBufIn,
DWORD dwLenIn,
PBYTE pBufOut,
DWORD dwLenOut,
PDWORD pdwActualOut
);
2.在注册表中添加如下项目。(一般放在Platform.reg)
[HKEY_LOCAL_MACHINE/Drivers/BuiltIn/SampleDev]
"Prefix"="XXX"
"Dll"="MyDev.Dll"
"Order"=dword:1
3.在BIB文件中添加项目,将所用到的文件加入BIN文件(一般放在Platform.bib)。
MyDev.dll $(_FLATRELEASEDIR)/MyDev.dll NK SH
注:
SampleDev为任意与其它项目不重名的字符串.
每个函数名的前缀XXX可以是任意大写的字符串,只要保证与注册表中Prefix后面的值相同就行。
现在,已经知道了需要实现那些东西,那你一定急不可待,想知道如何去实现它。好了,一个最直接的方法,
4、在platform/your CPU’s folder/drivers 下新建一个目录,然后在drivers目录中的dirs文件中加入以你刚新建的目录名。
在刚新建的目录下,新建你的C源代码文件,在其中实现上面所述的函数,及其功能。新建名称分别为sources, makefile, mydev.def的文件。其内容如下:
makefile: 只需要这样一行
!INCLUDE $(_MAKEENVROOT)/makefile.def
mydriver.def文件定义需要输出的函数,这些函数能够被其它代码用动态加载的方法调用。格式:
LIBRARY MyDev(这个字符串要和将要生成的动态库的文件名一样)
EXPORTS
XXX_Init
XXX_Deinit
XXX_Open
XXX_Close
XXX_PowerOff
XXX_Power_Down
XXX_IOControl
Sources:这个文件很重要,内容也多,最基本的一个文件该有如下内容。
TARGETNAME=MyDev(指定要生成的动态库的名称)
TARGETTYPE=DYNLINK(指定要生成的是一个动态库)
(下面两项指定需要与哪些动态库链接,一般要第一项就足够了)
TARGETLIBS=$(_COMMONSDKROOT)/lib/$(_CPUINDPATH)/coredll.lib /
$(_COMMONOAKROOT)/lib/$(_CPUINDPATH)/ceddk.lib
DEFFILE=MyDev.def (指定def文件)
DLLENTRY=DllEntry(指定动态库的入口函数)
SOURCES=(请在这写上你所有源文件的名字,它们将会被编译)
源文档 <http://hi.baidu.com/nosoft008/blog/item/812a08355d111e1291ef397d.html>
WinCE下驱动开发入门记录(一)
2008年03月13日星期四 下午 09:22
这两天时间完全泡在CE的驱动开发中,学习学习,感觉就是资料不好找,难入门难上手,象我这样仅仅只有eVc4的更是没法调试没法跟踪,困难还是挺多的。学习了两天,现在感觉有那么点意思了,记录一下与大家分享。
首先说明一下,我可能仍然是个门外汉,因为以前基本没做过和硬件相关的东西,这方面知识缺乏的要命,现在公司要求做个驱动出来,也只有硬着头皮上了,学习研究了两天,基本掌握了一些有用的信息,所以认为自己入门了,但仅从自己的感觉出发都可以说我只是窥见了冰山之一角,还有很多很多都不懂。上次的帖子里面介绍了一些当时收集到的比较有用的资料,那个PB我也试着下了,下了一两天没多少,公司网太破,那个ftp又不支持断点续传,可害苦了我了,一个个的文件包100多M,一掉线就得重来,最后我干脆放弃了。那个弟兄有的,干脆打个包把代码发给我好了,谢谢了先。
好,怎们切入正题。首先介绍一下我的驱动目标,目的是为了使在pda上运行的应用程序能够通过USB口和我们这个外设通讯,可以发送指令给外设,也要求从外设获取数据,因此我把它定位在流接口上,这就引出第一个概念,流接口,应该说这里所说的流接口是Wince上驱动的一种,象串口啊这样的可以用CreateFile打开的都属于这个范畴。其关键在于1)实现xxx_系列的函数2)注册表中定义Prefix和Dll。其中xxx就是注册表中Prefix的值,比如串口就是“COM”。而注册表中的DLL就是你的驱动程序dll(wince下的驱动就是一个dll),加载驱动的时候,会到你的dll中去找xxx_系列的函数,所以你的dll一定要导出这些函数符号。
XXX_Init
XXX_Deinit
XXX_Open
XXX_Close
XXX_Read
XXX_Write
XXX_Seek
XXX_IOControl
XXX_PowerDown
XXX_PowerUp
经过测试,其中前六个是必须实现且导出的,否则是不能够成功加载的。
好,先介绍了一些关于流接口驱动的相关知识,这部分在网上还是能够找到不少资料的,我就不多说,回到我要开发的驱动上,说到底我这个还首先是个USB设备,被识别之后才能将它驱动成一个流设备。
说到USB驱动,就要先介绍一下USB驱动加载过程了。当usb设备接到主机(usb host,因此你的pda必须是能够作为usb host使用的)上时,系统就会根据它的信息去从注册表里查找它的驱动相关信息,在HKLM/Drivers/Usb/LoadClients下面会有一些主键Group1_ID/Group2_ID/Group3_ID/DeviceID,而DeviceID下面有一个字符串Dll=DriverFile.dll
注意,其中Group1_ID,Group2_ID,Group3_ID分别表示什么,以及其匹配的优先级别,可以在《WindowsCE 驱动开发指南》一书中USB驱动开发一章去详细研究。
如果找到匹配的注册表信息,系统就会加载DriverFile.dll,否则就会提示用户输入一个驱动名称。
那么加载dll的时候会有些什么动作呢?驱动程序DLL和普通的DLL是否具备不同的入口点呢?
先回答第二个问题,答案是否定的,其入口点和普通的dll没有区别。但是加载的过程就不那么简单了。你可以理解系统已经作了一些事情,使得你可以用一个普通的dll来作为驱动程序,但是显然,你必须实现系统所要求的接口函数。
对于USB驱动程序来说,有这么几个接口函数是必须实现且导出的:
BOOL USBDeviceAttach(USB_HANDLE hDevice,
LPCUSB_FUNCS lpUsbFuncs,
LPCUSB_INTERFACE lpInterface,
LPCWSTR szUniqueDriverId,
LPBOOL fAcceptControl,
LPCUSB_DRIVER_SETTINGS lpDriverSettings,
DWORD dwUnused);
BOOL USBInstallDriver(LPCWSTR szDriverLibFile);
BOOL USBUnInstallDriver();
建议大家先读一下sdk的include目录下的usbdi.h头文件,这里面定义了很多usb驱动相关的结构、函数接口,包括注释。
下班了,明天再写。 :P
源文档 <http://hi.baidu.com/zzaajj/blog/item/32a2a7507a4202581038c2f6.html>
WinCE下驱动开发入门记录(二)
2008年03月13日星期四 下午 09:23
昨天太忙,没来得及写,今天晚上火车要回武汉了,5.1估计没空写,这两天又有不少新发现想要些出来跟大家分享,但是一下子又理不清出头绪,还是不能着急,慢慢写,不要让列位看官越看越糊涂才好。
上一篇咱们写到了USB驱动必须实现的三个入口函数:USBInstallDriver,USBUnInstallDriver和USBDeviceAttach。这一篇就主要介绍一下这几个函数(及另外两个函数:ActivateDevice和USBDeviceNotificationCallback,有时间的话,后来发现没时间写这么长了Attach都写不完,只好下篇再写)。
其实网上搜索到的关于WinceUSB驱动开发的文章都有介绍这些函数,这些函数干什么用的,里面调用了那些东东都有说明,但是似乎天下文章一大抄的原则永远没有改变,每篇文章说的内容都差不多,还有些该说明的细节根本没有一篇提到过,根本就不是给新手入门看的,我想可能学习Wince驱动开发最大的疑惑就是哪些是我们该做的,哪些是不需要我们作的,我在学习的时候,看了这些所谓的入门文章,还是没有完全搞清楚,所以我才专门用一篇的篇幅把我研究所得写出来,可能会对新入门的朋友有所帮助。
先说USBInstallDriver,这个函数在驱动程序DLL被加载的时候会被调用,但是不是任何情况下加载驱动都会调用这个函数入口,前面提到过USB驱动的注册表键值,当系统能够根据注册表定位到驱动程序dll并且成功加载的话,这个函数就不会被调用了。反之,当不能够找到匹配的驱动或者不能够成功加载驱动的时候,系统会弹出一个对话框,让用户输入一个驱动程序名称,这个时候,系统就会加载用户输入的这个驱动程序文件,并调用其中的USBInstallDriver函数了。USBUnInstallDriver函数呢,我很迷惑,《WindowCE驱动开发指南》有一句话说WinCE永远不会调用它,我也不明白,但是就我测试的结果来看,确实没发现这个函数被调用过。
USBInstallDriver函数里面作什么的呢?说白了,就是写注册表,让系统下次能够通过注册表信息匹配到这个驱动程序文件。其他文章都说了,怎么写注册表,就是用USBD.dll中的RegisterClientDriverID和RegisterClientSettings两个函数,少不了LoadLibrary,GetProcAddress,FreeLibrary。网上看到过一个问题,问驱动程序不是被USBD进程加载的么?为什么不能直接用这个两个函数,还要LoadLibrary和GetProcAddress来调用这些函数呢?我不知道怎么去解答这个问题,只觉得即使在一个进程里面,似乎不这样你也得不到这两个函数的地址吧。至于到处都说USBInstallDriver里面不要用Reg的API函数去操作注册表,却没有个所以然,这个应该是因为这些注册表主键可能会根据操作系统的变更而变更的,而不论你是哪个操作系统,RegisterClientDriverID和RegisterClientSettings都会找到对应的正确的注册表主键去添加值,所以建议不要用regAPI来操作,换句话说你用了RegAPI去操作注册表,写入信息,也不会有什么问题,除非你的wince系统中那些驱动信息不应该写在那几个主键下了。
要注意的一点是:在RegisterClientSettings的参数中,给的USB_DRIVER_SETTINGS(内有9个ID)如果和你的设备的ID对不上,结果就是系统仍然不能够通过注册表信息加载你的驱动程序,所以,那个提示你输入驱动程序的对话框还会继续弹出来,但是USBInstallDriver成功返回的话,其中写入注册表的信息是成功写入了的(如果不成功,也会继续弹出那个对话框)。
在USBInstallDriver函数调用完之后,驱动程序dll会被释放掉,然后系统再读取注册表信息去找匹配的驱动来加载,所以才会出现上述情况。因此如果你写入的USB_DRIVER_SETTINGS是和你的设备匹配的,系统就会加载你的驱动,去继续干活了。
这次系统加载会干什么呢?会调用驱动DLL中的USBDeviceAttach入口函数。这个函数的学问就大啦,函数的声明如下:
BOOL USBDeviceAttach(USB_HANDLE hDevice, LPCUSB_FUNCS lpUsbFuncs,
LPCUSB_INTERFACE lpInterface, LPCWSTR szUniqueDriverId,
LPBOOL fAcceptControl,
LPCUSB_DRIVER_SETTINGS lpDriverSettings, DWORD dwUnused)
lpUsbFuncs是usb的一些函数接口,定义在USBDI.H头文件中,大家自己先看看,对照msdn看看。今天只取其中一个函数说一下:lpGetDeviceInfo
在USBDeviceAttach中写这么一行:
LPCUSB_DEVICE lpUsbDev = (lpUsbFuncs->lpGetDeviceInfo)(hDevice);
如果取出的lpUsbDev是NULL的话,那就说明该设备无法使用,咱们也不用继续折腾了,不为空的话,建议大家把这个lpUsbDev指向的那些数据对照msdn搞清楚其含义,这也有助于你理解usb规范中的一些东西。这个结构里面套结构,套的很深很深,而且我看MSDN2005和我的eVc4中的头文件中的定义有些地方有出入,大家自己研究一下,捉摸一下吧,结构就对照自己的头文件中的定义去探索,各成员的含义就对照MSDN去解读,完成了,差不多就进了一大步了。
马上要开会,所以今天就写到这里,大家也可以自己研究研究,然后和我交流,我只觉得一个人在这黑漆八乌地探索实在是......要是有个伴就好了~ :P有个老师就更爽了~~~
源文档 <http://hi.baidu.com/zzaajj/blog/item/4b8ccc263f94da138a82a1f7.html>
#define IOCTL_POWER_GET
/
CTL_CODE(FILE_DEVICE_POWER, 0x401, METHOD_BUFFERED, FILE_ANY_ACCESS)