***********《朱有鹏老师嵌入式linux核心课程》 *********** 《5.linux驱动开发-第3部分-5.3.字符设备驱动高级》 -------------------------------------------------------- 本课程由朱老师物联网大讲堂推出并提供技术支持,课件可打包下载 网盘地址:http://yunpan.cn/cjVy3RAgfDufK 访问密码 4ad7 技术交流QQ群:朱老师物联网讲堂1群 397164505 -------------------------------------------------------- 第一部分、章节目录 5.3.1.注册字符设备驱动新接口1 5.3.2.注册字符设备驱动新接口2 5.3.3.注册字符设备驱动新接口3 5.3.4.注册字符设备驱动新接口4 5.3.5.字符设备驱动注册代码分析1 5.3.6.字符设备驱动注册代码分析2 5.3.7.自动创建字符设备驱动的设备文件 5.3.8.设备类相关代码分析1 5.3.9.设备类相关代码分析2 5.3.10.静态映射表建立过程分析 5.3.11.动态映射结构体方式操作寄存器 5.3.12.内核提供的读写寄存器接口 第二部分、章节介绍 5.3.1.注册字符设备驱动新接口1 本节介绍内核中提供的字符设备驱动注册的新接口cdev,并且讲了相关的接口函数,最后实践编写代码。 5.3.2.注册字符设备驱动新接口2 本节对上节讲述的知识进行实践编程测试。 5.3.3.注册字符设备驱动新接口3 本节讲述新接口如何自动分配设备号,以及其他一些编程细节如错误的逐级处理技巧。 5.3.4.注册字符设备驱动新接口4 本节讲述cdev_alloc和cdev_init这两个接口,同时引申讲解了C语言如何以面向对象的编程方式来实现linux内核。 5.3.5.字符设备驱动注册代码分析1 本节带大家浏览分析内核源码中与字符设备驱动相关的接口,使用SourceInsight逐级追踪的方式进入内核源码中。 5.3.6.字符设备驱动注册代码分析2 本节继续上节分析字符设备驱动注册相关的接口函数,目的是教大家学习如何从源码中去学习。 5.3.7.自动创建字符设备驱动的设备文件 本节实践编程演示如何使用class_create和device_create这两个接口来让字符设备驱动借助设备类自动创建及删除设备文件。 5.3.8.设备类相关代码分析1 本节开始分析class_create和device_create内部的实现原理。 5.3.9.设备类相关代码分析2 本节接上节继续分析,通过分析让大家对sysfs有所了解,知晓内核如果通过sysfs和udev进行通信以实现设备文件的自动创建和删除。 5.3.10.静态映射表建立过程分析 本节分析内核源码中与虚拟地址静态映射建立有关的代码,通过分析大家可以进一步掌握静态映射的实现细节。 5.3.11.动态映射结构体方式操作寄存器 本节对5.2.17中使用动态映射方式得到多个寄存器虚拟地址的代码进行改进,使用结构体封装的方式让我们能够方便的映射多个寄存器。 5.3.12.内核提供的读写寄存器接口 本节介绍内核提供的writel/readl和iowrite32/ioread32等读写寄存器的接口,并且对之前的驱动进行改进,和内核中典型的驱动程序进行对比学习。 第三部分、随堂记录 5.3.1.注册字符设备驱动新接口1 5.3.1.1、新接口与老接口 (1)老接口:register_chrdev (2)新接口:register_chrdev_region/alloc_chrdev_region + cdev (3)为什么需要新接口 5.3.1.2、cdev介绍 (1)结构体 (2)相关函数:cdev_alloc、cdev_init、cdev_add、cdev_del 5.3.1.3、设备号 (1)主设备号和次设备号 (2)dev_t类型 (3)MKDEV、MAJOR、MINOR三个宏 5.3.1.4、编程实践 (1)使用register_chrdev_region + cdev_init + cdev_add进行字符设备驱动注册 5.3.2.注册字符设备驱动新接口2 5.3.2.1、实践编程 5.3.2.2、测试 5.3.3.注册字符设备驱动新接口3 5.3.2.1、使用alloc_chrdev_region自动分配设备号 (1)register_chrdev_region是在事先知道要使用的主、次设备号时使用的;要先查看cat /proc/devices去查看没有使用的。 (2)更简便、更智能的方法是让内核给我们自动分配一个主设备号,使用alloc_chrdev_region就可以自动分配了。 (3)自动分配的设备号,我们必须去知道他的主次设备号,否则后面没法去mknod创建他对应的设备文件。 5.3.2.2、得到分配的主设备号和次设备号 (1)使用MAJOR宏和MINOR宏从dev_t得到major和minor (2)反过来使用MKDEV宏从major和minor得到dev_t。 (3)使用这些宏的代码具有可移植性 5.3.2.3、中途出错的倒影式错误处理方法 (1)内核中很多函数中包含了很多个操作,这些操作每一步都有可能出错,而且出错后后面的步骤就没有进行下去的必要性了。 5.3.4.注册字符设备驱动新接口4 5.3.4.1、使用cdev_alloc (1)cdev_alloc的编程实践 (2)从内存角度体会cdev_alloc用与不用的差别 (3)这就是非面向对象的语言和面向对象的代码 (4)再次感叹C语言的博大精深,好好去看《4.C语言高级专题》 5.3.4.2、cdev_init的替代 (1)cdev_init源码分析 (2)不使用cdev_init时的编程 (3)为什么讲这个 5.3.5.字符设备驱动注册代码分析1 5.3.5.1、老接口分析 register_chrdev __register_chrdev __register_chrdev_region cdev_alloc cdev_add 5.3.5.2、新接口分析 register_chrdev_region __register_chrdev_region alloc_chrdev_region __register_chrdev_region 5.3.6.字符设备驱动注册代码分析2 5.3.7.自动创建字符设备驱动的设备文件 5.3.7.1、问题描述: (1)整体流程回顾 (2)使用mknod创建设备文件的缺点 (3)能否自动生成和删除设备文件 5.3.7.2、解决方案:udev(嵌入式中用的是mdev) (1)什么是udev?应用层的一个应用程序 (2)内核驱动和应用层udev之间有一套信息传输机制(netlink协议) (3)应用层启用udev,内核驱动中使用相应接口 (4)驱动注册和注销时信息会被传给udev,由udev在应用层进行设备文件的创建和删除 5.3.7.3、内核驱动设备类相关函数 (1)class_create (2)device_create 5.3.7.4、编程实践 5.3.8.设备类相关代码分析1 5.3.8.1、sys文件系统简介 (1)sys文件系统的设计思想 (2)设备类的概念 (3)/sys/class/xxx/中的文件的作用 5.3.8.2、 (1) class_create __class_create __class_register kset_register kobject_uevent (2) device_create device_create_vargs kobject_set_name_vargs device_register device_add kobject_add device_create_file device_create_sys_dev_entry devtmpfs_create_node device_add_class_symlinks device_add_attrs device_pm_add kobject_uevent 5.3.9.设备类相关代码分析2 5.3.10.静态映射表建立过程分析 5.3.10.1、建立映射表的三个关键部分 (1)映射表具体物理地址和虚拟地址的值相关的宏定义 (2)映射表建立函数。该函数负责由(1)中的映射表来建立linux内核的页表映射关系。 在kernel/arch/arm/mach-s5pv210/mach-smdkc110.c中的smdkc110_map_io函数 smdkc110_map_io s5p_init_io iotable_init 结论:经过分析,真正的内核移植时给定的静态映射表在arch/arm/plat-s5p/cpu.c中的s5p_iodesc,本质是一个结构体数组,数组中每一个元素就是一个映射,这个映射描述了一段物理地址到虚拟地址之间的映射。这个结构体数组所记录的几个映射关系被iotable_init所使用,该函数负责将这个结构体数组格式的表建立成MMU所能识别的页表映射关系,这样在开机后可以直接使用相对应的虚拟地址来访问对应的物理地址。 (3)开机时调用映射表建立函数 问题:开机时(kernel启动时)smdkc110_map_io怎么被调用的? start_kernel setup_arch paging_init devicemaps_init if (mdesc->map_io) mdesc->map_io(); 5.3.11.动态映射结构体方式操作寄存器 5.3.11.1、问题描述 (1)仿效真实驱动中,用结构体封装的方式来进行单次多寄存器的地址映射。来代替我们5.2.17节中讲的多次映射。 5.3.11.2、实践编码 5.3.11.3、分析和总结 5.3.12.内核提供的读写寄存器接口 5.3.12.1、前面访问寄存器的方式 (1)行不行 (2)好不好 5.3.12.2、内核提供的寄存器读写接口 (1)writel和readl (2)iowrite32和ioread32 5.3.12.3、代码实践 5.3.12.4、分析和总结