大型linux驱动项目框架基础

大型linux驱动项目框架基础

声明:尝试阶段,欢迎有志之士提出建议,或者共同完善
联系方式:qq:1614811057
博客目前状态:持续更新中

1.主入口

makefile

arch ?= x86
modname ?= hello_drv

ifeq ($(arch),arm)
	KERNELDIR := /home/psd/code_space/100ask_imx6ull-sdk/Linux-4.9.88
else
	KERNELDIR := /lib/modules/$(shell uname -r)/build/
endif

PWD := $(shell pwd)
# ccflags-y += -I$(PWD)/../irq_sr501
ccflags-y += -I/home/psd/code_space/100ask_imx6ull-sdk/my_project_space/project_test/irq/irq_sr501

all:
	make -C $(KERNELDIR) M=$(PWD) modules
clean:
	make -C $(KERNELDIR) M=$(PWD) clean

obj-m += $(modname).o
obj-m += irq_main.o
obj-m += irq_sr501.o

main.c

#include "irq_main.h"

module_t mod_table[] = {
    { irq_sr501_init, irq_sr501_exit }, // 定义函数指针数组,用于存储模块初始化和退出函数的地址
};

sub_module_t kmd_module_table[] = {
    {
        .name = "irq_sr501",
        .code_num = 0,
        .sub_component = &mod_table[0]
    },
};

static int irq_main_init(void)
{
    int ret = 0;
    int i = 0;
    // 对模块进行初始化,遍历子模块数组,并依次调用其中存储的函数指针
    for (i = 0; i < ARRAY_SIZE(kmd_module_table); i++) {
        if (kmd_module_table[i].sub_component->init != NULL) {
            ret = (int)kmd_module_table[i].sub_component->init();
            printk("sucess to initialize module: %s %d %d\n", kmd_module_table[i].name, kmd_module_table[i].code_num, i);
            if (ret != 0) {
                // 如果初始化函数返回错误,则打印错误信息并返回
                printk(KERN_ERR "Failed to initialize module: %s %d %d\n", kmd_module_table[i].name, kmd_module_table[i].code_num, i);
                return ret;
            }
        }
    }
    return ret;
}

static void irq_main_exit(void)
{
    int i = 0;
    // 对模块进行退出操作,逆序遍历子模块数组,并依次调用其中存储的函数指针
    for (i = ARRAY_SIZE(kmd_module_table) - 1; i >= 0; i--) {
        if (kmd_module_table[i].sub_component->exit != NULL) {
            kmd_module_table[i].sub_component->exit();
            printk("sucess to initialize module: %s %d %d\n", kmd_module_table[i].name, kmd_module_table[i].code_num, i);
        }
    }
}

module_init(irq_main_init); // 设置模块初始化函数
module_exit(irq_main_exit); // 设置模块退出函数
MODULE_LICENSE("GPL"); // 设置模块许可证

main.h

#ifndef __IRQ_MAIN_H__
#define __IRQ_MAIN_H__

#include "irq_sr501.h"
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/fcntl.h>
#include <linux/fs.h>
#include <linux/gfp.h>
#include <linux/gpio/consumer.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/kmod.h>
#include <linux/major.h>
#include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/poll.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/stat.h>
#include <linux/timer.h>
#include <linux/tty.h>

typedef struct kmd_module {
    int (*init)(void);
    void (*exit)(void);
} module_t;

typedef struct kmd_sub_module {
    char* name;
    int code_num;
    module_t* sub_component;
} sub_module_t;

static int irq_main_init(void);
static void irq_main_exit(void);

#endif

2.驱动模块

2.1温度中断传感器sr501

路径:

/home/psd/code_space/100ask_imx6ull-sdk/my_project_space/project_test/irq/irq_sr501

.c

#include "irq_sr501.h"



static int __init irq_sr501_init(void)
{

	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);

	return 0;
}


static void __exit irq_sr501_exit(void)
{

	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);

}

.h

#ifndef __IRQ_SR501_H__
#define __IRQ_SR501_H__

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

#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/fcntl.h>
#include <linux/timer.h>

