嵌入式---驱动7
内核计数器是用原子操作实现的统计工具用于安全地记录各种事件发生的次数比如中断次数、错误次数、数据包数量等。赫兹Hz在内核中表示系统一秒所对应的节拍数量目前为100。在内核中的.config 中定义 jiffies表 示系统节拍记录系统启动到当前累加的数字如果想通过内核定时器计时则定时时间为jiffers N*100定时时间到达后可以调用回调函数。函数接口void work_handle(struct work_struct *work) // 内核中的线程调度可休眠可打断 { // // msleep(5000); // wait_condition 1; // wake_up_interruptible(wait_que); // mytimer.expires jiffies msecs_to_jiffies(10); mod_timer(mytimer, jiffies msecs_to_jiffies(10)); return; } void timer_handle(unsigned long data) { if (gpio_get_value(key_gpio)) { } else { wait_condition 1; wake_up_interruptible(wait_que); } } init_timer(mytimer); // mytimer.expires 0; mytimer.function timer_handle;定时器消抖的优势每次中断只是调用mod_timer重置超时时间不创建工作队列项开销极小。kworker线程不会被阻塞能及时处理其他任务。适合高频中断场景比如编码器、高频按键。jiffies是内核的“系统心跳计数器”驱动用它来实现超时、定时和延时功能是内核时间管理的核心记录了系统启动以来发生的“时钟滴答Tick”次数。每次系统定时器中断触发jiffies就会自动加 1。宏/函数作用msecs_to_jiffies(ms)把毫秒转换成jiffiesusecs_to_jiffies(us)把微秒转换成jiffiestime_after(a, b)判断a是否在b之后处理回绕time_before(a, b)判断a是否在b之前处理回绕platform驱动框架Platform 总线是 Linux 嵌入式驱动的基石它通过compatible匹配机制将设备树数据和驱动逻辑绑定在一起驱动在probe中调用platform_get_resource获取硬件资源并初始化硬件Platform 总线的工作方式完美体现了 Linux 驱动“分离”的设计思想。设备Device“描述硬件资源”。告诉内核“我的地址是0x0209C000中断号是42”。在设备树.dts中描述。驱动Driver“提供操作逻辑”。告诉内核“我会配置 GPIO”、“我会读写 UART”。在驱动代码中实现。总线Bus“负责匹配”。内核通过 Platform 总线根据compatible属性值将设备和驱动绑定在一起。当compatible字符串匹配时内核就会调用驱动中的.probe()函数驱动就可以通过platform_get_resource()等 API从匹配的设备节点中获取硬件信息并初始化硬件函数接口module_platform_driver(my_driver);是module_initmodule_exitplatform_driver_registerplatform_driver_unregister的四合一模板宏。Platform 总线维护两条链表分别存储设备和驱动。每当有新的设备或驱动加入时内核就会遍历另一条链表根据compatible或name进行匹配匹配成功后调用probe建立绑定关系。这个机制是 Linux 设备驱动模型的核心。链表存储内容用户态查看路径klist_devicesplatform_device硬件描述/sys/bus/platform/devices/klist_driversplatform_driver软件驱动/sys/bus/platform/drivers/① 设备注册时platform_device_register把该设备加入设备链表klist_devices。遍历驱动链表klist_drivers对每个驱动调用platform_match判断是否匹配。如果匹配成功调用驱动的probe函数建立绑定关系。② 驱动注册时platform_driver_register把该驱动加入驱动链表klist_drivers。遍历设备链表klist_devices对每个设备调用platform_match判断是否匹配。如果匹配成功调用驱动的probe函数建立绑定关系。probeprobe是 platform 驱动中的一个回调函数当内核成功将驱动和设备匹配后它会自动调用这个函数让驱动完成硬件的初始化工作。probe是驱动真正初始化硬件的地方解析设备树gpio、irq、reg资源申请GPIO、注册中断、初始化定时器、注册input/misc设备分配私有设备结构体存入dev-platform_data/dev-driver_dataprobe驱动和设备的“连接确认函”匹配成功后自动调用参数struct platform_device *pdev包含硬件资源信息返回值0 成功负数 失败执行上下文进程上下文可以睡眠主要任务获取硬件资源、映射寄存器、分配设备号、创建/dev/节点、初始化硬件probe是驱动真正“活过来”的时刻——它拿到硬件资源、初始化设备、注册到系统让应用层能通过/dev/节点访问硬件。没有probe驱动就只是一段“未激活的代码”。static int myprobe(struct platform_device *plat_dev); static int myremove(struct platform_device *plat_dev); //声明了Platform驱动的probe/remove回调。 struct device_node *pnode NULL; static struct of_device_id of_match_table[] {{.compatible pt,pute-led}, // 主要靠这个 匹配 驱动 {} };//of_match_table用于设备树匹配。设备树中的compatible必须完全匹配pt,pute-ledprobe才会被调用。 static struct platform_device_id id_table[] {{ .name ptled, }, {} };//id_table用于非设备树的传统匹配方式通过name匹配 static struct platform_driver plat_drv { .probe myprobe, .remove myremove, .driver { .name ptled, .owner THIS_MODULE, .of_match_table of_match_table, }, .id_table id_table, };//Platform驱动的核心结构体 static int myprobe(struct platform_device *plat_dev) { int ret 0; ret misc_register(misc_dev); if (ret 0) { pr_err(misc_register error\n); return ret; } pnode of_find_node_by_path(/puteled); if (NULL pnode) { pr_err(of_find_node_by_path error\n); ret -ENODEV; goto del_misc; } led_gpio of_get_named_gpio(pnode, gpio-led, 0); if (led_gpio 0) { pr_err(of_get_named_gpio error\n); ret -ENODEV; goto del_pnode; } ret devm_gpio_request(misc_dev.this_device, led_gpio, led_gpio); if (ret 0) { pr_err(devm_gpio_request error,errno:%d\n, ret); goto del_pnode; } gpio_direction_output(led_gpio, 1); pr_info(pute led myprobe ok \n); return 0; del_pnode: of_node_put(pnode); del_misc: misc_deregister(misc_dev); return ret; } static int myremove(struct platform_device *plat_dev) { misc_deregister(misc_dev); return 0; } static int __init led_init(void) { int ret 0; ret platform_driver_register(plat_drv); if (ret 0) { pr_err(platform_driver_register error,errno :%d\n, ret); return ret; } return 0; } static void __exit led_exit(void) { platform_driver_unregister(plat_drv); return; } module_init(led_init); module_exit(led_exit); MODULE_LICENSE(GPL);platform匹配优先级由高到低1. driver_override强制指定 ← 最高优先级调试/临时覆盖用2. 设备树 OF compatible ← 主流嵌入式 Linux 的标准方式3. ACPI ID 匹配 ← x86/服务器 使用4. platform_driver id_table 匹配 ← 传统方式非设备树5. 设备名与驱动名全等匹配 ← 兜底最后尝试