Linux学习笔记--insmod 命令
命令作用
insmod ap3216c_drv.ko
是Linux内核模块加载命令,用于将编译好的AP3216C传感器驱动模块插入到运行中的内核。
详细执行流程
阶段1:用户空间执行命令
insmod ap3216c_drv.ko
阶段2:内核模块加载
// 内核调用模块初始化函数
static int __init i2c_driver_ap3216c_init(void)
{printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);return i2c_add_driver(&i2c_ap3216c_driver);
}
执行步骤:
内核解析
.ko
文件格式分配模块需要的内存空间
执行模块的初始化函数
i2c_driver_ap3216c_init()
阶段3:注册I2C驱动
i2c_add_driver(&i2c_ap3216c_driver);
内核内部操作:
将
i2c_ap3216c_driver
添加到内核的I2C驱动链表遍历所有已注册的I2C适配器(总线)
在每个适配器上查找匹配的设备
阶段4:设备匹配过程
内核检查两种匹配方式:
方式1:设备树匹配
static const struct of_device_id of_match_ids_ap3216c[] = {{ .compatible = "lite-on,ap3216c", .data = NULL },{ /* END OF LIST */ },
};
匹配流程:
# 检查设备树中是否有兼容节点
/sys/firmware/devicetree/base/... 查找 compatible = "lite-on,ap3216c"
方式2:传统ID匹配
static const struct i2c_device_id ap3216c_ids[] = {{ "ap3216c", (kernel_ulong_t)NULL },{ /* END OF LIST */ }
};
匹配流程:检查I2C总线上是否有名称为"ap3216c"的设备
阶段5:调用probe函数(如果匹配成功)
static int ap3216c_probe(struct i2c_client *client, const struct i2c_device_id *id)
{printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);ap3216c_client = client;// 字符设备注册三步曲major = register_chrdev(0, "ap3216c", &ap3216c_ops);ap3216c_class = class_create(THIS_MODULE, "ap3216c_class");device_create(ap3216c_class, NULL, MKDEV(major, 0), NULL, "ap3216c");return 0;
}
阶段6:系统状态变化
内核空间变化:
1. /proc/modules 中出现 ap3216c_drv 模块
2. /proc/devices 中出现字符设备 "253 ap3216c"(假设分配的主设备号是253)
3. 内核驱动链表添加了 i2c_ap3216c_driver
文件系统变化:
1. /sys/class/ap3216c_class/ 目录被创建 2. /dev/ap3216c 设备节点被创建
sysfs变化:
/sys/bus/i2c/drivers/ap3216c/ # I2C驱动目录
/sys/class/ap3216c_class/ap3216c/ # 设备类目录
验证加载结果
方法1:检查模块列表
lsmod | grep ap3216c
输出:
ap3216c_drv 16384 0
方法2:检查设备节点
ls -l /dev/ap3216c
输出:
crw------- 1 root root 253, 0 Jan 1 10:30 /dev/ap3216c
方法3:检查/proc/devices
cat /proc/devices | grep ap3216c
输出:
253 ap3216c
方法4:检查sysfs
# 检查驱动目录
ls /sys/bus/i2c/drivers/ap3216c/
# 检查类目录
ls /sys/class/ap3216c_class/