static int __init irq_sr501_init(void);
static void __exit irq_sr501_exit(void);

#endif

目前状态:

无法加载sr_501文件
从下面的实验已经可以找到问题所在了,但是这一块不急,先在同一目录下多集成几个模块之后再扩大规模

3.最新进展:

同目录下的不同模块集成已完成,
正在完善主入口文件里面的基础配套操作

3.1文件目录结构介绍

3.1.1目录:

在这里插入图片描述

3.1.2文件:
led_ctrl.h:
#ifndef __LED_CTRL_H__
#define __LED_CTRL_H__

#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/uaccess.h>

#define LED_NAME "led"
#define PATH_DTS_LED "/leds/led0"

#define KMD_ERR(str) \
	printk("%s %s line: %d %s \n", __FILE__, __FUNCTION__, __LINE__, str);

typedef struct led_ctrl {
    char *dev_name;
    struct device_node *led_node;
    int led_num;
} led_ctrl_t;

void test(void);
int led_ctrl_init(led_ctrl_t * led);

int led_ctrl_exit(led_ctrl_t * led);

#endif
led_ctrl.c:
#include"led_ctrl.h"

// led_ctrl_t led =
// {
//     .dev_name = LED_NAME,

// };
void test(void)
{
    KMD_ERR("led_ctrl_init 测试");
}
int led_ctrl_init(led_ctrl_t * led)
{
    // led->led_node = of_find_node_by_path(PATH_DTS_LED);
    KMD_ERR("led_ctrl_init 测试");
    return 0;
}

int led_ctrl_exit(led_ctrl_t * led)
{
    KMD_ERR("led_ctrl_exit 测试");
    return 0;
}
irq_base.h:
#ifndef __IRQ_BASE_H__
#define __IRQ_BASE_H__

#include <linux/module.h>
#include <linux/poll.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/fcntl.h>
#include <linux/timer.h>

#define KMD_ERR(str) \
	printk("%s %s line: %d %s \n", __FILE__, __FUNCTION__, __LINE__, str);

typedef struct irq_base
{
    unsigned int major;
    const char *name;
    struct class *class;
    struct device * device;

} irq_base_t;

// 字符设备初始化
static int irq_cdev_init(void);   

#endif

irq_base.c

#include "irq_base.h"
#include "irq_sr501.h"

#define IRQ_BASE_NAME "IRQ_BASE"
static irq_base_t irq_base = {
	.name = IRQ_BASE_NAME,
};


static int irq_base_open(struct inode *inode, struct file *file)
{
	int ret = 0;
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	return -ret;
}

static ssize_t irq_base_read(struct file *file, char __user *buf,
			   size_t count, loff_t *ppos)
{
	int ret = 0;
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);

	return ret;
}

static ssize_t irq_base_write(struct file *file, const char __user *buf,
			    size_t count, loff_t *ppos)
{
	int ret = 0;
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);

	return ret;
}

static int irq_base_release(struct inode *inode, struct file *file)
{
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	return 0;
}

static const struct file_operations irq_base_fops = {
	.owner		= THIS_MODULE,
	.open		= irq_base_open,
	.read		= irq_base_read,
	.write		= irq_base_write,
	.release	= irq_base_release,
};

static int irq_cdev_init(void)
{
	// 在/proc/devices文件中添加对应的字符设备信息和主设备号
	irq_base.major =  register_chrdev(0, irq_base.name, &irq_base_fops);
	if (irq_base.major < 0)
	{
		KMD_ERR("irq_base.major get ERR");
		goto ERR_IO;
	}
	// 在/sys/class/目录下添加了一个IRQ_BASE的目录,
	irq_base.class = class_create(THIS_MODULE, irq_base.name);
	if(IS_ERR(irq_base.class))
	{
		KMD_ERR("irq_base.class get ERR");
		return PTR_ERR(irq_base.class);
		goto class_ERR;
	}

	irq_base.device = device_create(irq_base.class,NULL, MKDEV(irq_base.major,0), NULL, "%s", irq_base.name);
	if(IS_ERR(irq_base.device))
	{
		KMD_ERR("irq_base.device get ERR");
		return PTR_ERR(irq_base.device);
		goto device_ERR;
	}
	return 0;
device_ERR:
	class_destroy(irq_base.class);
class_ERR:
	unregister_chrdev(irq_base.major, irq_base.name);
ERR_IO:
	return -EIO;			//没有这样的设备或地址
}

