驱动设计的思想:面向对象/分层/分离

本文介绍了一种基于分层和面向对象思想的LED驱动程序设计方法。通过将硬件操作抽象成通用模块,使得驱动程序更加灵活,易于维护。具体包括如何通过结构体抽象硬件操作,如何实现上下层分离及资源分配。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 面向对象

字符设备驱动程序抽象出一个 file_operations 结构体;

我们写的程序针对硬件部分抽象出led_operations 结构体。


2 分层

上下分层,比如我们前面写的 LED 驱动程序就分为 2 层:
① 上层实现硬件无关的操作,比如注册字符设备驱动:leddrv.c。
② 下层实现硬件相关的操作,比如 board_A.c 实现单板 A 的 LED 操作。

在这里插入图片描述


3 分离

还能不能改进?分离。
在 board_A.c 中,实现了一个led_operations,为 LED 引脚实现了初始化函数、控制函数:

static struct led_operations board_demo_led_opr = {
.num = 1,
.init = board_demo_led_init,
.ctl = board_demo_led_ctl,
};

如果硬件上更换一个引脚来控制 LED 怎么办?你要去修改上面结构体中的 init、ctl 函数。
实际情况是,每一款芯片它的 GPIO 操作都是类似的。比如:GPIO1_3、GPIO5_4 这 2 个引脚接到 LED:

① GPIO1_3 属于第 1 组,即 GPIO1。
有方向寄存器 DIR、数据寄存器 DR 等,基础地址是 addr_base_addr_gpio1。
设置为 output 引脚:修改 GPIO1 的 DIR 寄存器的 bit3。
设置输出电平:修改 GPIO1 的 DR 寄存器的 bit3。

② GPIO5_4 属于第 5 组,即 GPIO5。
有方向寄存器 DIR、数据寄存器 DR 等,基础地址是 addr_base_addr_gpio5。
设置为 output 引脚:修改 GPIO5 的 DIR 寄存器的 bit4。
设置输出电平:修改 GPIO5 的 DR 寄存器的 bit4。

既然引脚操作那么有规律,并且这是跟主芯片相关的,那可以针对该芯片写出比较通用的硬件操作代码。

比如 board_A.c 使用芯片 chipY,那就可以写出:chipY_gpio.c,它实现芯片 Y 的 GPIO 操作,适用于
芯片 Y 的所有 GPIO 引脚。
使用时,我们只需要在 board_A_led.c 中指定使用哪一个引脚即可。

程序结构如下:
在这里插入图片描述

以面向对象的思想,在 board_A_led.c 中实现 led_resouce 结构体,它定义“资源”──要用哪一个引脚。

在 chipY_gpio.c 中仍是实现 led_operations 结构体,它要写得更完善,支持所有 GPIO。

代码实现:
程序仍分为上下结构:上层 leddrv.c 向内核注册 file_operations 结构体;下层 chip_demo_gpio.c 提
供 led_operations 结构体来操作硬件。

下层的代码分为 2 个:chip_demo_gpio.c 实现通用的 GPIO 操作,board_A_led.c 指定使用哪个 GPIO,
即“资源”。

led_resource.h 中定义了 led_resource 结构体,用来描述 GPIO:

#ifndef _LED_RESOURCE_H
#define _LED_RESOURCE_H

/* GPIO3_0 */
/* bit[31:16] = group */
/* bit[15:0]  = which pin */
#define GROUP(x) (x>>16)
#define PIN(x)   (x&0xFFFF)
#define GROUP_PIN(g,p) ((g<<16) | (p))

struct led_resource {
	int pin;
};

struct led_resource *get_led_resouce(void);

#endif


board_A_led.c 指定使用哪个 GPIO,它实现一个 led_resource 结构体,并提供访问函数:


#include "led_resource.h"

static struct led_resource board_A_led = {
	.pin = GROUP_PIN(3,1),
};

struct led_resource *get_led_resouce(void)
{
	return &board_A_led;
}



chip_demo_gpio.c 中,首先获得 board_A_led.c 实现的 led_resource 结构体,然后再进行其他操作:

#include <linux/module.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 "led_opr.h"
#include "led_resource.h"

static struct led_resource *led_rsc;
static int board_demo_led_init (int which) /* 初始化LED, which-哪个LED */	   
{	
	//printk("%s %s line %d, led %d\n", __FILE__, __FUNCTION__, __LINE__, which);
	if (!led_rsc)
	{
		led_rsc = get_led_resouce();
	}
	
	printk("init gpio: group %d, pin %d\n", GROUP(led_rsc->pin), PIN(led_rsc->pin));
	switch(GROUP(led_rsc->pin))
	{
		case 0:
		{
			printk("init pin of group 0 ...\n");
			break;
		}
		case 1:
		{
			printk("init pin of group 1 ...\n");
			break;
		}
		case 2:
		{
			printk("init pin of group 2 ...\n");
			break;
		}
		case 3:
		{
			printk("init pin of group 3 ...\n");
			break;
		}
	}
	
	return 0;
}

static int board_demo_led_ctl (int which, char status) /* 控制LED, which-哪个LED, status:1-亮,0-灭 */
{
	//printk("%s %s line %d, led %d, %s\n", __FILE__, __FUNCTION__, __LINE__, which, status ? "on" : "off");
	printk("set led %s: group %d, pin %d\n", status ? "on" : "off", GROUP(led_rsc->pin), PIN(led_rsc->pin));

	switch(GROUP(led_rsc->pin))
	{
		case 0:
		{
			printk("set pin of group 0 ...\n");
			break;
		}
		case 1:
		{
			printk("set pin of group 1 ...\n");
			break;
		}
		case 2:
		{
			printk("set pin of group 2 ...\n");
			break;
		}
		case 3:
		{
			printk("set pin of group 3 ...\n");
			break;
		}
	}

	return 0;
}

static struct led_operations board_demo_led_opr = {
	.init = board_demo_led_init,
	.ctl  = board_demo_led_ctl,
};

struct led_operations *get_board_led_opr(void)
{
	return &board_demo_led_opr;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值