T2 第一个驱动(helloworld)

1.驱动代码

1.1头文件

#include <linux/init.h>
#include <linux/module.h>

1.2装载与卸载函数声明

  • 当生成的.ko文件被装载的时候,内核会调用module_init函数,向系统申请资源
  • 当生成的.ko文件被卸载的时候,内核会调用module_exit函数,释放资源
module_init(hello_drv_init);
module_exit(hello_drv_exit);

1.3装载与卸载函数实现

/*模块装载函数实现*/
static int __init hello_drv_init(void)
{
    return 0;
}


/*模块卸载函数实现*/
static void __exit hello_drv_exit(void)
{
    
}

1.4GPL声明

MODULE_LICENSE("GPL");

1.5最简单的驱动

#include <linux/init.h>
#include <linux/module.h>


/*模块装载函数实现*/
static int __init hello_drv_init(void)
{
    printk("--------%s---------\n", __FUNCTION__);
    return 0;
}


/*模块卸载函数实现*/
static void __exit hello_drv_exit(void)
{
    printk("--------%s---------\n", __FUNCTION__);
}


module_init(hello_drv_init);
module_exit(hello_drv_exit);
MODULE_LICENSE("GPL");

2.编译驱动代码

2.1编写Makefile

  • 在第一次执行make指令后,会自动执行Makefile文件
  • 首先判断KERNELRELEASE宏是否为空,默认为空,故执行make -C $(KERNEL_DIR) M=$(CUR_DIR) modules
  • 执行后Makefile会调用内核里面的Makefile将KERNELRELEASE赋值
  • 之后再次执行Makefile,此可会跳转到obj-m += hello_driver.o编译内核
  • 通用Makefile文件
# 指定保存ko文件的文件夹,可以是文件系统的某个文件夹
ROOTFS_DIR = /home/hanqi/my_drivers_ko
# 比较函数
ifeq ($(KERNELRELEASE), )
# 指向编译后内核的路径,一定是编译之后的内核!!!!
KERNEL_DIR = /home/hanqi/pi/linux-rpi-4.14.y
# 指向当前文件路径,即保存驱动.c文件的路径
CUR_DIR = $(shell pwd)

all:
# 编译驱动,需指定交叉编译工具路径
	make -C $(KERNEL_DIR) M=$(CUR_DIR) modules ARCH=arm CROSS_COMPILE=/home/hanqi/pi/toolchain/tools-master/arm-bcm2708/arm-linux-gnueabihf/bin/arm-linux-gnueabihf-
clean:
# 清除编译后的驱动文件
	make -C $(KERNEL_DIR) M=$(CUR_DIR) clean
install:
# 拷贝驱动.ko文件到目标文件夹
	cp -raf *.ko $(ROOTFS_DIR)
else
# 指定需要编译的驱动文件,此处为hello_driver.o
obj-m += hello_driver.o
endif
  • 结果
hanqi@hanqi-PC:~/my_drivers$ ls
hello_driver.c  Makefile
# 执行make指令
hanqi@hanqi-PC:~/my_drivers$ make
make -C /home/hanqi/pi/linux-rpi-4.14.y M=/home/hanqi/my_drivers modules ARCH=arm CROSS_COMPILE=/home/hanqi/pi/toolchain/tools-master/arm-bcm2708/arm-linux-gnueabihf/bin/arm-linux-gnueabihf-
make[1]: Entering directory '/home/hanqi/pi/linux-rpi-4.14.y'
  CC [M]  /home/hanqi/my_drivers/hello_driver.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /home/hanqi/my_drivers/hello_driver.mod.o
  LD [M]  /home/hanqi/my_drivers/hello_driver.ko
make[1]: Leaving directory '/home/hanqi/pi/linux-rpi-4.14.y'
hanqi@hanqi-PC:~/my_drivers$ ls
hello_driver.c   hello_driver.mod.c  hello_driver.o  modules.order
hello_driver.ko  hello_driver.mod.o  Makefile        Module.symvers
# 拷贝ko文件
hanqi@hanqi-PC:~/my_drivers$ make install
cp -raf *.ko /home/hanqi/my_drivers_ko
# 清除多余文件
hanqi@hanqi-PC:~/my_drivers$ make clean 
make -C /home/hanqi/pi/linux-rpi-4.14.y M=/home/hanqi/my_drivers clean
make[1]: Entering directory '/home/hanqi/pi/linux-rpi-4.14.y'
  CLEAN   /home/hanqi/my_drivers/.tmp_versions
  CLEAN   /home/hanqi/my_drivers/Module.symvers
