前言
-
嵌入式Linux 設(shè)備驅(qū)動(dòng)開發(fā)時(shí),經(jīng)常遇到平臺(tái)驅(qū)動(dòng)
platform_driver_register
的注冊(cè),最近深入了看了驅(qū)動(dòng)開發(fā)為何使用平臺(tái)驅(qū)動(dòng) -
開發(fā)一個(gè)設(shè)備驅(qū)動(dòng)時(shí),為了實(shí)現(xiàn) 設(shè)備的 打開、關(guān)閉、控制等操作,可以注冊(cè)為 Linux misc 設(shè)備,不過在這之前,可以先使用
platform_driver_register
注冊(cè)平臺(tái)驅(qū)動(dòng),在平臺(tái)驅(qū)動(dòng)probe
函數(shù)中,初始化調(diào)用 misc 設(shè)備的注冊(cè)操作 -
platform driver 在設(shè)備驅(qū)動(dòng)開發(fā)中,到底起到了什么作用?為何不直接注冊(cè)一個(gè)實(shí)際的設(shè)備,如 misc 【字符設(shè)備】?
Linux 驅(qū)動(dòng)模型
-
仔細(xì)研究了一下,發(fā)現(xiàn)當(dāng)前較新的Linux 內(nèi)核版本,使用了【設(shè)備樹】,這里注冊(cè)的不是平臺(tái)設(shè)備,而是平臺(tái)的驅(qū)動(dòng),好處就是平臺(tái)驅(qū)動(dòng)在注冊(cè)時(shí),會(huì)自動(dòng)匹配設(shè)備節(jié)點(diǎn),匹配成功后,就會(huì)調(diào)用用戶注冊(cè)平臺(tái)驅(qū)動(dòng)時(shí)的
probe
函數(shù),匹配失敗,就不會(huì)調(diào)用probe
函數(shù)。 -
利用平臺(tái)驅(qū)動(dòng)的這個(gè)機(jī)制,在設(shè)備匹配成功再去注冊(cè)設(shè)備,那么注冊(cè)實(shí)際的設(shè)備的操作放在平臺(tái)驅(qū)動(dòng)
probe
中調(diào)用,再適合不過了,如根據(jù)設(shè)備樹覺得是否需要注冊(cè)一個(gè) misc 字符設(shè)備,如果匹配失敗,那這個(gè)設(shè)備不存在,就無(wú)須注冊(cè),匹配成功,說明設(shè)備存在,就會(huì)在probe
中注冊(cè)設(shè)備。 -
如果只是為了匹配設(shè)備樹,自己寫個(gè) match 函數(shù)就可以吧,為何還要注冊(cè)平臺(tái)驅(qū)動(dòng)這么麻煩?其實(shí)平臺(tái)驅(qū)動(dòng)本身一點(diǎn)都不麻煩,相反如果自己去拿個(gè)【設(shè)備節(jié)點(diǎn)名稱】去匹配設(shè)備樹,才會(huì)比較的麻煩,也就是說,注冊(cè)了平臺(tái)驅(qū)動(dòng),這個(gè)匹配操作就自動(dòng)完成了,不需要用戶寫一些匹配設(shè)備樹的操作函數(shù)手動(dòng)去匹配了。
-
注冊(cè)了平臺(tái)驅(qū)動(dòng),設(shè)備驅(qū)動(dòng)如果是【模塊編譯】的,在移除設(shè)備驅(qū)動(dòng)模塊時(shí),平臺(tái)驅(qū)動(dòng)remove 函數(shù)會(huì)自動(dòng)調(diào)用 ,這樣可以在 remove 函數(shù)中做些設(shè)備釋放的相關(guān)操作
-
如此看來,注冊(cè)平臺(tái)驅(qū)動(dòng),簡(jiǎn)化了設(shè)備驅(qū)動(dòng)的開發(fā),交給內(nèi)核驅(qū)動(dòng)模型去管理設(shè)備驅(qū)動(dòng),帶來了很多的便利
測(cè)試環(huán)境搭建
-
ubuntu 20.04
-
VMware Workstation Pro 16
-
基于qemu(模擬器),vexpress-a9 平臺(tái)
-
Linux 6.0.10 (當(dāng)前最新版本)
-
注冊(cè)一個(gè)簡(jiǎn)單的平臺(tái)驅(qū)動(dòng),掌握平臺(tái)驅(qū)動(dòng)注冊(cè)的方法
注冊(cè)Linux 平臺(tái)驅(qū)動(dòng)示例
-
在Linux 內(nèi)核 目錄:
linux-6.0.10/drivers
下創(chuàng)建led_control
文件夾,當(dāng)前 qemu 環(huán)境,無(wú)法控制具體的引腳,這里只作為示例,也可以實(shí)際的開發(fā)板驗(yàn)證 -
新建
linux-6.0.10/drivers/led_control/led_control.c
#include "led_control.h"
#define LED_CONTROL_DRIVER_NAME "led_control"
static int led_control_probe(struct platform_device *pdev);
static int led_control_remove(struct platform_device *pdev);
static void led_control_shutdown(struct platform_device *pdev);
/* 設(shè)備樹匹配:這里的節(jié)點(diǎn),在相應(yīng)的 dts 設(shè)備樹文件中添加 */
static const struct of_device_id led_control_of_match[] = {
{
.compatible = "gpio,led,led-control",
},
};
/* 平臺(tái)驅(qū)動(dòng) : 核心是 probe函數(shù),設(shè)備樹匹配后,會(huì)調(diào)用 probe */
static struct platform_driver led_control_driver = {
.probe = led_control_probe,
.remove = led_control_remove,
.shutdown = led_control_shutdown,
.driver = {
.name = LED_CONTROL_DRIVER_NAME,
.of_match_table = of_match_ptr(led_control_of_match),
},
};
static int led_control_probe(struct platform_device *pdev)
{
printk(KERN_INFO "%s : enter\n", __func__);
// led_miscdev_init(); /* 設(shè)備存在就會(huì)進(jìn)入這里,注冊(cè) misc 設(shè)備 */
return 0;
}
static int led_control_remove(struct platform_device *pdev)
{
printk(KERN_INFO "%s : enter\n", __func__);
//led_miscdev_exit(); /* 移除設(shè)備驅(qū)動(dòng)模塊時(shí),反注冊(cè) misc 設(shè)備 */
return 0;
}
static void led_control_shutdown(struct platform_device *pdev)
{
printk(KERN_INFO "%s : enter\n", __func__);
}
static int __init led_control_driver_init(void)
{
printk(KERN_INFO "%s : enter\n", __func__);
return platform_driver_register(&led_control_driver);
}
late_initcall(led_control_driver_init); /* 自動(dòng)初始化機(jī)制:開機(jī)后會(huì)調(diào)用 */
static void __exit led_control_driver_exit(void)
{
printk(KERN_INFO "%s : enter\n", __func__);
platform_driver_unregister(&led_control_driver);
}
module_exit(led_control_driver_exit); /* 移除驅(qū)動(dòng)模塊時(shí)會(huì)調(diào)用 */
MODULE_AUTHOR("zhangsz");
MODULE_DESCRIPTION("led control driver");
MODULE_LICENSE("GPL");
- 新建
linux-6.0.10/drivers/led_control/led_control.h
#ifndef __LED_CONTROL_H__
#define __LED_CONTROL_H__
#include <linux/of.h>
#include <linux/platform_device.h>
//#include "led_misc.h"
#endif
- 新建
linux-6.0.10/drivers/led_control/Kconfig
,這里增加一個(gè)【宏】
config LED_CONTROL
tristate "Support LED Control"
help
Enable LED Control driver
default y
- 新建
linux-6.0.10/drivers/led_control/Makefile
,Linux 下,默認(rèn)使用 Makefile 管理文件的編譯
obj-$(CONFIG_LED_CONTROL) += led_control.o
其他修改
- 雖然 led_control 驅(qū)動(dòng)里面Kconfig 默認(rèn)選中 【default y】,但是 menuconfig 中找不到這個(gè) Kconfig 配置,需要修改
linux-6.0.10/drivers/Kconfig
,把 led_control 的 Kconfig 路徑添加進(jìn)去
source "drivers/led_control/Kconfig"
- 修改二:還需修改
linux-6.0.10/drivers/Makefile
,增加 led_control 的 Makefile 路徑
obj-$(CONFIG_LED_CONTROL) += led_control/
- 修改三: 修改設(shè)備樹文件
vim arch/arm/boot/dts/vexpress-v2p-ca9.dts
,增加一個(gè)虛擬的設(shè)備節(jié)點(diǎn)
led_control@0 {
compatible = "gpio,led,led-control";
};
- 備注:可以使用VS Code ssh 連接ubuntu 主機(jī),進(jìn)行代碼的編寫
編譯
- led_control 屬于內(nèi)核驅(qū)動(dòng),默認(rèn)跟內(nèi)核一起編譯,當(dāng)然也可以使用【模塊編譯】
- 編譯命令:這里使用 qemu
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- vexpress_defconfig
# 默認(rèn)選擇了 led_control,可以 menuconfig 看看
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
## 編譯,默認(rèn)生成 zImage
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j8
- 把 內(nèi)核編譯生成的 zImage,放到 qemu 根文件系統(tǒng)中
啟動(dòng) qemu
-
簡(jiǎn)單編寫個(gè) 啟動(dòng) qemu 的shell 腳本,這樣每次就不用輸入那么長(zhǎng)的命令了
-
vim boot_qemu.sh
#!/bin/bash
echo "---------- boot qemu ----------"
echo $1
qemu-system-arm -M vexpress-a9 -m 512M -dtb vexpress-v2p-ca9.dtb -kernel zImage -nographic -append "root=/dev/mmcblk0 rw console=ttyAMA0" -sd $1
-
chmod +x boot_qemu.sh
增加執(zhí)行的權(quán)限 -
啟動(dòng) qemu ,
sudo ./boot_qemu.sh rootfs.ext4.img
,完整的啟動(dòng)命令行為
qemu-system-arm -M vexpress-a9 -m 512M -dtb vexpress-v2p-ca9.dtb -kernel zImage -nographic -append "root=/dev/mmcblk0 rw console=ttyAMA0" -sd rootfs.ext4.img
-
其中 rootfs.ext4.img 是 根文件系統(tǒng),制作方法可以參考前面的文章
ubuntu 20.04 qemu linux6.0.1 制作ext4根文件系統(tǒng) -
啟動(dòng)后,發(fā)現(xiàn) led_control 平臺(tái)驅(qū)動(dòng) 注冊(cè)成功,并且匹配設(shè)備樹節(jié)點(diǎn)成功,進(jìn)入了 probe 函數(shù)
led_control_driver_init : enter
led_control_probe : enter
- 進(jìn)入 Linux shell,查看 platform 驅(qū)動(dòng)的文件
ls sys/devices/platform/ -la
,可以找到注冊(cè)的 platform 驅(qū)動(dòng)led_control@0
- reboot 時(shí),發(fā)現(xiàn)調(diào)用了
led_control_shutdown : enter
- 以上說明 platform 驅(qū)動(dòng) 注冊(cè)成功,調(diào)用正常
小結(jié)
-
Linux 的一些 misc 設(shè)備,通過先注冊(cè) platform driver 平臺(tái)驅(qū)動(dòng),在平臺(tái)驅(qū)動(dòng) probe 函數(shù)中再注冊(cè)初始化misc 設(shè)備,這是一種很好的驅(qū)動(dòng)開發(fā)設(shè)計(jì)方法,充分利用了Linux 內(nèi)核提供的驅(qū)動(dòng)模型帶來的便利,讓驅(qū)動(dòng)開發(fā)精簡(jiǎn),利于管理文章來源:http://www.zghlxwxcb.cn/news/detail-791630.html
-
Linux 設(shè)備驅(qū)動(dòng)還是比較的龐大,需要花些時(shí)間與精力耐心研究,才能有所收獲文章來源地址http://www.zghlxwxcb.cn/news/detail-791630.html
到了這里,關(guān)于嵌入式Linux 開發(fā)經(jīng)驗(yàn):platform_driver_register 的使用方法的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!