实验环境

开发板:龙芯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

参考