天天看点

Linux内核驱动开发-USB热插拔信息调取

前言:

        前段时间上科大嵌入式安卓开发溜了个作业,开发一个驱动,可以实现读取USB热插拔信息,程序调用显示USB设备名称和插拔时间。代码已经放在了我的Github上,供大家参考。

思路:

         USB热插拔的读取插拔信息项目应该是USB驱动层的很简单的一个应用。起初我想自己在网上寻找USB插拔信息如何调取,几乎没有什么案例。最终引导我的就是Linux内核网站中USB hotplugging的说明。简单看文档,这似乎就是我想用的东西,USB设备插入后进行识别,虽然要通过usb_device_id进行校验ID,但是只要我把ID范围设的很宽,任意USB设备都可以通过呢?尽管这是一种不完美的方法,但是总比没有路要好。又参考了USB Drive in Linux章节所给的案例,这似乎是难以实现的。usb_driver结构体似乎是针对某种USB设备进行驱动开发所用到的。被迫放弃了这条路。

        再考虑老师给的参考函数,注意到notifier_block结构体(内核通知链)似乎就是重点。初始化此结构体,设定.notifier_call函数地址,在函数中,用usb_device结构体指向dev地址。那么对于USB设备的变动通知就可以获取,这里除了老师给的,也参考了Notifier Function。到这里解决了信息如何获取的问题。

        依照作业要求,需要添加循环队列缓冲(ring buffer),环形队列实现很简单。图方便,我直接移植了suspend_monitor的部分表述方法。没有直接在suspend_monitor代码的基础上修改,是因为我发现,对于我的这个APP功能要求有很多冗余的地方,不考虑后期工程添加和革新,我需要的功能就只是环形队列和/proc文件交互应用。另外,不管是什么USB设备插拔,都只要放在一个队列中即可,通过一个简单的标志位来判断是插入还是拔出。

        通过字符设备驱动方法,让用户和驱动程序交互。这里主要参考了suspend_monitor,使用proc_create的方法,创建/proc/usb_monitor文件。考虑程序简易性,工程中只有读方法(.read),舍去了写方法(.write)。读函数中也参考了suspend_monitor中许多保护和进程阻塞优化的部分。到此,最终实现也只要在用户程序中读取/proc/usb_monitor即可。

        总的来说,理清思路后,工程很简单。

工程测试:

        实际工程测试,遇到很多有意思的问题。实际环境变化莫测,坑有很多,这也是需要完善的地方。

        测试设备有以下(以下顺序和图片从左到右一致):

        ST-Link,SanDisk U盘,Arduino UNO(板载USB转Serial芯片),有线鼠标 

Linux内核驱动开发-USB热插拔信息调取

前期测试遇到的问题:

        读取USB设备名称可以直接访问usb_device下的product参数。product的类型是char*,如果没有设备名称那么,product就会是一个NULL指针。这是不允许在我的字符串读取操作之中的。由于之前没有经验,没有考虑到这个问题,在几次测试中,直接导致我的驱动出错,系统死机。这样的USB设备我直接命名为NULL。

        这个设备就是Arduino UNO(板载USB转Serial芯片),一个很简单的单片机开发板。其他的USB测试设备没啥问题。

实验结果呈现(这里为了缩短篇幅,就放一个结果吧):

  1. 插拔ST-Link

    dmesg调试信息显示(### 开头)

Linux内核驱动开发-USB热插拔信息调取

         用户端读取,USB名称为STM32 STLink

Linux内核驱动开发-USB热插拔信息调取

工程代码:

        Github