我正在研究Linux设备驱动程序,我的主要关注点是wifi驱动程序。我想知道当我插入设备时代码如何流动。也许,我可以做一些事情,比如printk
在每个函数中添加一行。我拥有的设备受驱动程序支持ath9k_htc
。我想出于学习目的对驱动程序代码进行一些更改。
理解 Linux 中驱动程序模块的代码流程的正确或一般方法是什么?
答案1
当我想这样做时,我使用框架ftrace
。首先挂载特殊文件系统:
mount -t tracefs nodev /sys/kernel/tracing
(作为root;您应该成为所有这些的root,无论如何您都会以root身份做所有事情,并且拥有root shell比使用更容易sudo
)。
然后切换到该目录:
cd /sys/kernel/tracing
它包含一个README
提供简短摘要的基本内容。为了探索函数调用,我使用函数图追踪器,function_graph
在available_tracers
。例如,确定您感兴趣的功能ath9k_htc_tx
,并设置它们
echo ath9k_htc_tx > set_graph_function
您可以附加其他函数,请确保>>
在第一个函数之后使用。您可以使用以下命令查看配置的功能
cat set_graph_function
当您写入 时set_graph_function
,将根据正在运行的内核检查该函数;如果找不到该函数,写入将会失败,因此您会立即知道是否最终无法跟踪任何内容。
设置函数后,启用跟踪器:
echo function_graph > current_tracer
然后观看trace
文件。要再次禁用跟踪器,
echo nop > current_tracer
或者tracing_on
通过写入 0 或 1 来翻转(0 禁用跟踪,1 重新启用跟踪)。
答案2
主要要点是驱动程序将上部接口和下部接口连接在一起。在 的情况下ath9k_htc
,下层接口是 USB,上层接口是网络堆栈。
控制流很大程度上是一个状态机,它可以对来自两个接口的事件做出反应,而无需任何同步,例如,网络接口完全有可能通知驱动程序加入多播组,同时通知来自设备被弹出的USB子系统——在多处理器系统中,这些事件可以在不同的CPU上报告,然后驱动程序将同时进入。
大多数驱动程序没有进程或线程上下文,并且纯粹是事件驱动的,事件循环位于驱动程序外部,因此通常您会看到许多处理特定事件的小函数,尝试转发它们,如果失败则在某处进行记录,并立即返回。
在典型驱动程序中可视化控制流的最明智的方法是绘制共享可锁定资源的映射以及哪些函数访问它们,因为典型的通信线路是锁定列表、向其附加数据并解锁。如果您在一侧绘制与 USB 相关的功能,在另一侧绘制与网络相关的功能,那么应该会给您最清晰的图片。