一、什么是驅動框架?
數據結構,這些是驅動框架的直接表現。
Linux/init.h中。
這個宏的功能是:將其聲明的函數放到一個特定的段:.initcall4.init。
(2)分析module_init宏,可以看出它將函數放到了.initcall6.init段中。
module_init
__initcall
device_initcall
__define_initcall('6',fn,6)
(3)內核在啟動過程中,需要按照順序執行很多事情。內核如何實現按照先后順序去做很多初始化操作?
內核的解決方案就是將內核啟動時要調用的所有函數歸類,然后每個類按照一定的次序去調用執行。
這些分類名就叫.initcalln.init,n的值從1到8。
內核開發者在編寫內核代碼時只要將函數設置合適的級別,鏈接的時候,這些函數就會被放入特定的段,內核啟動時再按照(內核鏈接腳本中指定的)段順序去依次執行各個段即可。內核鏈接腳本(編譯之后才有)在arch/arm/kernel/vmlinux.lds中。
(4)經過分析可以看出,subsys_initcall和module_init的作用是一樣的,只不過前者所聲明的函數要比后者在內核啟動時的執行順序更早。
3、led_class_attrs
(1)什么是attribute?
對應將來/sys/class/leds/目錄里的內容,一般是文件和文件夾。
這些文件其實就是sysfs開放給應用層的一些操作接口(非常類似于/dev/目錄下的那些設備文件,對這些設備文件的操作API,對應file_operations里面的函數)。
(2)attribute有什么用?
讓應用程序可以通過/sys/class/leds/目錄下面的屬性文件來操作驅動進而操作硬件設備。
(3)attribute其實是另一條驅動實現的路線(不再有c_dev相關的函數操作),有區別于之前講的file_operations那條線。
4、led_classdev_register設備注冊函數
led_classdev_register函數創建一個屬于leds這個類的一個設備,其實就是去注冊一個設備。
這個函數是led驅動框架中,內核開發者提供給SoC廠家驅動開發者的一個注冊驅動的接口。
當使用led驅動框架去編寫驅動的時候,這個led_classdev_register函數的作用類似于之前使用file_operations方式去注冊字符設備驅動時的register_chrdev函數。
之前使用file_operations方式時,在sys/class目錄下創建一個類,然后再創建屬于這個類的一個設備。
5、led_classdev結構體
在leds.h文件中
四、在內核中添加或去除某個驅動
1、去除九鼎移植的LED驅動
(1)九鼎移植的驅動(在應用層的接口)在/sys/devices/platform/x210-led/目錄下,有led1、led2、led3、led4四個設備文件,各自管理一個led。
echo 1 > led1可以點亮其中的led1;
(2)要去掉九鼎自己移植的led驅動,要在make menucofig中去掉選擇項,然后重新make得到zImage,然后重啟時啟動這個新的zImage即可。
新的內核啟動后,如果/sys/devices/platform/目錄下已經沒有了x210-led這個目錄,就說明我們去掉這個驅動成功了。
(3)為什么make menuconfig就能去掉這個驅動?
理解make menuconfig的功能。
2、添加led驅動框架支持
當前內核中沒有LED驅動框架,要去添加它。(/sys/class目錄下沒有此類,因此要去添加此類)
主要是menuconfig的操作。
3、sysfs中的內容分析
4、后續展望:完成leds-x210.c
五、基于驅動框架寫led驅動1
1、分析
(1)參考哪里? drivers/leds/leds-s3c24xx.c文件
(2)關鍵點?led_classdev_register函數
2、動手寫led驅動模塊
代碼如下
注意設備注冊函數、設備注銷函數
#include
// module_init module_exit #include
// __init __exit #include
#include
#include
#include
#include
#include
#define GPJ0CON S5PV210_GPJ0CON
#define GPJ0DAT S5PV210_GPJ0DAT
static struct led_classdev mydev; // 定義結構體變量
// 這個函數就是要去完成具體的硬件讀寫任務的
static void s5pv210_led_set(struct led_classdev *led_cdev,enum led_brightness value)
{
printk(KERN_INFO 's5pv210_led_setn');
// 在這里根據用戶設置的值來操作硬件
// 用戶設置的值就是value
if (value == LED_OFF)
{
// 用戶給了個0,希望LED滅
writel(0x11111111, GPJ0CON);
writel(((1<<3) | (1<<4) | (1<<5)), GPJ0DAT);
}
else
{
// 用戶給的是非0,希望LED亮
writel(0x11111111, GPJ0CON);
writel(((0<<3) | (0<<4) | (0<<5)), GPJ0DAT);
}
}
static int __init s5pv210_led_init(void)
{
// 用戶insmod安裝驅動模塊時會調用該函數
// 該函數的主要任務就是去使用led驅動框架提供的設備注冊函數來注冊一個設備
int ret = -1;
mydev.name = 'myled';//設備的名字
mydev.brightness = 255;
mydev.brightness_set = s5pv210_led_set;
ret = led_classdev_register(NULL, &mydev);
if (ret < 0) {
printk(KERN_ERR 'led_classdev_register failedn');
return ret;
}
return 0;
}
static void __exit s5pv210_led_exit(void)
{
led_classdev_unregister(&mydev);
}
module_init(s5pv210_led_init);
module_exit(s5pv210_led_exit);
// MODULE_xxx這種宏作用是用來添加模塊描述信息
MODULE_LICENSE('GPL'); // 描述模塊的許可證
MODULE_AUTHOR('aston <1264671872@qq.com>'); // 描述模塊的作者
MODULE_DESCRIPTION('s5pv210 led driver'); // 描述模塊的介紹信息
MODULE_ALIAS('s5pv210_led'); // 描述模塊的別名信息
六、基于驅動框架寫led驅動2
1、代碼實踐
(1)調試
(2)分析
我們寫的驅動確實工作了,被加載了,/sys/class/leds/目錄下確實多出來了一個表示設備的文件夾。
文件夾里面有相應的操控led硬件的2個屬性brightness和max_brightness。
led-class.c中brightness方法有一個show方法和store方法,這兩個方法對應用戶在/sys/class/leds/myled/brightness目錄下直接去讀寫這個文件時實際執行的代碼。
當我們show brightness時,實際就會執行led_brightness_show函數。
當我們echo 1 > brightness時,實際就會執行led_brightness_store函數。
(3)show方法實際要做的就是讀取LED硬件信息,然后把硬件信息返回
因此show方法和store方法會去操控硬件;
但是led-class.c文件又屬于驅動框架中的文件,它本身無法直接讀取具體硬件,因此在show和store方法中使用函數指針的方式調用了struct led_classdev結構體中的相應的讀取/寫入硬件信息的方法。
(4)struct led_classdev結構體中的實際用來讀寫硬件信息的函數,就是我們自己寫的驅動文件leds-s5pv210.c中要提供的。
2、添加硬件操作
七、基于驅動框架寫led驅動3
1、在驅動中將4個LED分開
(1)好處
驅動層實現對各個LED設備的獨立訪問,并向應用層展示出4個操作接口led1、led2、led3、led4,這樣應用層可以完全按照自己的需要對LED進行控制。
驅動的設計理念:不要對最終需求功能進行假定(不能假定用戶進行什么操作,比如是幾個led一起操作還是一個操作而已?),而應該只是直接的對硬件的操作。
有一個概念就是:機制和策略的問題。在硬件操作上驅動只應該提供機制(具體實現)而不是策略(方法、主意、解決方案)。策略由應用程序來做。
(2)如何實現
#include
// module_init module_exit #include
// __init __exit #include
#include
#include
#include
#include
#include
#define GPJ0CON S5PV210_GPJ0CON
#define GPJ0DAT S5PV210_GPJ0DAT
static struct led_classdev mydev1; // 定義結構體變量
static struct led_classdev mydev2; // 定義結構體變量
static struct led_classdev mydev3; // 定義結構體變量
上一篇:tiny210V2 Uboot kernel filesystem 燒寫和啟動
下一篇:INPUT輸入子系統——按鍵
推薦閱讀最新更新時間:2025-04-07 06:52







