【TINY4412】LINUX移植筆記:(17)設備樹 HELLO WORLD驅動
宿主機 : 虛擬機 Ubuntu 16.04 LTS / X64
目標板[底板]: Tiny4412SDK - 1506
目標板[核心板]: Tiny4412 - 1412
LINUX內核: 4.12.0
交叉編譯器: gcc-arm-none-eabi-5_4-2016q3
日期: 2017-8-7 20:46:09
作者: SY
簡介
通過這個基於設備樹的例程,熟悉Linux內核
驅動。
設備樹
HelloWorld {
compatible = "tiny4412, hello_world";
status = "okay";
};
源文件
新建一個hello_world.c
源文件
root@ubuntu:/opt/linux-4.12# more drivers/tiny4412/hello_world.c
/*
* Hello World Driver for Tiny4412
*
* Copyright (c) 2017
* Author: SY <[email protected]>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
*/
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/of.h>
static int hello_world_probe(struct platform_device *pdev)
{
pr_notice("------------------- %s\n", __func__);
return 0;
}
static int hello_world_remove(struct platform_device *pdev)
{
pr_notice("------------------- %s\n", __func__);
return 0;
}
static void hello_world_shutdown(struct platform_device *pdev)
{
pr_notice("------------------- %s\n", __func__);
return ;
}
static int hello_world_suspend(struct platform_device *pdev, pm_message_t state)
{
pr_notice("------------------- %s\n", __func__);
return 0;
}
static int hello_world_resume(struct platform_device *pdev)
{
pr_notice("------------------- %s\n", __func__);
return 0;
}
static const struct of_device_id tiny4412_hello_world_dt_match[] = {
{ .compatible = "tiny4412, hello_world" },
{},
};
static struct platform_driver tiny4412_hello_world_driver = {
.probe = hello_world_probe,
.remove = hello_world_remove,
.shutdown = hello_world_shutdown,
.suspend = hello_world_suspend,
.resume = hello_world_resume,
.driver = {
.name = "hello world",
.of_match_table = tiny4412_hello_world_dt_match,
},
};
module_platform_driver(tiny4412_hello_world_driver);
MODULE_AUTHOR("SY <[email protected]>");
MODULE_DESCRIPTION("TINY4412 Hello World driver");
MODULE_LICENSE("GPL v2");
寫一個Makefile
文件
root@ubuntu:/opt/linux-4.12# cat drivers/tiny4412/Makefile
obj-$(CONFIG_BSP_HELLO_WORLD) += hello_world.o
在上一級目錄的Makefile
末尾添加
root@ubuntu:/opt/linux-4.12# cat drivers/Makefile
# tiny4412
obj-$(CONFIG_TINY4412_BSP) += tiny4412/
寫一個Kconfig
配置文件
root@ubuntu:/opt/linux-4.12# cat drivers/tiny4412/Kconfig
menuconfig TINY4412_BSP
bool "TINY4412 BSP Support"
help
Select [Y] to enable tiny4412 driver.
if TINY4412_BSP
config BSP_HELLO_WORLD
tristate "HELLO WORLD Support"
help
This option enables hello_world in /tiny4412/hello_world.
You'll need this to open hello_world driver.
It can be built as a module.
endif # TINY4412_BSP
在上一級的Kconfig
中添加
root@ubuntu:/opt/linux-4.12# cat drivers/Kconfig
source "drivers/tiny4412/Kconfig"
編譯hello_world.c
root@ubuntu:/opt/linux-4.12# make modules
安裝hello_world.ko
root@ubuntu:/opt/linux-4.12# make modules_install INSTALL_MOD_PATH=/opt/fs/rootfs/rootfs/
測試
使用NFS
進入LINUX內核
[root@TINY4412:~]# depmod
depmod
命令可產生模塊依賴的映射文件;
加載模塊
[root@TINY4412:~]# modprobe hello_world
[ 1561.495147] ------------------- hello_world_probe
卸載模塊
[root@TINY4412:~]# rmmod hello_world
[ 1596.936763] ------------------- hello_world_remove
關機
[root@TINY4412:~]# modprobe hello_world
[ 1561.495147] ------------------- hello_world_probe
[root@TINY4412:~]# reboot
The system is going down NOW!
Sent SIGTERM to all processes
Terminated
Sent SIGKILL to all processes
Requesting system reboot
[ 39.681554] ------------------- hello_world_shutdown
進階探索
基於當前的hello_world.c
,我們添加一些元素,瞭解linux
內核驅動加載流程
在hello_world.c
中添加
static int hello_world_probe(struct platform_device *pdev)
{
void *platdata = NULL;
pr_notice("------------------- %s\n", __func__);
platdata = dev_get_platdata(&pdev->dev);
pr_notice("platdata = %p\n", platdata);
return 0;
}
測試
[root@TINY4412:~]# modprobe hello_world
[ 279.524148] hello_world: loading out-of-tree module taints kernel.
[ 279.526495] ------------------- hello_world_probe
[ 279.526609] platdata = (null)
可以看出來,在第一次執行probe
時,還沒有platdata
。
在hello_world.c
中添加
static int hello_world_probe(struct platform_device *pdev)
{
void *platdata = NULL;
int count = 0;
pr_notice("------------------- %s\n", __func__);
platdata = dev_get_platdata(&pdev->dev);
pr_notice("platdata = %p\n", platdata);
pr_notice("device_tree = %p\n", pdev->dev.of_node);
count = of_get_child_count(pdev->dev.of_node);
pr_notice("child_count = %d\n", count);
return 0;
}
測試
[root@TINY4412:~]# modprobe hello_world
[ 279.524148] hello_world: loading out-of-tree module taints kernel.
[ 279.526495] ------------------- hello_world_probe
[ 279.526609] platdata = (null)
[ 279.526679] device_tree = ef7f5e0c
[ 279.526753] child_count = 0
可以看出,設備樹節點已經有值。(廢話! compatible
字段匹配了,當然有值 :-) ),打印出來的孩子個數爲0
。修改設備樹
HelloWorld {
compatible = "tiny4412, hello_world";
status = "okay";
instance {
aaa = <123>;
};
};
測試
[root@TINY4412:~]# modprobe hello_world
[ 279.524148] hello_world: loading out-of-tree module taints kernel.
[ 279.526495] ------------------- hello_world_probe
[ 279.526609] platdata = (null)
[ 279.526679] device_tree = ef7f5e0c
[ 279.526753] child_count = 1
可以看出,子節點就是嵌套在包含compatible
字段的{...}
內的節點。
總結
- 如果驅動與設備樹的
compatible
字段不匹配,不會加載驅動。 - 如果設備樹中的
status = disabled
,也不會加載驅動,如果不寫或者設置爲status = okay
,則加載驅動的probe
方法。 - 設備在
menuconfig
中如果配置爲[*]
,表示編譯進內核;如果配置爲[M]
,表示編譯成獨立的模塊。