【TINY4412】LINUX移植笔记:(17)设备树HELLO WORLD驱动

【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 <1530454315@qq.com>
 *
 * 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 <1530454315@qq.com>");
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],表示编译成独立的模块。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值