无标题
Linux驱动
内容
1、内核模块框架
2、一个完完整驱动的组成
3、led设备驱动
准备工作:
1、将linux源码拷贝一份到Windows下
2、在Windows下的linux源码目录下新建一个 source insight 文件夹
3、打开source insight 软件,新建一个工程,工程保存到刚新建的source insight 文件夹下
4、将Linux源码导入到source insight的工程中,并同步
同步方法如下:
在右边project文件栏下按鼠标右键-》点击Synchronize files-》勾选force all files to be re-parsed-》点击start
一)内核模块框架
1》内核模块组成
1、在fs_mp157a/driver/2308/1day/新建一个drv_hello.c 文件
2、头文件
#include <linux/init.h>
#include <linux/module.h>
3、加载函数——模块加载后运行的第一个函数
static int __init drv_hello_init(void)//加载函数
{
int ret=0;
printk(“—%s—\r\n”,FUNCTION);
return ret;
}
4、卸载函数——模块卸载时,会调用这个函数
static void __exit drv_hello_exit(void)//卸载函数
{
printk(“—%s—\r\n”,FUNCTION);
}
5、函数声明和认证
module_init(drv_hello_init);
module_exit(drv_hello_exit);
MODULE_LICENSE(“GPL”);
2》编写Makefile文件
//指定内核源码路径
KERNEL_DIR = /home/linux/fs_mp157a/kernel/stm32mp1-openstlinux-5.4-dunfell-mp1-20-06-24/sources/arm-ostl-linux-gnueabi/linux-stm32mp-5.4.31-r0/linux-5.4.31
CUR_DIR = ${shell pwd}
all:
//将当前目录下的源码和内核源码一起编译,编译成.ko文件
make -C $(KERNEL_DIR) M=$(CUR_DIR) modules
clean:
//清除将上面编译生成的文件
make -C $(KERNEL_DIR) M=$(CUR_DIR) clean
install:
//将当前目录下的所有.ko文件拷贝到根文件系统中
sudo cp *.ko /opt/rootfs/drivers
//指定要编译的源文件
obj-m = drv_hello.o
3》编译 make
make -C /home/linux/fs_mp157a/kernel/stm32mp1-openstlinux-5.4-dunfell-mp1-20-06-24/sources/arm-ostl-linux-gnueabi/linux-stm32mp-5.4.31-r0/linux-5.4.31 M=/home/linux/fs_mp157a/drivers/2308/1day modules
make[1]: Entering directory ‘/home/linux/fs_mp157a/kernel/stm32mp1-openstlinux-5.4-dunfell-mp1-20-06-24/sources/arm-ostl-linux-gnueabi/linux-stm32mp-5.4.31-r0/linux-5.4.31’
CC [M] /home/linux/fs_mp157a/drivers/2308/1day/drv_hello.o
Building modules, stage 2.
MODPOST 1 modules
CC [M] /home/linux/fs_mp157a/drivers/2308/1day/drv_hello.mod.o
LD [M] /home/linux/fs_mp157a/drivers/2308/1day/drv_hello.ko
make[1]: Leaving directory ‘/home/linux/fs_mp157a/kernel/stm32mp1-openstlinux-5.4-dunfell-mp1-20-06-24/sources/arm-ostl-linux-gnueabi/linux-stm32mp-5.4.31-r0/linux-5.4.31’
4》加载内核模块
1、在/opt/rootfs/下新建一个drivers文件夹
2、执行 make install 将.ko文件拷贝到根文件系统中
3、打开开发板,加载内核模块 (insmod 加载函数,rmmod 卸载函数,lsmod 查看)
[root@fsmp1a ]# cd drivers/ //进入模块文件夹
[root@fsmp1a drivers]# ls //查看文件夹内容
drv_hello.ko
[root@fsmp1a drivers]# insmod drv_hello.ko//加载内核模块
[ 8213.458054] —drv_hello_init—
[root@fsmp1a drivers]# lsmod//查看系统中加载的模块
drv_hello 16384 0 - Live 0xbf000000 (OE)
[root@fsmp1a drivers]# rmmod drv_hello.ko//卸载已经加载的模块
[ 8338.518719] —drv_hello_exit—
(二)一个完整驱动的组成
1》设备号
1、设备号的概念
是用一个32位的正数表示,分成两部分: 主设备号和次设备号
主设备号:用32位正数的高12位表示,表示一类设备(一类设备)
次设备号:用32位正数的低20位表示,表示具体的设备编号(具体的某一个)
2、申请设备号:
static inline int register_chrdev(unsigned int major, const char *name,const struct file_operations *fops)
//参数1 申请设备号的方式:major=0,表示动态申请主设备号
major>0,表示静态指定一个主设备号
//参数2 字符串,表示描述信息,自定义
//参数3 struct file_operations结构体指针
//返回指 如果参数1为0,成功返回主设备号,失败返回错误码
如果参数1不为0,成功返回0,失败返回错误码
static inline void unregister_chrdev(unsigned int major, const char *name) // 释放设备号.
3、编译,在开发板中加载驱动,并查看主设备号
[root@fsmp1a drivers]# insmod drv_hello.ko
[ 1985.156434] —drv_hello_init—
[root@fsmp1a drivers]# cat /proc/devices
Character devices:
1 mem
2 pty
3 ttyp
4 /dev/vc/0
4 tty
5 /dev/tty
5 /dev/console
5 /dev/ptmx
5 ttyRPMSG
7 vcs
10 misc
13 input
21 sg
29 fb
89 i2c
90 mtd
100 drv_hello //加载驱动申请的主设号
1 |
|