“一个”网站,毕业设计做 什么网站好,如何运营网站,网站备案成功后可以改吗驱动编译前提#xff1a;驱动代码的编译需要提前编译号的内核
驱动#xff08;3种实现方法#xff0c;2条路线#xff09;_驱动编写三种方法-CSDN博客
驱动的编写_驱动编写-CSDN博客
一、概念
1.1、驱动认识 1、裸机程序中是直接操控硬件的#xff0c;操作系统… 驱动编译前提驱动代码的编译需要提前编译号的内核
驱动3种实现方法2条路线_驱动编写三种方法-CSDN博客
驱动的编写_驱动编写-CSDN博客
一、概念
1.1、驱动认识 1、裸机程序中是直接操控硬件的操作系统中必须通过驱动来操控硬件。这两个的本质区别就是分层 2、linux驱动本身做了模块化设计linux驱动本身和linux内核不是强耦合的 3、驱动的设计中有一个关键数据结构结构体结构体中包含一些变量和一些函数指针 变量用来记录驱动相关的一些属性函数指针用来记录驱动相关的操作方法 这些变量和函数指针加起来就构成了驱动。驱动就被抽象为这个结构体 4、一个驱动工作时主要就分几部分驱动构建构建一个struct mmc然后填充它 驱动运行时调用这些函数指针指针的函数和变量 5、分离思想 分离思想就是说在驱动中将操作方法和数据分开 操作方法就是函数数据就是变量 在不同的地方来存储和管理驱动的操作方法和变量这样的优势就是驱动便于移植。 6、分层思想 分层思想是指一个整个的驱动分为好多个层次 简单理解就是驱动分为很多个源文件放在很多个文件夹中
1.2、什么是驱动 1、设备和用户之间的桥梁内核结构由用户级内核级硬件级 2、驱动操作硬件部分代码
1.3、驱动分为3种及区别 1、字符设备以字节为单位读写串口led等 2、块设备以块为单位读写sd卡等 3、网络设备网卡socket等
1.4、模块化 1、宏内核:操作系统是整体紧耦合直接调用函数简单高效 微内核:相当于是多个进程一个错误不会影响其他Windows 2、静态模块化:程序编译内核编译时可裁剪加模块要重新编译烧录 动态模块化:加模块不需要重新编译
1.5、安全性 1、驱动程序崩溃内核可能崩溃 2、驱动效率影响内核效率 3、安全漏洞 未初始化例如函数指针 恶意用户程序利用驱动的漏洞例如传参 缓冲区溢出例如超出缓存区大小 竞争状态自旋锁等
1.6、应用驱动硬件的流程 APP------调用C库种(openwrite,read)等函数产生软中断(中断号0x80)从用户空间进入到内核空间---------sys_call函数根据驱动被设备名去找到设备号----------虚拟文件系统VAFS(sys_opensys_write)去找相应驱动引脚的驱动文件open-------------驱动文件open直接操作寄存器
1.7、设备文件 1、各种设备以文件的形式存放在**/dev目录称设备文件** 2、主设备号次设备号 1、主设备号不同的设备硬盘led 2、次设备号同一类的多个设备led1led2
1.8、驱动链表数组 驱动插入链表的顺序由设备号检索 1、管理所有设备的驱动 2、添加驱动插入链表顺序由设备号检索 编写驱动加载到内核 设备名设备号设备驱动函数操作寄存器来驱动I/O 3、查找 调用 调用驱动程序用户应用去open
1.9、
1.9、udev机制 1、udev是一个设备管理工具udev以守护进程的形式运行 2、通过侦听内核发出来的uevent来管理/dev目录下的设备文件。 3、udev在用户空间运行而不在内核空间运行。 4、它能够根据系统中的硬件设备的状态动态更新设备文件包括设备文件的创建删除等。 5、udev会根据/etc/udev/udev.conf文件中的udev_rules指定的目录逐个检查该目录下的 文件这个目录下的文件都是针对某类或某个设备应该施行什么措施的规则文件。
二、实现一个驱动代码 1、添加驱动需要什么 1、设备名 2、设备号 3、驱动代码 2、假设树莓派dev目录下已经存在了一个 pin4的驱动 应用层访问/dev/pin4驱动代码
#include sys/types.h
#include sys/stat.h
#include fcntl.h
#include unistd.h#include stdio.hint main()
{int fd;char ch 1;fd open(/dev/pin4 ,O_RDWR);if (-1 fd){perror(erron);printf(open failed!\n);}else{printf(open success\n);}fd write(fd , (void *)ch ,1);return 0;
}3、写一个字符设备驱动 因为驱动程序是通过驱动链表进行添加的首先开发需要拿到固定驱动框架下面是一个字符驱动框架
#include linux/fs.h //file_operations声明
#include linux/module.h //module_init module_exit声明
#include linux/init.h //__init __exit 宏定义声明
#include linux/device.h //class device声明
#include linux/uaccess.h //copy_from_user的头文件
#include linux/types.h //设备号 dev_t 类型声明
#include asm/io.h //iorsemap iorsemap的头文件static struct class *pin4_class;
static struct device *pin4_class_dev;static dev_t devno; //设备号
static int major231; //主设备号
static int minor 0; //次设备号
static char *module_name pin4; //模块名static ssize_t pin4_read(struct file *file ,char __user *buf,size_t size ,loff_t *ppos)
{printk(pin4_read\n);return 0;
}// led_open函数
static int pin4_open(struct inode *inode, struct file *file)
{printk(pin4_open\n); //内和打印函数和printf差不多可以用dmesg命令查看内核的打印return 0;
}//led_write函数
static ssize_t pin4_write(struct file *file, const char __user *buf, size_t count,loff_t *ppos)
{printk(pin4_write\n);return 0;
}// 这个结构结构体会被注册进驱动链表
static struct file_operations pin4_fops { .owner THIS_MODULE,//将对应的函数关联在file_operations的结构体中.open pin4_open,.write pin4_write,.read pin4_read,
};int __init pin4_drv_init(void) //真实驱动入口
{ int ret;devno MKDEV(major,minor); //创建设备号ret register_chrdev(major, module_name, pin4_fops); //注册驱动告诉内核 把这个驱动加到内核的链表中pin4_class class_create( THIS_MODULE,myfirstdemo); //让代码在dev自动生成设备 pin4_class_dev device_create(pin4_class,NULL,devno,NULL,module_name);//创建设备文件return 0;
}void __exit pin4_drv_exit(void)
{device_destroy(pin4_class,devno);class_destroy(pin4_class);unregister_chrdev(major,module_name); //卸载驱动}module_init(pin4_drv_init); // 入口内核加载该驱动的时候这个宏会被调用
module_exit(pin4_drv_exit);
MODULE_LICENSE(GPL v2);3、对驱动代码进行编译驱动可以编译成模块或编译进内核 把写的驱动代码复制到下载的Linux源码文件里的drviers/char字符驱动设备下 更改Makefile文件 将驱动编译成模块 编译驱动代码
ARCHarm CROSS_COMPILEarm-linux-gnueabihf- KERNELkernel7 make modules 交叉编译调用该驱动的应用层文件并将驱动模块文件和应用层文件都考入树莓派 加载内核驱动
sudo insmod pin4drivers.kolsmod //这个命令可以查看内核驱动模块
rmmod //删除驱动模块 例rmmod pin4drivers 运行驱动测试代码 sudo ~/pin4testdmesg 查看内核打印的信息 应用层调用驱动 引用层open通过文件名找到驱动的设备号————产生软中断调用sys_call————调用虚拟文件系统的sys_open通过设备号去驱动链表找到相应的硬件驱动文件————执行驱动文件里面的open。