make[1]: Leaving directory '/home/hanqi/pi/linux-rpi-4.14.y'
hanqi@hanqi-PC:~/my_drivers$ ls
hello_driver.c  Makefile
# 拷贝成功
hanqi@hanqi-PC:~/my_drivers$ ls /home/hanqi/my_drivers_ko/
hello_driver.ko
hanqi@hanqi-PC:~/my_drivers$ 

2.2直接修改内核源码目录

# 进入源码下的字符设备驱动文件夹
hanqi@hanqi-PC:~/my_drivers$ cd /home/hanqi/pi/linux-rpi-4.14.y/drivers/char
# 将当前编写好的驱动代码拷贝到内核驱动目录下
hanqi@hanqi-PC:~/pi/linux-rpi-4.14.y/drivers/char$ cp ~/my_drivers/hello_driver.c hello_driver.c
# 修改当前驱动路径下的Makefile文件
hanqi@hanqi-PC:~/pi/linux-rpi-4.14.y/drivers/char$ vim Makefile 
# 在其中添加我们自己的驱动hello_driver.o
obj-y				+= mem.o random.o
obj-m				+= hello_driver.o	# 自己的驱动
obj-$(CONFIG_TTY_PRINTK)	+= ttyprintk.o
obj-y				+= misc.o
obj-$(CONFIG_ATARI_DSP56K)	+= dsp56k.o
obj-$(CONFIG_VIRTIO_CONSOLE)	+= virtio_console.o
obj-$(CONFIG_RAW_DRIVER)	+= raw.o
obj-$(CONFIG_SGI_SNSC)		+= snsc.o snsc_event.o
obj-$(CONFIG_MSPEC)		+= mspec.o
obj-$(CONFIG_UV_MMTIMER)	+= uv_mmtimer.o
obj-$(CONFIG_IBM_BSR)		+= bsr.o
obj-$(CONFIG_SGI_MBCS)		+= mbcs.o
obj-$(CONFIG_BFIN_OTP)		+= bfin-otp.o
...
# 回到内核根目录下编译驱动,注意此时只需要编译内核,不用加镜像,设备树的选项
hanqi@hanqi-PC:~/pi/linux-rpi-4.14.y$ ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- KERNEL=kernel7 make -j2 modules
  CHK     include/config/kernel.release
  CHK     include/generated/uapi/linux/version.h
  CHK     include/generated/utsrelease.h
  CHK     scripts/mod/devicetable-offsets.h
  CHK     include/generated/timeconst.h
  CHK     include/generated/bounds.h
  CHK     include/generated/asm-offsets.h
  CALL    scripts/checksyscalls.sh
  CHK     kernel/config_data.h
  Building modules, stage 2.
  MODPOST 1523 modules
  CC      drivers/char/hello_driver.mod.o
  LD [M]  drivers/char/hello_driver.ko	# 编译好的驱动
# 将.ko文件拷贝到树莓派上
hanqi@hanqi-PC:~/pi/linux-rpi-4.14.y$ scp drivers/char/hello_driver.ko pi@192.168.1.39:/home/pi
pi@192.168.1.39's password: 
hello_driver.ko                      100% 3412   327.1KB/s   00:00    

# 在树莓派上装载驱动
pi@raspberrypi:~/my_drivers $ sudo insmod hello_driver.ko
# 查看驱动
pi@raspberrypi:~/my_drivers $ lsmod
Module                  Size  Used by
hello_driver           16384  0
fuse                  106496  3
brcmfmac              278528  0
brcmutil               16384  1 brcmfmac
cfg80211              569344  1 brcmfmac
rfkill                 24576  4 cfg80211
snd_bcm2835            32768  1
snd_pcm                98304  1 snd_bcm2835
snd_timer              32768  1 snd_pcm
snd                    69632  5 snd_timer,snd_bcm2835,snd_pcm
uio_pdrv_genirq        16384  0
uio                    20480  1 uio_pdrv_genirq
fixed                  16384  0
i2c_dev                16384  0
ip_tables              24576  0
x_tables               32768  1 ip_tables
ipv6                  425984  24
# 卸载驱动
pi@raspberrypi:~/my_drivers $ sudo rmmod hello_driver
# 查看后台打印信息
pi@raspberrypi:~/my_drivers $ dmesg
...
[ 1180.032406] ---------hello_drv_init---------
[ 1382.148499] ---------hello_drv_exit---------
...

2.3相关指令

  • insmod装载驱动,装载驱动时候需要加ko后缀名称
  • rmmod卸载驱动,卸载驱动时候不用加ko后缀名称
  • lsmod查看已安装的驱动
  • dmesg查看后台打印信息
posted @ 2021-08-05 23:38  MHDSG  阅读(82)  评论(0)    收藏  举报