/* 在入口函数 */
static int __init irq_base_init(void)
{
	int ret = 0;
	// printk(KERN_ERR "irq_sr501_init 测试\n");
	if(irq_sr501_init())
	{
		printk(KERN_ERR "irq_sr501_init ERR\n");
		return -EINVAL;
	}

	if((ret = irq_cdev_init()) != 0)
	{
		KMD_ERR("irq_cdev_init ERR");
		return ret;
	}
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);

	return 0;
}

/* 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数
 */
static void __exit irq_base_exit(void)
{
	device_destroy(irq_base.class, MKDEV(irq_base.major, 0));
	class_destroy(irq_base.class);
	unregister_chrdev(irq_base.major, irq_base.name);
	irq_sr501_exit();
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);

}

module_init(irq_base_init);
module_exit(irq_base_exit);

MODULE_DESCRIPTION("irq_base_driver");
MODULE_LICENSE("GPL");
irq_sr501.h
#ifndef __IRQ_SR501_H__
#define __IRQ_SR501_H__

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

#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/fcntl.h>
#include <linux/timer.h>

int __init irq_sr501_init(void);
void __exit irq_sr501_exit(void);

#endif
irq_sr501.c
#include "irq_sr501.h"


/* 在入口函数 */
int __init irq_sr501_init(void)
{

	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);

	return 0;
}

/* 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数
 */
void __exit irq_sr501_exit(void)
{

	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);

}
MODULE_DESCRIPTION("irq_sr501_driver");
MODULE_LICENSE("GPL");
makefile
arch ?= arm
modname ?= irq_base
PWD := $(shell pwd)
TARGET := IRQ_MAIN
INCLUDE_DIR := other_module
CFLAGS_DIR := $(PWD)/$(INCLUDE_DIR)
# 定义额外的编译选项,EXTRA_CFLAGS 变量用于指定额外的编译选项,可以通过它向编译器传递自定义的选项
EXTRA_CFLAGS += -I$(CFLAGS_DIR)
ifeq ($(arch),arm)
	KERNELDIR := /home/psd/code_space/100ask_imx6ull-sdk/Linux-4.9.88
else
	KERNELDIR := /lib/modules/$(shell uname -r)/build/
endif

$(TARGET)-objs := ./other_module/led_ctrl.o irq_sr501.o irq_base.o     #依赖的中间文件
obj-m += $(TARGET).o			#生成最终TARGET.ko文件
#  $(CFLAGS) INCDIR=$(PWD)/$(INCLUDE_DIR)
all:
	make -C $(KERNELDIR) M=$(PWD) EXTRA_CFLAGS='$(EXTRA_CFLAGS)' modules
	@echo "Copying module files to ~/nfs_rootfs/"
	@if [ -d ~/nfs_rootfs ]; then \
		if [ -e ~/nfs_rootfs/*.ko -o -e ~/nfs_rootfs/*.sh ]; then \
			rm -f ~/nfs_rootfs/*.ko ~/nfs_rootfs/*.sh; \
		fi; \
		if [ -e ./*.ko ]; then \
			cp -f ./*.ko ~/nfs_rootfs/; \
		fi; \
		if [ -e ./*.sh ]; then \
			cp -f ./*.sh ~/nfs_rootfs/; \
		fi; \
	fi
clean:
	make -C $(KERNELDIR) M=$(PWD) clean
#obj-m是模块化编译会生成.ko文件,obj-y则是编译进内核不会生成.ko文件
#-objs代表需要编译的依赖中间.o文件
op_mod.sh
lsmod
dmesg -c
rmmod *.ko
lsmod
dmesg
# 删除完之后打印下
insmod *.ko
dmesg
cat /proc/devices
ls /sys/class
ls /dev

3.2调试进展

已经可以调用其他目录下驱动模块代码

在这里插入图片描述

  • 10
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值