設計資源 培訓 開發板 精華推薦
- 迅為IMX6開發板Android應用-AndroidStudio-calculator測試
- 玩轉 ESP32 + Arduino (二十) SIM800L上傳數據到OneNet(新版Mqtts)
- 玩轉 ESP32 + Arduino (二十一) SPIFFS文件系統 (已棄用)
- 玩轉 ESP32 + Arduino (二十二) SIM800L上傳數據到阿里IOT(溫濕度和LBS)(NTP對時)
- 玩轉 ESP32 + Arduino (二十三) 多文件系統及全局變量
- 玩轉 ESP32 + Arduino (二十四) SD卡讀寫
- 玩轉 ESP32 + Arduino (二十五) SSD1306庫驅動OLED
- 玩轉 ESP32 + Arduino(二十六) 按鍵控制庫 OneButton
- 玩轉 ESP32 + Arduino(二十七) ESP對象
- LT3692AIFE 四路輸出 5V、2.5V、1.8V 和 1.2V 多頻同步、兩級轉換器的典型應用電路
- 用于光網絡的光收發器
- 消費類電子產品PIC12 MCU開發系統
- AM2G-2415DH30Z ±15V 2 瓦 DC/DC 轉換器的典型應用
- SSM3302 2 x 10 W 無濾波器 D 類立體聲音頻放大器的典型立體聲模式配置應用電路
- NCV3030B同步PWM控制器典型應用
- LT8500ITJ 單個 LT8500 的典型應用電路從 VDD 軌驅動 48 個電阻鎮流 LED 串
- 使用 NXP Semiconductors 的 TDA1521Q 的參考設計
- LT1634ACS8-2.5 單節鋰離子電池監控電路的典型應用 (IQ = 20uA)
- 2.4G無線通信模塊-SI24R1