• linux 驱动——将模块编译进内核


    linux 驱动——字符设备驱动
    linux 驱动——字符设备驱动(自动生成设备节点文件)
    linux 驱动——将模块编译进内核

    前面两节介绍的驱动都是以模块的形式,需要手动加载,本节介绍如何将模块编译进内核

    新增 C 文件

    #include "linux/device/class.h"
    #include "linux/export.h"
    #include "linux/uaccess.h"
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    #define CHRDEVBASE_NAME "chrdevbase" /* 设备名 */
    #define CHRDEVBASE_NUM 1             /* 设备数目 */
    
    static char write_buf[100];
    static char read_buf[100];
    
    static char *string_test = "kernel data this tyustli test";
    
    typedef struct {
        dev_t dev_id;          /* 设备号 */
        struct cdev c_dev;     /* cdev */
        struct class *class;   /* 类 */
        struct device *device; /* 设备 */
        int major;             /* 主设备号 */
        int minor;             /* 次设备号 */
    } new_chrdev_t;
    
    new_chrdev_t new_chrdev;
    
    static int chrdevbase_open(struct inode *inode, struct file *file)
    {
        printk("k: chrdevbase open\r\n");
    
        return 0;
    }
    
    static ssize_t chrdevbase_read(struct file *file, char __user *buf,
                                   size_t count, loff_t *ppos)
    {
        unsigned long ret = 0;
    
        printk("k: chrdevbase read\r\n");
        memcpy(read_buf, string_test, strlen(string_test));
    
        ret = copy_to_user(buf, read_buf, count);
        if (ret == 0) {
            printk("k: read data success\r\n");
        } else {
            printk("k: read data failed ret = %ld\r\n", ret);
        }
    
        return ret;
    }
    
    static ssize_t chrdevbase_write(struct file *file, const char __user *buf,
                                    size_t count, loff_t *ppos)
    {
        unsigned long ret = 0;
    
        printk("k: chrdevbase write\r\n");
    
        ret = copy_from_user(write_buf, buf, count);
        if (ret == 0) {
            printk("k: write data success write data is: %s\r\n", write_buf);
        } else {
            printk("k: write data failed ret = %ld\r\n", ret);
        }
    
        return count;
    }
    
    static int chrdevbase_release(struct inode *inode, struct file *file)
    {
        printk("k: chrdevbase release\r\n");
    
        return 0;
    }
    
    static struct file_operations chrdevbase_fops = {
        .owner = THIS_MODULE,
        .open = chrdevbase_open,
        .read = chrdevbase_read,
        .write = chrdevbase_write,
        .release = chrdevbase_release,
    };
    
    static int __init chrdevbase_init(void)
    {
        int err = 0;
    
        err = alloc_chrdev_region(&new_chrdev.dev_id, 0, CHRDEVBASE_NUM,
                                  CHRDEVBASE_NAME);
        if (err < 0) {
            printk("k: alloc chrdev region failed err = %d\r\n", err);
            return -1;
        }
    
        /* get major and minor */
        new_chrdev.major = MAJOR(new_chrdev.dev_id);
        new_chrdev.minor = MINOR(new_chrdev.dev_id);
        printk("k: newcheled major=%d,minor=%d\r\n", new_chrdev.major,
               new_chrdev.minor);
    
        new_chrdev.c_dev.owner = THIS_MODULE;
        cdev_init(&new_chrdev.c_dev, &chrdevbase_fops);
        err = cdev_add(&new_chrdev.c_dev, new_chrdev.dev_id, CHRDEVBASE_NUM);
        if (err < 0) {
            printk("k: cdev add failed err = %d\r\n", err);
            goto out;
        }
    
        new_chrdev.class = class_create(CHRDEVBASE_NAME);
        if (IS_ERR(new_chrdev.class)) {
            printk("k: class create failed\r\n");
            goto out_cdev;
        }
    
        new_chrdev.device = device_create(new_chrdev.class, NULL, new_chrdev.dev_id,
                                          NULL, CHRDEVBASE_NAME);
        if (IS_ERR(new_chrdev.device)) {
            printk("k: device create failed\r\n");
            goto out_class;
        }
    
        printk("k: base module init\r\n");
    
        return 0;
    
    out_class:
        class_destroy(new_chrdev.class);
    out_cdev:
        cdev_del(&new_chrdev.c_dev);
    out:
        unregister_chrdev_region(new_chrdev.dev_id, CHRDEVBASE_NUM);
    
        return err;
    }
    
    static void __exit chrdevbase_exit(void)
    {
        device_destroy(new_chrdev.class, new_chrdev.dev_id);
        class_destroy(new_chrdev.class);
        cdev_del(&new_chrdev.c_dev);
        unregister_chrdev_region(new_chrdev.dev_id, CHRDEVBASE_NUM);
    
        printk("k: base module exit!\r\n");
    }
    
    module_init(chrdevbase_init);
    module_exit(chrdevbase_exit);
    
    MODULE_LICENSE("GPL");
    MODULE_AUTHOR("tyustli");
    MODULE_INFO(intree, "Y"); /* loading out-of-tree module taints kernel */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155

    将上一节中的模块源码拷贝到 drivers/char 目录下
    在这里插入图片描述

    修改 Makefile 文件

    在这里插入图片描述

    • CONFIG_MY_MODULE 是配置宏,如果定义了该宏,就是 obj-y += my_module.o
    • my_module.o 就是自己新增 C 文件,这里写 .o 即可

    修改 Kconfig 文件

    在这里插入图片描述

    • Makefile 文件中依赖的是 CONFIG_MY_MODULE 宏,所以这里定义 MY_MODULE 宏即可。

    模块使能

    在这里插入图片描述
    空格即可选中

    Shift + ? 可以显示帮助信息
    在这里插入图片描述

    内核启动日志

    workingset: timestamp_bits=30 max_order=17 bucket_order=0
    squashfs: version 4.0 (2009/01/31) Phillip Lougher
    jffs2: version 2.2. (NAND) © 2001-2006 Red Hat, Inc.
    9p: Installing v9fs 9p2000 file system support
    io scheduler mq-deadline registered
    io scheduler kyber registered
    io scheduler bfq registered
    k: newcheled major=250,minor=0
    k: base module init
    OF: graph: no port node found in /bus@40000000/motherboard-bus@40000000/iofpga@7,00000000/i2c@16000/dvi-transmitter@60
    sii902x 0-0060: supply iovcc not found, using dummy regulator
    sii902x 0-0060: supply cvcc12 not found, using dummy regulator
    simple-pm-bus bus@40000000:motherboard-bus@40000000:iofpga@7,00000000: Failed to create device link (0x180) with dcc:tcrefclk
    simple-pm-bus bus@40000000:motherboard-bus@40000000:iofpga@7,00000000: Failed to create device link (0x180) with dcc:tcrefclk
    physmap-flash 40000000.flash: physmap platform flash device: [mem 0x40000000-0x43ffffff]
    40000000.flash: Found 2 x16 devices at 0x0 in 32-bit bank. Manufacturer ID 0x000000 Chip ID 0x000000
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    k: newcheled major=250,minor=0
    k: base module init
    
    • 1
    • 2

    自动打印出来了

    参考

    • https://www.rt-thread.org/document/site/#/development-tools/build-config-system/Kconfig
  • 相关阅读:
    Android Studio中创建java项目
    [PAT练级笔记] 34 Basic Level 1034 有理数四则运算
    声控小夜灯方案开发 声控小夜灯IC芯片方案开发MCU
    2022年度嵌入式C语言面试题库(含答案)
    【hadoop】纠删码技术详解
    PySide6应用实践 | 在PyCharm中安装、部署、启动PySide6
    专用嵌入式分析软件的重要性
    尚硅谷Flink(一)
    沉睡者IT - 月赚几千的创业项目思路,抖音文案号网赚项目
    TCP协议之《对端MSS值估算》
  • 原文地址:https://blog.csdn.net/tyustli/article/details/134255158