1.1 详见 Linux C编程-CSDN博客
1.2 Linux 驱动
1.2.1 我的第一个Linux驱动
-
查看linux环境中的fs.h文件
cd /
sudo find -name "fs.h"
可以看到如下,一般是在./usr/src/linux-hwe-6.8-headers-6.8.0-87/include/linux/fs.h这个路径下(实际源码路径无查看权限,但是这个路径可以查看),通过vim即可查看。
xiaobai@xiaobai:/$ sudo find -name "fs.h"
find: './run/user/1000/gvfs': 权限不够
find: './run/user/1000/doc': 权限不够
find: './run/user/128/doc': 权限不够
./usr/src/linux-hwe-6.8-headers-6.8.0-87/include/trace/misc/fs.h
./usr/src/linux-hwe-6.8-headers-6.8.0-87/include/linux/fs.h
./usr/src/linux-hwe-6.8-headers-6.8.0-87/include/linux/mlx5/fs.h
./usr/src/linux-hwe-6.8-headers-6.8.0-87/include/uapi/linux/fs.h
./usr/src/linux-hwe-6.8-headers-6.8.0-86/include/trace/misc/fs.h
./usr/src/linux-hwe-6.8-headers-6.8.0-86/include/linux/fs.h
./usr/src/linux-hwe-6.8-headers-6.8.0-86/include/linux/mlx5/fs.h
./usr/src/linux-hwe-6.8-headers-6.8.0-86/include/uapi/linux/fs.h
图示如下:

-
首先找到实际源码路径,如下
xiaobai@xiaobai:~/linux/Linux_Drivers/1_chrdevbase$ uname -r
6.8.0-87-generic
然后在./usr/src该目录下可以找到一个如下几个文件
xiaobai@xiaobai:/usr/src/linux-hwe-6.8-headers-6.8.0-87$ cd ..
xiaobai@xiaobai:/usr/src$ ll
总计 28
drwxr-xr-x 7 root root 4096 11月 5 00:00 ./
drwxr-xr-x 14 root root 4096 9月 11 2024 ../
drwxr-xr-x 7 root root 4096 10月 29 11:44 linux-headers-6.8.0-86-generic/
drwxr-xr-x 7 root root 4096 11月 4 10:35 linux-headers-6.8.0-87-generic/
drwxr-xr-x 26 root root 4096 10月 29 11:44 linux-hwe-6.8-headers-6.8.0-86/
drwxr-xr-x 26 root root 4096 11月 4 10:35 linux-hwe-6.8-headers-6.8.0-87/
drwxr-xr-x 4 root root 4096 11月 5 00:00 python3.10/
其中这个linux-headers-6.8.0-87-generic就是所在源码文件夹。然后新建一个.vscode文件夹新建两个文件分别是c_cpp_properties.json 和settings.json 里面内容如下
c_cpp_properties.json
{
"configurations": [
{
"name": "linux",
"includePath": [
"${workspaceFolder}/**",
"/usr/src/linux-headers-6.8.0-87-generic/include",
"/usr/src/linux-headers-6.8.0-87-generic/arch/arm/include"
],
"intelliSenseMode": "linux-gcc-x64",
"compilerPath": "/usr/bin/gcc",
"cStandard": "c11",
"cppStandard": "gnu++17"
}
],
"version": 4
}
注意
"/usr/src/linux-headers-6.8.0-87-generic/include",
"/usr/src/linux-headers-6.8.0-87-generic/arch/arm/include"
这两行代码需要换成你自己的源文件所在目录当然./usr/src/linux-hwe-6.8-headers-6.8.0-87这个目录也可以尝试一下。
settings.json
{
"files.associations": {
"*.py": "python",
"module.h": "c"
},
"search.exclude": {
"**/node_modules": true,
"**/bower_components": true,
"**/*.code-search": true,
"**/*.o":true,
"**/*.su":true,
"**/*.cmd":true,
"Documentation":true
},
"files.exclude": {
"**/.git": true,
"**/.svn": true,
"**/.hg": true,
"**/.DS_Store": true,
"**/Thumbs.db": true,
"**/CVS":true,
"**/*.o":true,
"**/*.su":true,
"**/*.cmd":true,
"Documentation":true
}
}
在.vscode同级文件夹下建立chardevbase.c文件如下
#include <linux/module.h>
MODULE_LICENSE("GPL");
static int __init chardevbase_init(void)
{
return 0;
}
static void __exit chardevbase_exit(void)
{
}
/*
模块入口与出口
*/
module_init(chardevbase_init); /* 入口 */
module_exit(chardevbase_exit);/* 出口 */
再写一个Makefile,注意这个KERNELDIR必须是你的实际源码所在位置。
KERNELDIR := /usr/src/linux-headers-6.8.0-87-generic
CURRENT_PATH := $(shell pwd)
obj-m := chardevbase.o
build: kernel_modules
kernel_modules:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules
clean:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean
创建.ko文件
make
通过如下命令进行驱动的加载与移除
sudo insmod chardevbase.ko
sudo rmmod chardevbase
或者
sudo modprode chardevbase.ko
sudo modprode -r chardevbase
第一个加载第二个删除并且可以通过lsmod | grep chardevbase查看是否加载成功。
注意使用insmod并不能自动查找驱动之间的依赖关系,但是使用modprode可以。
例如如果你有个驱动叫 mc.ko依赖lc.ko如果你要成功使用mc.ko则需要先用insmod加载lc.ko再加载mc.ko但如果你用modprode则可以直接使用modprode mc.ko ,但需要你自己把.ko移到/lib/modules/6.8.0-87-generic目录下,注意首次使用时需要运行sudo depmod。否则还是会报错modprobe: FATAL: Module chardevbase not found in directory /lib/modules/6.8.0-87-generic。
- 实现驱动加载的调试,打印相关输出!!!(注意输出难以通过打印台打印出来需要通过
sudo dmesg | tail -8查看)
修改chardevbase.c
#include <linux/module.h>
#include <linux/printk.h>
static int __init chardevbase_init(void)
{
printk("driver init!!!!\n");
return 0;
}
static void __exit chardevbase_exit(void)
{
printk(KERN_EMERG "chardevbase: module unloaded\n");
}
/*
模块入口与出口
*/
module_init(chardevbase_init); /* 入口 */
module_exit(chardevbase_exit);/* 出口 */
MODULE_LICENSE("GPL");
输出如下
xiaobai@xiaobai:/usr/src/linux-hwe-6.8-headers-6.8.0-87$ sudo dmesg | tail -8
[52454.452524] driver init!!!!
[52543.248780] chardevbase: module unloaded
-
- 嵌入式设备的注册与注销

