欢迎光临散文网 会员登陆 & 注册

简单分析USB设备驱动框架(秒懂~)

2022-09-27 17:55 作者:补给站Linux内核  | 我要投稿

在生活、工作中经常会接触到USB设备,如鼠标、键盘、摄像头、可移动硬盘、扫码枪等。这些设备通过USB接口连接到电脑上后,电脑会立刻提示“检测到新硬件...”、安装驱动等。这里需要强调下USB设备使用的是USB总线,window或Linux内核中都会自带usb总线驱动,所以接上USB设备后,主机能够立刻检测到,提醒需要安装设备驱动是指安装USB设备驱动。

USB设备驱动使用USB总线,所以很多操作由USB总线驱动帮我们完成了,我们只需要的按照总线、设备、驱动框架来实现USB设备的驱动既可。USB设备数据的读写操作由总线驱动现在,我们可以直接使用总线读取到的数据,然后解析这些数据的含义、再进行相关的操作就可以了(这里需要注意的一点是USB总线驱动只提供USB设备的读写操作函数,这函数是通用的,即里面的数据的含义总线驱动并不知道)。

USB设备驱动的框架图下,具体的代码可以参考内核中的/drivers/hid/usbhid/usbmouse.c

分配/设置usb_driver结构体,填充里面的.id_table、.probe、.disconnect成员。 调用usb_register把usb_driver结构体注册到内核中。

struct usb_driver中的id_table成员是用与和usb设备进行匹配的选项,表示这个驱动支持的设备。


【文章福利】小编推荐自己的Linux内核技术交流群:【891587639】整理了一些个人觉得比较好的学习书籍、视频资料共享在群文件里面,有需要的可以自行添加哦!!!(含视频教程、电子书、实战项目及代码)     

.probe成员为函数指针,就是在设备和驱动匹配成功的时候执行。

.disconnect成员也为函数指针,在设备和驱动关联成功后再断开执行,如拔了USB设备或卸载USB设备驱动。

.probe函数中我们需要处理的事情如下(这里以鼠标为例子):

创建input_dev设备 设置input_dev支持的类,需要支持按键类、相对位移类。 设置input_dev支持的事件,能够产生左、中、右、以及侧边附加按键事件,还有xy方向上的相对位移事件和滚轮滑动事件。 注册input_dev到input输入子系统中。 硬件相关的操作,不同的设备的操作存在差异 USB总线为组从结构,USB总线驱动只能轮询去获取USB设备上的数据,USB设备不能主动通知USB主机传输数据。在USB驱动中需要构建urb(usb request block)结构体,然后填充使用。urb中要指定USB设备数据存放到主机上的物理地址以及虚拟地址,还有USB数据传输的方向、长度,和设备通信的端点等。

使用usb_alloc_urb()函数分配urb结构体,结束后使用usb_free_urb()释放这个结构体。

USB设备的数据要存放在主机上的什么地方,USB设备驱动中需要指明。

找到对应的设备端点和数据长度

现在数据传输的三要素(源、长度、目的)都确定了,剩下的就是要进行填充urb结构体,即告诉主机数据传输的三要素。

调用usb_fill_int_urb(),其中complete_fn相当于中断函数,即主机读取完数据会放到指定的内存data_dma中。然后通知CPU处理这些数据,这些数据只有USB设备驱动程序知道其含义。所以要在这个完成函数中处理这些数据,如上报。

最后就是提交usr请求块了。

到这里基本上就结束了,剩下的就是disconnect函数的操作。这个函数和.probe完全相反,申请了的资源需要在这里释放。

看到这里是不是感觉USB驱动很简单啊!框架确实很简单!很简单!很简单!重要的事情要说三遍,要相信你们的实力。

下面的代码是我在ARM板子上的针对usb鼠标写的。

测试如下图,按键和移动鼠标都能产生相应的事件码。这里/dev/event0的格式就不说了,要是不太清楚的可以参考input输入子系统。

usb驱动设备使用了input输入子系统框架,这个和之前的输入子系统(按键、触摸屏)之类的存在一点差异。之前的都是在中断服务函数中直接获取到数据然后调用input_event上报,而USB设备驱动中的数据来源是USB总线驱动,在完成函数中调用input_event上报数据。

事情就是这么个事情,情况就是这么个情况。

这就是usb设备驱动的简单框架,后面有空在把写操作(数据由主机发送到设备)的驱动模型以及各种传输类型的驱动更新下




简单分析USB设备驱动框架(秒懂~)的评论 (共 条)

分享到微博请遵守国家法律