驱动设计的思想:面向对象/分层/分离
文章目錄
- 1 面向對象
- 2 分層
- 3 分離
1 面向對象
字符設備驅動程序抽象出一個 file_operations 結構體;
我們寫的程序針對硬件部分抽象出led_operations 結構體。
2 分層
上下分層,比如我們前面寫的 LED 驅動程序就分為 2 層:
① 上層實現硬件無關的操作,比如注冊字符設備驅動:leddrv.c。
② 下層實現硬件相關的操作,比如 board_A.c 實現單板 A 的 LED 操作。
3 分離
還能不能改進?分離。
在 board_A.c 中,實現了一個led_operations,為 LED 引腳實現了初始化函數、控制函數:
如果硬件上更換一個引腳來控制 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);#endifboard_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; } 《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的驱动设计的思想:面向对象/分层/分离的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: FFMpeg的基本介绍
- 下一篇: FFMpeg的基本用法