为什么要进行驱动开发?
有的平台没有所谓“wiringPi”库,为了驱动引脚需要编写自己的“wiringPi”库
如何找到驱动?
1:文件名
2:设备号: Linux的设备管理是和文件系统紧密结合的,各种设备都以文件的形式存放在/dev目录下,称为设备文件。使用open系列打开。为了管理这些设备,系统为设备编了号
①主设备号:区分不同种类的设备
②次设备号:区分同一类型的多个设备
查看设备号:ls -l 红圈是 主 黄圈是 次
驱动调用或添加步骤参考:
用户进行open时linux进行系统调用的过程:
自己总结:用户调用open,open调用sys_call(系统调用),sys_call调用sys_open去打开驱动
open -> sys_call -> sys_open -> 驱动
参考别人的驱动:
#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 devise声明
#include <linux/uaccess.h> //copy_from_user 的头文件
#include <linux/types.h> //设备号 dev_t 类型声明
#include <asm/io.h> //ioremap iounmap的头文件
static struct class *pin4_class;
static struct device *pin4_class_dev;
static dev_t devno; //设备号
static int major = 231; //主设备号
static int minor = 0; //次设备号
static char *module_name = "pin4"; //模块名
//led_open函数
static int pin4_open(struct inode *inode,struct file *file)
{
printk("pin4_open\n"); //内核的打印函数和printf类似
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,
.open = pin4_open,
.write = pin4_write,
};
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); //入口,内核加载该驱动(insmod)的时候,这个宏被使用
module_exit(pin4_drv_exit);
MODULE_LICENSE("GPL v2");
编译阶段:
1.进入linux-rpi-4.14.y/drivers/char,编辑好文件pin_4.c
2.修改一下Makefile:vi Makefile
3.回到linux-rpi-4.14.y 编译代码:
ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- KERNEL=kernel7 make modules
4.生成的驱动pin_4发给树莓派:
scp /home/lzy/SYSTEM/linux-rpi-4.14.y/drivers/char/pin_4.ko pi@192.168.0.21:/home/pi
5.驱动传到树莓派后,需要加载驱动
加载驱动:sudo insmod hello_drv.ko
驱动卸载:sudo rmmod hello_drv 不需要写ko
查看驱动模块:lsmod
在/dev底下就能看到:
6.写一个测试程序,编译并运行测试程序
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
int fd;
fd=open("/dev/my_pin4",O_RDWR);
if(fd==-1){
printf("open failed\n");
}else{
printf("open success\n");
}
write(fd,"1",1);
return 0;
}
运行测试程序,一定要加超级用户权限sudo
在用户态是看不到内核态的东西的使用:dmesg查看:
总结:
调用流程:我们上层空间的①open去查找dev下的驱动(文件名),文件名背后包含了驱动的主设备号和次设备号,此时用户open触发一个②系统调用(sys_call),系统调用经过③vfs(虚拟文件系统),vfs根据文件名背后的设备号去调用④sys_open去判断,找到内核中驱动链表的驱动位置,再去调用驱动里面自己的⑤dev_open函数
验证步骤:
①装载驱动
②查看驱动装载后是否生成设备
③运行测试程序调试驱动
④内核的printk打印在内核层,通过dmesg查看内核打印信息