前言:
前段时间上科大嵌入式安卓开发溜了个作业,开发一个驱动,可以实现读取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芯片),有线鼠标
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAzNfRHLGZkRGZkRfJ3bs92YsYTMfVmepNHL61EVNVzZ610MNpHW4Z0MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnLzATNyATOzQTM1ADOwEjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
前期测试遇到的问题:
读取USB设备名称可以直接访问usb_device下的product参数。product的类型是char*,如果没有设备名称那么,product就会是一个NULL指针。这是不允许在我的字符串读取操作之中的。由于之前没有经验,没有考虑到这个问题,在几次测试中,直接导致我的驱动出错,系统死机。这样的USB设备我直接命名为NULL。
这个设备就是Arduino UNO(板载USB转Serial芯片),一个很简单的单片机开发板。其他的USB测试设备没啥问题。
实验结果呈现(这里为了缩短篇幅,就放一个结果吧):
- 插拔ST-Link
dmesg调试信息显示(### 开头)
用户端读取,USB名称为STM32 STLink
工程代码:
Github