首先可以看到major对应的主设备号,extern int register_chrdev_region(dev_t, unsigned, const char *);这个代码中的dev_t代表设备号,typedef __kernel_dev_t dev_t;再去索引__kernel_dev_t发现typedef u32 __kernel_dev_t;是u32再去索引typedef __u32 u32;发现是__u32最终得出是typedef unsigned int __u32;32位无符号整型变量。
通过如下代码(kdev.h中)

#define MINORBITS 20
#define MINORMASK ((1U << MINORBITS) - 1)
#define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS))
#define MINOR(dev) ((unsigned int) ((dev) & MINORMASK))
#define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi))
发现高12位代表主设备号,低20位代表次设备号,通过命令行输入cat /proc/devices 发现如下输出:第一个为设备号,第二个为设备名,得到200的主设备号没有使用。可以定义本次主设备号为200。设备名可以为chardev。
Character devices:
1 mem
4 /dev/vc/0
4 tty
4 ttyS
5 /dev/tty
5 /dev/console
5 /dev/ptmx
5 ttyprintk
6 lp
7 vcs
10 misc
13 input
21 sg
29 fb
81 video4linux
89 i2c
99 ppdev
108 ppp
116 alsa
128 ptm
136 pts
180 usb
189 usb_device
202 cpu/msr
204 ttyMAX
216 rfcomm
226 drm
234 kfd
235 aux
236 media
237 cec
238 lirc
239 nvme-generic
240 nvme
241 hidraw
242 ttyDBC
243 bsg
244 watchdog
245 remoteproc
246 ptp
247 pps
248 rtc
249 dma_heap
250 dax
251 dimmctl
252 ndctl
253 tpm
254 gpiochip
261 accel
Block devices:
7 loop
8 sd
9 md
11 sr
65 sd
66 sd
67 sd
68 sd
69 sd
70 sd
71 sd
128 sd
129 sd
130 sd
131 sd
132 sd
133 sd
134 sd
135 sd
252 device-mapper
253 virtblk
254 mdp
259 blkext
第三个参数是一个结构体,通过上图可知该结构体有open,write等函数,此时仅需定义一个该类型的结构体即可。可以参考如下搭一个简单的驱动
#include <linux/module.h>
#include <linux/printk.h>
#define CHARDEVBASE 200 //定义主设备号 200
#define dev_name "chardev" //定义设备名
//写open
/*
* @descripts : 打开设备
* @param - inode : 传递给驱动的inode
* @param - filp : 设备文件,file结构体有个叫做private_data的成员变量
*
* @return : 0 成功;其他 失败
*/
static int chardev_open(struct inode *inode, struct file *file){
printk("chardevbase_open\n");
return 0;
}
//写release
/*
* @descripts : 打开设备
* @param - inode : 传递给驱动的inode
* @param - filp : 设备文件,file结构体有个叫做private_data的成员变量
*
* @return : 0 成功;其他 失败
*/
static int chardev_release(struct inode *inode, struct file *file){
printk("chardevbase_release\n");
return 0;
}
static ssize_t chardev_read(struct file *, char __user *, size_t, loff_t *){
printk("chardevbase_read\n");
return 0;
}
static ssize_t chardev_write(struct file *, const char __user *, size_t, loff_t *){
printk("chardevbase_write\n");
return 0;
}
static struct file_operations chardev_file = {
.owner = THIS_MODULE,
.open = chardev_open,
.release = chardev_release,
.read = chardev_read,
.write = chardev_write,
};
static int __init chardevbase_init(void)
{
int ret = 0; //接收注册设备的返回值
/*注册字符设备*/
ret = register_chrdev(CHARDEVBASE, dev_name,&chardev_file);
if (ret < 0)
{
printk(KERN_WARNING "coudle not get major number,chrdevbase init fail\n");
}
printk("driver init!!!!\n");
return 0;
}
static void __exit chardevbase_exit(void)
{
printk("chardevbase: module unloaded\n");
/*注销字符设备*/
unregister_chrdev(CHARDEVBASE, dev_name);
}
/*
模块入口与出口
*/
module_init(chardevbase_init); /* 入口 */
module_exit(chardevbase_exit);/* 出口 */
MODULE_LICENSE("GPL");
1.2.2 我的第一个开发板驱动(Jeston nano )
通过如下命令uname -a查找自己开发板的架构
Linux wheeltec 5.10.216-tegra #1 SMP PREEMPT Tue Mar 4 01:35:16 PST 2025 aarch64 aarch64 aarch64 GNU/Linux
第二步通过uname -r查看内核版本
5.10.216-tegra
第三步查看自己的内核所在地
cd /
sudo find -name "fs.h"
输出如下:
wheeltec@wheeltec:/$ sudo find -name "fs.h"
./var/lib/docker/overlay2/7ab8244ee411089a0ed93ed354a24f284c691be259e4e1254c675c0af07fffc2/diff/usr/include/linux/fs.h
./var/lib/docker/overlay2/7ab8244ee411089a0ed93ed354a24f284c691be259e4e1254c675c0af07fffc2/diff/usr/lib/aarch64-linux-gnu/openmpi/include/openmpi/ompi/mca/fs/fs.h
./var/lib/docker/overlay2/aa3e65839ccf6918d5e2f06b3addaae9fa5603bda8e402e12d255ffe25341d09/diff/usr/include/linux/fs.h
./timeshift/snapshots/2025-10-28_08-53-15/localhost/usr/include/linux/fs.h
./timeshift/snapshots/2025-10-28_08-53-15/localhost/usr/lib/aarch64-linux-gnu/openmpi/include/openmpi/ompi/mca/fs/fs.h
./timeshift/snapshots/2025-10-28_08-53-15/localhost/usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/uapi/linux/fs.h
./timeshift/snapshots/2025-10-28_08-53-15/localhost/usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/btrfs/fs.h
./timeshift/snapshots/2025-10-28_08-53-15/localhost/usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/debug/fs.h
./timeshift/snapshots/2025-10-28_08-53-15/localhost/usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/usb/f/fs.h
./timeshift/snapshots/2025-10-28_08-53-15/localhost/usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/usb/configfs/f/fs.h
./timeshift/snapshots/2025-10-28_08-53-15/localhost/usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/msdos/fs.h
./timeshift/snapshots/2025-10-28_08-53-15/localhost/usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/exfat/fs.h
./timeshift/snapshots/2025-10-28_08-53-15/localhost/usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/ext4/fs.h
./timeshift/snapshots/2025-10-28_08-53-15/localhost/usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/fuse/fs.h
./timeshift/snapshots/2025-10-28_08-53-15/localhost/usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/nfs/fs.h
./timeshift/snapshots/2025-10-28_08-53-15/localhost/usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/proc/fs.h
./timeshift/snapshots/2025-10-28_08-53-15/localhost/usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/snd/proc/fs.h
./timeshift/snapshots/2025-10-28_08-53-15/localhost/usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/blk/debug/fs.h
./timeshift/snapshots/2025-10-28_08-53-15/localhost/usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/overlay/fs.h
./timeshift/snapshots/2025-10-28_08-53-15/localhost/usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/set/fs.h
./timeshift/snapshots/2025-10-28_08-53-15/localhost/usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/autofs/fs.h
./timeshift/snapshots/2025-10-28_08-53-15/localhost/usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/ext3/fs.h
./timeshift/snapshots/2025-10-28_08-53-15/localhost/usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/configfs/fs.h
./timeshift/snapshots/2025-10-28_08-53-15/localhost/usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/fat/fs.h
./timeshift/snapshots/2025-10-28_08-53-15/localhost/usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/scsi/proc/fs.h
./timeshift/snapshots/2025-10-28_08-53-15/localhost/usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/vfat/fs.h
./timeshift/snapshots/2025-10-28_08-53-15/localhost/usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/efivar/fs.h
./timeshift/snapshots/2025-10-28_08-53-15/localhost/usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/iso9660/fs.h
./timeshift/snapshots/2025-10-28_08-53-15/localhost/usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/9p/fs.h
./timeshift/snapshots/2025-10-28_08-53-15/localhost/usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/ntfs/fs.h
./timeshift/snapshots/2025-10-28_08-53-15/localhost/usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/autofs4/fs.h
./timeshift/snapshots/2025-10-28_08-53-15/localhost/usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/linux/fs.h
./timeshift/snapshots/2025-10-28_08-53-15/localhost/usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/linux/mlx5/fs.h
./usr/include/linux/fs.h
./usr/lib/aarch64-linux-gnu/openmpi/include/openmpi/ompi/mca/fs/fs.h
./usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/uapi/linux/fs.h
./usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/btrfs/fs.h
./usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/debug/fs.h
./usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/usb/f/fs.h
./usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/usb/configfs/f/fs.h
./usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/msdos/fs.h
./usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/exfat/fs.h
./usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/ext4/fs.h
./usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/fuse/fs.h
./usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/nfs/fs.h
./usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/proc/fs.h
./usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/snd/proc/fs.h
./usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/blk/debug/fs.h
./usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/overlay/fs.h
./usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/set/fs.h
./usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/autofs/fs.h
./usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/ext3/fs.h
./usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/configfs/fs.h
./usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/fat/fs.h
./usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/scsi/proc/fs.h
./usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/vfat/fs.h
./usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/efivar/fs.h
./usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/iso9660/fs.h
./usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/9p/fs.h
./usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/ntfs/fs.h
./usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/config/autofs4/fs.h
./usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/linux/fs.h
./usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10/include/linux/mlx5/fs.h
find: './run/user/1000/gvfs': Permission denied
wheeltec@wheeltec:/$
内核版本我查了一下发现内核的源码在/usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10。(一般是在/usr/src)。然后可以去fs.h文件下找到file_operations结构体发现和上面的截图有点不太一样。
然后你可以查找read函数发现如下,索引到simple_attr_read
static const struct file_operations __fops = { \
.owner = THIS_MODULE, \
.open = __fops ## _open, \
.release = simple_attr_release, \
.read = simple_attr_read, \
.write = (__is_signed) ? simple_attr_write_signed : simple_attr_write, \
.llseek = generic_file_llseek, \
}
ssize_t simple_attr_read(struct file *file, char __user *buf, size_t len, loff_t *ppos);
发现自己上面写的还是有点问题,修改如下,主要修改了read和write两个函数
#include <linux/module.h>
#include <linux/printk.h>
#define CHARDEVBASE 200 //定义主设备号 200
#define dev_name "chardev" //定义设备名
//写open
/*
* @descripts : 打开设备
* @param - inode : 传递给驱动的inode
* @param - filp : 设备文件,file结构体有个叫做private_data的成员变量
*
* @return : 0 成功;其他 失败
*/
static int chardev_open(struct inode *inode, struct file *file){
printk("chardevbase_open\n");
return 0;
}
//写release
/*
* @descripts : 打开设备
* @param - inode : 传递给驱动的inode
* @param - filp : 设备文件,file结构体有个叫做private_data的成员变量
*
* @return : 0 成功;其他 失败
*/
static int chardev_release(struct inode *inode, struct file *file){
printk("chardevbase_release\n");
return 0;
}
static ssize_t chardev_read(struct file *file, char __user *buf,size_t len, loff_t *ppos){
printk("chardevbase_read\n");
return 0;
}
static ssize_t chardev_write(struct file *file, const char __user *buf, size_t len, loff_t *ppos){
printk("chardevbase_write\n");
return 0;
}
static struct file_operations chardev_file = {
.owner = THIS_MODULE,
.open = chardev_open,
.release = chardev_release,
.read = chardev_read,
.write = chardev_write,
};
static int __init chardevbase_init(void)
{
int ret = 0; //接收注册设备的返回值
/*注册字符设备*/
ret = register_chrdev(CHARDEVBASE, dev_name,&chardev_file);
if (ret < 0)
{
printk(KERN_WARNING "coudle not get major number,chrdevbase init fail\n");
}
printk("driver init!!!!\n");
return 0;
}
static void __exit chardevbase_exit(void)
{
printk("chardevbase: module unloaded\n");
/*注销字符设备*/
unregister_chrdev(CHARDEVBASE, dev_name);
}
/*
模块入口与出口
*/
module_init(chardevbase_init); /* 入口 */
module_exit(chardevbase_exit);/* 出口 */
MODULE_LICENSE("GPL");
写一下Makefile,注意KERNELDIR需要改变一下改成上面的。
KERNELDIR := /usr/src/linux-headers-5.10.216-tegra-ubuntu20.04_aarch64/kernel-5.10
CURRENT_PATH := $(shell pwd)
obj-m := chardevbase.o
build: kernel_modules
kernel_modules:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules
clean:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean
1.2.3 我的第一个Linux应用
可以通过 man 123 read , man 123 write 和 open 以及 close
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
/*
* argc : 应用参数个数
* argv : 每个参数的内容,以字符串表示
* return : 0 成功执行,其他未成功执行
* ./chardevbaseapp.c <filename>
**/
int main(int argc, char *argv[])
{
int fd = 0;
char *filename;
filename = argv[1];
/* The return value of open() is a file descriptor 返回值为文件描述符
* The argument flags must include one of the following access modes: O_RDONLY, O_WRONLY, or O_RDWR. These request opening the file read-only, write-only, or read/write, respectively.
* flag参数需要选择一个可用的模式O_RDONLY, O_WRONLY, or O_RDWR
**/
char buffer[100];
char writer_buf[20];
int ret;
/*打开文件*/
fd = open(argv[1], O_RDWR);
if (fd < 0)
{
printf("filename:%s file open fail !!!",filename);
return -1;
}
/*读取数据*/
ret = read(fd,buffer,100);
if (ret < 0)
{
printf("filename:%s file read fail !!!",filename);
return -1;
}
/*写数据*/
ret = write(fd,writer_buf,20);
if (ret < 0)
{
printf("filename:%s file wirte fail !!!",filename);
return -1;
}
/*关闭文件*/
ret = close(fd);
if (ret < 0)
{
printf("filename:%s file close fail !!!",filename);
return -1;
}
return 0;
}
1.2.4 驱动的载入
cd "Makefile文件夹下"
make
sudo insmod chardevbase.ko
实现驱动加载的调试,打印相关输出!!!(注意输出难以通过打印台打印出来需要通过sudo dmesg | tail -8查看)
输入输出如下
wheeltec@wheeltec:~/driver/1_chrdevbase$ sudo insmod chardevbase.ko
wheeltec@wheeltec:~/driver/1_chrdevbase$ sudo dmesg | tail -1
[ 6176.679700] driver init!!!!
注册设备
解释一下 /dev/(你的设备名#define dev_name "chardev" //定义设备名)
c 字符设备 200 主设备号 0 次设备号
sudo mknod /dev/chardev c 200 0
输出如下:
wheeltec@wheeltec:~/driver/1_chrdevbase$ ll /dev/chardev
crw-r--r-- 1 root root 200, 0 12月 3 01:02 /dev/chardev
然后开发板端通过编译chardevbaseapp
gcc chardevbaseapp.c -o chardevbaseapp
然后sudo ./chardevbaseapp /dev/chardev
再通过sudo dmesg | tail -5查看输出。
wheeltec@wheeltec:~/driver/1_chrdevbase$ sudo dmesg | tail -5
[ 6176.679700] driver init!!!!
[ 6384.888651] chardevbase_open
[ 6384.888660] chardevbase_read
[ 6384.888661] chardevbase_write
[ 6384.888663] chardevbase_release