实验环境
开发板:龙芯LS2K0300久久派
网络配置:配置好ssh连接,通过网口可以scp文件到开发板,参考前一篇文章
串口配置:通过CH340T模块连接好开发板上的UART0
示例程序
驱动代码
#include <linux/init.h>
#include <linux/module.h>
static int hello_init(void)
{
printk("Hello, this is a simple linux driver!\n");
return 0;
}
static void hello_exit(void)
{
printk("Goodbye\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
Makefile脚本
obj-m += hello.o
KDIR:=/home/asensing/loongson/linux-4.19
ARCH=loongarch
CROSS_COMPILE=loongarch64-linux-gnu-
PWD?=$(shell pwd)
all:
make -C $(KDIR) M=$(PWD) modules
构建和部署脚本
export PATH=$PATH:/home/asensing/loongson/loongson-gnu-toolchain-8.3-x86_64-loongarch64-linux-gnu-rc1.3-1/bin
make -j8
FILE=$PWD/$(basename $PWD).ko
scp $FILE root@192.168.137.128:/home/root
验证
先清除内核日志
dmesg -c
在串口终端输入插入模块命令
insmod hello.ko
可以看到终端输出以下日志
[ 1253.139695] Hello, this is a simple linux driver!
然后输入卸载驱动模块命令
rmmod hello.ko
可以看到终端输出以下日志
[ 1350.375171] Goodbye
接口用法
MODULE_LICENSE
是一个用于指定模块的开源协议类型的宏,一般有以下几种
- GPL
- GPL v2
- GPL and additional rights
- Dual MIT/GPL
- Dual BSD/GPL
- Dual MPL/GPL
- Proprietary
module_init
用于指定模块初始化回调函数,设置驱动的资源初始化条件:如GPIO、定时器、中断、i2c设备等,函数原型:
typedef int (func)(void);
module_exit
用于指定模块卸载回调函数,驱动模块卸载时清理驱动所占用的资源:如内存、GPIO、定时器、中断等,函数原型:
typedef int (func)(void);
printk函数相当于内核编程的printf函数,用于在内核态打印日志,它有几个日志等级,用法如下:
printk(KERN_INFO "Info : %s\n", arg);
日志等级有以下几种:
Name | String | Alias function |
---|---|---|
KERN_EMERG | “0” | pr_emerg() |
KERN_ALERT | “1” | pr_alert() |
KERN_CRIT | “2” | pr_crit() |
KERN_ERR | “3” | pr_err() |
KERN_WARNING | “4” | pr_warn() |
KERN_NOTICE | “5” | pr_notice() |
KERN_INFO | “6” | pr_info() |
KERN_DEBUG | “7” | pr_debug() and pr_devel() if DEBUG is defined |
KERN_DEFAULT | “ ” | |
KERN_CONT | “c” | pr_cont() |
读取内核日志等级
cat /proc/sys/kernel/printk
设置内核日志等级
echo XX > /proc/sys/kernel/printk