一、关于Linux内核启动流程
参见文章《Linux内核启动流程笔记》。
二、关于数据结构
1. 双向循环链表
参见总结《Linux中List.h文件分析和应用》。
2. 哈希表
三、关于驱动程序的分析
基于4412-linux3.5平台,以I2C接口的触摸屏驱动为例子。
1. 找驱动程序源文件
触摸屏肯定属于输入子系统,所以在drivers\input\touchscreen目录下肯定能找到其驱动程序; 然后把触摸屏电源和地短接一下,串口终端就会打印什么ft5x06 err,所以断定drivers\input\touchscreen目录下下的ft5x06_ts.c文件为当前使用触摸屏的驱动程序。
2. 在Linux内核中找到对于配置项
在上面找到文件名的情况下, 终端中输入命令grep "ft5x06_ts" -R * 找到如下一行:
drivers/input/touchscreen/Makefile:obj-$(CONFIG_TOUCHSCREEN_FT5X0X) += ft5x06_ts.o
由此可见,当变量CONFIG_TOUCHSCREEN_FT5X0X为y或m时,ft5x06_ts文件会被编译。
在内核源码目录中执行make menuconfig,按”/“表示搜索。输入CONFIG_TOUCHSCREEN_FT5X0X,出现如下信息:
| Symbol: TOUCHSCREEN_FT5X0X_SINGLE [=n]
| Type : boolean
| Prompt: Disable MULTI-Touch Mode
| Defined at drivers/input/touchscreen/Kconfig:324
| Depends on: !S390 && !UML && INPUT [=y] && INPUT_TOUCHSCREEN [=y] && TOUCHSCREEN_FT5X0X [=y]
| Location:
| -> Device Drivers
| -> Input device support
| -> Generic input layer (needed for keyboard, mouse, ...) (INPUT [=y])
| -> Touchscreens (INPUT_TOUCHSCREEN [=y])
| -> FocalTech ft5x0x TouchScreen driver (TOUCHSCREEN_FT5X0X [=y])
从上述信息中可知,只要FocalTech ft5x0x TouchScreen driver选项被配置,相应Makefile中CONFIG_TOUCHSCREEN_FT5X0X变量的值就为y,ft5x06_ts.就会被编译近内核。上述信息中Defined at drivers/input/touchscreen/Kconfig:324 表示在Kconfig文件中定义的位置,一般在Kconfig中都是CONFIG TOUCHSCREEN_FT5X0X的字样。
注意,有时分析是上述流程的逆过程,也就是用配置选项CONFIG_TOUCHSCREEN_FT5X0X找到驱动源文件ft5x06_ts.c。
3. 驱动结构的分析
分析子系统源码,一般从入口函数开始分析。在ft5x06_ts.c源码文件中,由module_init(ft5x0x_ts_init);可知入口函数为ft5x0x_ts_init,在ft5x0x_ts_init函数中调用i2c_add_driver函数注册i2c_driver,对应的i2c_driver结构体为ft5x0x_ts_driver,在ft5x0x_ts_driver结构体id_table成员中name为ft5x0x_ts。
通过上面的分析,再结合bus-dev-drv模型,在bus总线的dev链表中必将找到对应的一个i2c_client结构(i2c_board_info的type成员值为ft5x0x_ts),所以在终端中输入命令:
grep "ft5x0x_ts" -R * 后,找到如下信息:
arch/arm/mach-exynos/mach-tiny4412.c: I2C_BOARD_INFO("ft5x0x_ts", (0x70 >> 1)),
从上述信息中可以知道在mach-tiny4412.c文件中肯定能找到dev(如果是I2c设备,就是i2c_client)的注册过程。通过内核文档可知,i2c_client的注册过程有4中方法,查看mach-tiny4412.c源码文件发现使用了第一中方法。
这种方法是线调用i2c_register_board_info函数把i2c_board_info结构体放入__i2c_board_list链表,后面在某个地方会调用i2c_register_adapter函数,此函数中会调用i2c_scan_static_board_info函数,此函数就会使用到__i2c_board_list链表,具体做法就是调用i2c_new_device函数把链表中的每个成员构造成一个i2c_client。
由此可见,这种方法必须在 i2c_register_adapter 之前 i2c_register_board_info,所以不适合动态加载insmod。如果要想动态加载,可以使用直接创建设备的方法,即直接i2c_new_device方法。不管哪种方法,最终都会调用i2c_driver结构体的成员函数probe,在里面进行设备驱动的设计,由于是触摸屏,将使用输入子系统。