winceUSB设备驱动开发详解

本文分享了作者一周内研究WinCE USB设备驱动的心得,包括USB协议的基础知识、USB描述符的理解及其与驱动程序的关系。文章重点介绍了USB驱动开发中的关键函数USBInstallDriver和USBDeviceAttach的作用及其实现细节。
 

研究了一个星期的winceUSB设备驱动开发,我主要是研究了两个源代码OV511的摄像头驱动和鼠标驱动;刚开始就是看天数似的,不过万事开头难,只要你砸进去没天都会又突破的,为了不让各位走弯路,我谈下我的学习感受和要注意的问题。1.首先要知道USB协议,这是最基本的,如果大家觉得复杂那就简单的看下http://www.juqingshow.com/jsjyuanli/200703/7893.html;2.要知道USB设备驱动开发的结构,具体我就不说了,网上很多;3.很关键的就是要弄清USB描述符,特别是一层层的关系,如一个USB设备有一个设备描述符,设备描述符里面决定了该设备有多少种配置,每种配置描述符对应着配置描述符;而在配置描述符中又定义了该配置里面有多少个接口,每个接口有对应的接口描述符;在接口描述符里面又定义了该接口有多少个端点,每个端点对应一个端点描述符;端点描述符定义了端点的大小,类型等等。由此我们可以看出,USB的描述符之间的关系是一层一层的,最上一层是设备描述符,下面是配置描述符,再下面是接口描述符,再下面是端点描述符。在获取描述符时,先获取设备描述符,然后再获取配置描述符,根据配置描述符中的配置集合长度,一次将配置描述符、接口描述符、端点描述符一起一次读回。其中可能还会有获取设备序列号,厂商字符串,产品字符串等。http://hi.baidu.com/angle3839/blog/item/1f4707fa39309f63024f564a.html这些明确后我们就可以开始看程序了,一般网上说得很多的就是除了驱动的标准接口函数外还有三个入口函数,其实网上搜索到的关于WinceUSB驱动开发的文章都有介绍这些函数,这些函数干什么用的,里面调用了那些东东都有说明,但是似乎天下文章一大抄的原则永远没有改变,每篇文章说的内容都差不多,还有些该说明的细节根本没有一篇提到过,根本就不是给新手入门看的,再次我结合自己的理解对这三个函数,希望对大家又帮助。入口点的设置是为了实现USB驱动程序和USBD之间的交互,我们在动态连接库中设置入口点。

设备插入后,系统在取得设备信息后将自动在注册表中寻找是否有这一项,如果没有,则出现提示输入设备名称对话框,输入设备名称后USBInstallDriver这个函数在驱动程序DLL被加载的时候会被调用,但不是任何情况下加载驱动都会调用这个函数入口,当系统能够根据注册表定位到驱动程序dll并且成功加载的话,这个函数就不会被调用了,但是我们一般都需要这个函数,因为怕注册表子键和设备信息不一样,有了这个函数后我们就能够正确的加载驱动了,其实这个函数的功能就是写注册表,为下次插入设备后能真确找到驱动。这函数里主要用到的就是RegisterClientDriverID和RegisterClientSettings函数注册,也少不了少不了LoadLibrary,GetProcAddress,FreeLibrary函数;提醒下:大家有没注意到USBInstallDriver的那个参数就是驱动的名称,也就是对话框要输入的设备驱动名称。也许大家问怎么用RegisterClientDriverID和RegisterClientSettings函数写注册表的,初次看过代码的人肯定有这样的疑问,其实很简单的就是用到了函数指针,是通过函数指针调用的。这两函数是USBD接口函数,已经都被下层实现了的,只要传参数就可以了。对于RegisterClientSettings的参数USB_DRIVER_SETTINGS的结构我就不讲了,是与注册表的子键相同的。

这样我们就把第一个要调用的函数讲清楚了,主要是写注册表,为下次插入设备自动定位到我们的驱动设备。接着就是调用第二个函数USBDeviceAttach()函数的基本定义如下:

USBDeviceAttach(
USB_HANDLE hDevice, // USB设备句柄
LPCUSB_FUNCS lpUsbFuncs, // USBDI的函数集合
LPCUSB_INTERFACE lpInterface, // 设备接口描述信息
LPCWSTR szUniqueDriverId, // 设备ID描述字符串。
LPBOOL fAcceptControl, // 返回TRUE,标识我们可以控制此设备,反之表示不能控制参数看起来还是比较清楚的,提醒下大家要注意的是这些参数的具体值怎么来(系统传来的),其实这个函数是个回调函数,我们填好后系统会自动调用。函数里面会有这样的语句LPCUSB_DEVICE lpDeviceInfo = (*m_lpUsbFuncs->lpGetDeviceInfo)(m_hDevice);很重要的,我们应该知道USB的0端点是控制端点,是默认的,只要找到驱动就可以开始主机和设备的控制传输,这样我们就得到设备描述符等描述符相关值。下面我们就可以保存我们的接口了,当我们要传输时就可以通过选择接口就可以找到端点,再就可打开管道了,就可以通信了。但是第二个函数里怎么实现驱动的加载呢?

ActiveDevice函数调用的时候,依据参数lpszDevKey找到驱动程序文件,在注册表的HKEY_LOCAL_MACHINE\Drivers\Active键中增加这个设备,并且将USB驱动程序的上下文指针放到这里(即该函数的第2个参数),并且指定一个索引(设备序号),将驱动程序加载到Device Manager的进程空间。这时Device Manager将发送一个新设备插入的消息,调用该流接口驱动的CAM_Init函数;
已经博主授权,源码转载自 https://pan.quark.cn/s/a4b39357ea24 QueueForMcu 基于单片机实现的队列功能模块,主要用于8位、16位、32位非运行RTOS的单片机应用,兼容大多数单片机平台。 开源代码:https://.com/xiaoxinpro/QueueForMcu 一、特性 动态创建队列对象 动态设置队列数据缓冲区 静态指定队列元素数据长度 采用值传递的方式保存队列数据 二、快速使用 三、配置说明 目前QueueForMcu只有一个静态配置项,具体如下: 在文件 中有一个宏定义 用于指定队列元素的数据长度,默认是 ,可以根据需要更改为其他数据类型。 四、数据结构 队列的数据结构为 用于保存队列的状态,源码如下: 其中 为配置项中自定义的数据类型。 五、创建队列 1、创建队列缓存 由于我们采用值传递的方式保存队列数据,因此我们在创建队列前要手动创建一个队列缓存区,用于存放队列数据。 以上代码即创建一个大小为 的队列缓存区。 2、创建队列结构 接下来使用 创建队列结构,用于保存队列的状态: 3、初始化队列 准备好队列缓存和队列结构后调用 函数来创建队列,该函数原型如下: 参数说明: 参考代码: 六、压入队列 1、单数据压入 将数据压入队列尾部使用 函数,该函数原型如下: 参数说明: 返回值说明: 该函数会返回一个 枚举数据类型,返回值会根据队列状态返回以下几个值: 参考代码: 2、多数据压入 若需要将多个数据(数组)压入队列可以使用 函数,原理上循环调用 函数来实现的,函数原型如下: 参数说明: 当数组长度大于队列剩余长度时,数组多余的数据将被忽略。 返回值说明: 该函数将返回实际被压入到队列中的数据长度。 当队列中的剩余长度富余...
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值