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

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

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

新增 C 文件

#include "linux/device/class.h"
#include "linux/export.h"
#include "linux/uaccess.h"
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/cdev.h>

#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 */

将上一节中的模块源码拷贝到 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
k: newcheled major=250,minor=0
k: base module init

自动打印出来了

参考

  • https://www.rt-thread.org/document/site/#/development-tools/build-config-system/Kconfig

猜你喜欢

转载自blog.csdn.net/tyustli/article/details/134255158