之前公司由于项目需要让我研究PDA上的WinCE系统下的USB外设驱动开发,刚刚有点入门的感觉结果又终止了这个计划,我也一直在郁闷这个事情,不想现如今,机会又来了。我又开始了驱动开发的研究学习之旅,这里将继续记录我的心得体会。
之前的入门记录(二)已经讲到了USBDeviceAttach函数,原形这里再列一下:
BOOL USBDeviceAttach(USB_HANDLE hDevice, LPCUSB_FUNCS lpUsbFuncs,
LPCUSB_INTERFACE lpInterface, LPCWSTR szUniqueDriverId,
LPBOOL fAcceptControl,
LPCUSB_DRIVER_SETTINGS lpDriverSettings, DWORD dwUnused);
不过(二)只谈到了它的第一个参数hDevice,调用一句: LPCUSB_DEVICE lpUsbDev = (lpUsbFuncs->lpGetDeviceInfo)(hDevice);
就能够获得一个USB_DEVICE的指针,然后顺藤摸瓜可以看到这个设备的许多信息,被命名为Descriptor的,PC上有一个软件叫USBView的可以看到接到USB口上的设备信息,读取的应该就是这个结构。我当时傻乎乎的,自己写打印函数,在驱动程序加载的时候把这些信息MessageBox显示出来:P,所以呢,今天这篇先讨论一下关于这个驱动的调试问题。在MSDN上有关于wince驱动程序调试的专题,大体是介绍使用PB开发驱动的情况下测试、调试驱动程序的,而我是用EVC4开发的,没有那个什么(名字忘记了:P),没法调试。当研究一些驱动的源代码的时候,最开始看到的那些 DEBUGMSG、DEBUGZONE还有个叫什么什么tail的那些宏,其实都是在PB的调试环境下用的, 功能应该是类似TRACE之类的,打印一些信息到Output窗口的,因为没有那个调试环境,所以这些东东都没法用了,因此要看我的驱动加载过程中的一些信息,要么就是打印到文件,要么就是用MessageBox了,我选择用MessageBox直观的显示,呵呵,笨笨的办法还是很好用的,跟设断点似的。
下面继续说USBDeviceAttach函数,其第二个参数lpUsbFuncs,这个是一个函数指针数组,有点vtable的味道,具体的看看USB_FUNCS这个结构的声明就差不多了,在MSDN中也能够通过这个结构查看其所有指向的函数的调用方法及用途。在驱动程序中,往往要用到这个vtable中的很多函数,所以我们需要把这个vtable保存下来备用,如何保存和备用我会在下篇中写明白,在Attach过程中还需要保存很多有用的东东。
那么继续往下,lpInterface,一个指向USB_INTERFACE的指针,我一直对这个参数没太弄明白,我在这个函数里面得到的这个指针是一个空指针,而看别人的代码中间,当这个指针为空的时候attach是返回FALSE的,显然对我这种情况是不适用的,我后来想想,觉得大概是因为我的外设Interface的class、subclass、protocol都是0,所以才出现这种情况吧(准确的说是因为我在USBInstallDriver函数中,RegisterClientDriverID调用给的参数USB_DRIVER_SETTINGS结构体中关于Interface的几个变量值我全给的USB_NO_INFO,我后来尝试赋值为0,结果就得到了非空的Interface指针)。那么对于我这种情况,interface是个空指针该怎么办呢?可以用USB_FUNCS中的lpFindInterface来“找出”合适的Interface指针,具体的用法还是看官自己研究MSDN吧。
其实猛地一下蹦出一个Interface的概念,估计初次接触的都会有点糊涂,我当时也很糊涂,Interface在现如今含义太多了,不过可以肯定这里的不是COM中的Interface~:),在查阅资料的时候,我找到了它的确切定义:
USB peripheral devices consist of one or more logical components that implement the abilities of the devices. These components are called interfaces.Each interface typically provides some useful grouping of functionality, but exactly what constitutes an interface is an implementation detail. For example, a USB mouse device could present one interface for horizontal and vertical movement information and a separate interface for left and right button information. As another option, the device could present a single interface containing all of the information. Both are valid approaches, but each approach has implications for how the device driver must operate.
这段话我就不翻译了,本来英文就不怎么地,翻译过来有误导之嫌,还是留给大家原汁原味的比较好。
其实研究wince的驱动,或者单纯的讲USB驱动,还是应该了解一下wince下USB的驱动模型的,貌似很简单的一个模型,但是好像还没有能够找到比较精辟的阐述讲解,看着MSDN能够让你看睡着了也不知所云,只能是边研究边体会,我很想在我的文章里对这个模型进行一番讲解,但是发现自己也没有理解到能够给别人讲解的地步。
好了,不废话了,继续就Interface这个指针继续往下谈,我看了PB下的USB Printer的驱动源码,在这个阶段它调用了SetInterface这个函数,我也依葫芦画瓢,调用了,但却阻塞在这个调用上不能继续,至今我仍不知道是什么原因。这也可以说是我目前的疑问点之一,文中我用特殊颜色标记出来,有朋友能够解疑释惑的可以和我联系,我自己研究出来了,以后也会在后记中加上其答案。
其它的似乎就没有太多好说的了,直接在MSDN中间都能够看懂是干什么,今天就先写到这里,下次再写的内容就和我的外设有很直接的关系了,只能是根据我外设的具体情况介绍我探索驱动开发的经历。我的外设还算比较简单的,只有两个BULK的EndPoint,什么是EndPoint?呵呵~~留给看官自己研究下吧~
BTW:经过几天的摸索,我终于完成了我的外设的驱动开发,看着测试程序成功的打开设备,写数据又读数据,心中无比欣慰~~不过由于写程序的时候是摸着石头过河,而且到后来才如愿以偿的看到了PB下USBPrinter的源代码,才发现自己的程序结果实在有点混乱。这两天再调整调整,USBPrinter的源代码中果然还是有不少可以借鉴的东西。
2007.8.6后记:“好”日子差不多又要到头了,这次驱动开发的成果在我看来才只是刚刚可用而已,已经调配我做别的事情了,这方面的研究又要被停止下来了。之后一段时间估计很难抽出时间自己继续深入研究了,回头看看自己写的东西居然没有介绍LPBOOL fAcceptControl这个参数,不过好在介绍这个参数的文章也比较多,简单来说,它是一个输出参数。当把它指向的那个变量赋值为真的时候,我们的设备驱动程序就取得了设备的控制权了,系统也就不会再继续为之寻找匹配的驱动了(我的理解是这样,不知是否有错误)。这里小小的后记补充一下。入门记录(四)可能会在更晚的时候,抽时间纪录下来,希望到时我还记得我要写些什么~:)