[ 驱动移植 ] [ 1 ] 内核模块

Linux中驱动程序,可以像浏览器中的插件一样,通过模块插入方式与内核产生互动。

内核模块程序

hello.c

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

int __init myhello_init(void) {
    printk("###############################\n");
    printk("myhello is running\n");
    printk("###############################\n");
    return 0;
}

void __exit myhello_exit(void) {
    printk("myhello will exit\n");
}

MODULE_LICENSE("GPL");

module_init(myhello_init);

module_exit(myhello_exit);

Makefile

ifeq ($(KERNELRELEASE),)

KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)

modules:
        $(MAKE) -C $(KERNELDIR) M=$(PWD) modules

modules_install:
        $(MAKE) -C $(KERNELDIR) M=(PWD) INSTALL_MOD_PATH=$(ROOTFS)

clean:
        rm -rf *.o *.ko .*.cmd *.mod.* modules.order Module.symvers

else
obj-m += hello.o

endif

输出

[46328.986968] ###############################
[46328.986969] myhello is running
[46328.986970] ###############################
[46396.441806] myhello will exit

相关命令

sudo insmod ./???.ko  #插件安装

lsmod  #查看已经插入内核模块的插件

sudo rmmod  #删除插件

sudo dmesg -C  #清除插件输出信息

dmesg  #查看插件输出信息printk

驱动程序

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>

int major = 11;
int minor = 0;
int mychar_num = 1;

struct cdev mydev;

int mychar_open(struct inode *pnode, struct file *pfile) {
    printk("mychar_open is called\n");
    return 0;
}

int mychar_close(struct inode *pnode, struct file *pfile) {
    printk("mychar_close is called\n");
    return 0;
}

struct file_operations myops = {
    .owner = THIS_MODULE,
    .open = mychar_open,
    .release = mychar_close,
};

int __init mychar_init(void) {
    int ret = 0;
    dev_t devno = MKDEV(major, minor);

    // 申请设备号
    ret = register_chrdev_region(devno, mychar_num, "mychar");
    if (ret) {
        ret = alloc_chrdev_region(&devno, minor, mychar_num, "mychar");
        if (ret) {
            printk("get devno failed\n");
            return -1;
        }
        major = MAJOR(devno);
    }

    // 给struct cdev对象指定操作函数集
    cdev_init(&mydev, &myops);

    // 将struct cdev对象添加到内核对应的数据结构中
    mydev.owner = THIS_MODULE;
    cdev_add(&mydev, devno, mychar_num);
    return 0;
}

void __exit mychar_exit(void) {
    dev_t devno = MKDEV(major, minor);
    cdev_del(&mydev);
    unregister_chrdev_region(devno, mychar_num);
}

MODULE_LICENSE("GPL");
module_init(mychar_init);
module_exit(mychar_exit);

测试程序

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc, char *argv[]) {
    if (argc < 2) {
        printf("The argument is too fewc\n");
        return -1;
    }
    int fd = open(argv[1], O_RDONLY);
    if (fd < 0) {
        printf("open error\n");
        return -1;
    }
    return 0;
}

安装驱动:sudo insmod mychar.ko

查看驱动主设备号:cat /proc/devices | grep mychar

创建驱动文件:sudo mknod /dev/mydev c 11 0

测试程序通过系统调用open函数,调用驱动程序,输出如下:

image.png