Linux 驱动

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.jsonsettings.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
相关推荐
向山行_wolf1 小时前
ubuntu20.04安装向日葵
linux·运维·服务器
❀͜͡傀儡师1 小时前
Docker部署OneTerm堡垒机
运维·docker·容器·oneterm
菜鸟小九1 小时前
mysql运维(主从复制)
android·运维·mysql
飘忽不定的bug1 小时前
记录:ubuntu20.04隐藏鼠标指针
linux·ubuntu
松涛和鸣1 小时前
23、链式栈(LinkStack)的实现与多场景应用
linux·c语言·c++·嵌入式硬件·ubuntu
虾..1 小时前
Linux 进程替换
linux·运维·服务器
赖small强1 小时前
【Linux驱动开发】Linux Debugfs 虚拟文件系统深度解析与实战指南
linux·驱动开发·debugfs
Crazy________1 小时前
43ansible常用模块及变量定义方式
linux·运维·服务器
翼龙云_cloud1 小时前
阿里云渠道商:无影云电脑常见问题及其解决方法有哪些?
运维·服务器·阿里云·云计算·电脑