加载中……
Linux 设备树(dts)节点相关函数

匹配流程

在设备树(dts、dtsi)中通常有一个compatible属性,我们可以在驱动源码里找到该属性值。例如:

/*定义的of_match_table*/
static const struct of_device_id mytest[] = {
    { .compatible = "test,12345" },
    { }
};

/*driver 结构体中的of_match_table*/
static struct i2c_driver mydriver = {
    .driver = {
        .name = DRIVER_NAME,
        .owner = THIS_MODULE,
        .of_match_table = of_match_ptr(mytest),
    },
    .probe = my_probe,
    .id_table = test_id,
};

static int my_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
    //处理
}

可以看到,在mydriver中.of_match_table设置成了mytest结构体,只要驱动中的.of_match_table 中的compatible 值和设备节点中的compatible 相匹配,那么probe函数(my_probe)就会被触发。另外,compatible对第二个字段敏感,即只有字段“12345”也可以成功匹配上。

GPIO操作

gpio_request

申请一个pin脚作为gpio口,命名为 * label,如果经过判断空闲的 申请成功了做一些初始的bit位设置。

int gpio_request(unsigned gpio, const char *label)
{
    struct gpio_desc *desc;
    struct gpio_chip *chip;
    int status = -EINVAL;
    unsigned long	 flags;

    spin_lock_irqsave(&gpio_lock, flags);
    ...
    if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0)
    ...
}

gpio_free

释放gpio口,还原bit。

void gpio_free(unsigned gpio)
{
	unsigned long		flags;
	struct gpio_desc	*desc;
	struct gpio_chip	*chip;


	might_sleep();
...
clear_bit(FLAG_ACTIVE_LOW, &desc->flags);
clear_bit(FLAG_REQUESTED, &desc->flags);
clear_bit(FLAG_OPEN_DRAIN, &desc->flags);
clear_bit(FLAG_OPEN_SOURCE, &desc->flags);
...
}

gpio_direction_input

设置gpio口为输入模式:

int gpio_direction_input(unsigned gpio)
{
	unsigned long		flags;
	struct gpio_chip	*chip;
	struct gpio_desc	*desc = &gpio_desc[gpio];
	int			status = -EINVAL;


	spin_lock_irqsave(&gpio_lock, flags);
	if (!gpio_is_valid(gpio))
		goto fail;
	chip = desc->chip;
...
	status = chip->direction_input(chip, gpio);
...
}

gpio_direction_output

设置gpio口为输出模式 value为初始值 0为高电平/1为低电平:

int gpio_direction_output(unsigned gpio, int value)
{
	unsigned long		flags;
	struct gpio_chip	*chip;
	struct gpio_desc	*desc = &gpio_desc[gpio];
	int			status = -EINVAL;


	/* Open drain pin should not be driven to 1 */
	if (value && test_bit(FLAG_OPEN_DRAIN,  &desc->flags))
		return gpio_direction_input(gpio);
...
	status = chip->direction_output(chip, gpio, value);
...
}

__gpio_set_value

设置gpio口的值:

void __gpio_set_value(unsigned gpio, int value)
{
	struct gpio_chip	*chip;

	chip = gpio_to_chip(gpio);
	WARN_ON(chip->can_sleep);
	trace_gpio_value(gpio, 0, value);
	if (test_bit(FLAG_OPEN_DRAIN,  &gpio_desc[gpio].flags))
		_gpio_set_open_drain_value(gpio, chip, value);
	else if (test_bit(FLAG_OPEN_SOURCE,  &gpio_desc[gpio].flags))
		_gpio_set_open_source_value(gpio, chip, value);
	else
		chip->set(chip, gpio - chip->base, value);
}

__gpio_get_value

获取gpio口的值:

int __gpio_get_value(unsigned gpio)
{
	struct gpio_chip	*chip;
	int value;

	chip = gpio_to_chip(gpio);
	WARN_ON(chip->can_sleep);
	value = chip->get ? chip->get(chip, gpio - chip->base) : 0;
	trace_gpio_value(gpio, 1, value);
	return value;
}

Sys节点属性

从底层把值传给上层有很多种方法,sysfs就是很简单的一个:

提到sysfs,就不得不提函数宏 DEVICE_ATTR

DEVICE_ATTR的原型:

 

#define DEVICE_ATTR(_name,_mode,_show,_store)\

struct device_atttribute dev_attr_##_name = __ATTR(_name,_mode,_show,_store) //名称,权限位,读函数,写函数

 

其中_show表示读方法 — 对应于adb的cat

_store表示写方法 — 对应于adb的echo

 

_ATTR宏有很多,例如设备使用的是DEVICE_ATTR,总线使用的是BUS_ATTR,驱动使用的是DRIVER_ATTR,类别(class)使用的是CLASS_ATTR, 这四个宏定义在<inlude/linux/device.h>中.

#include <linux/module.h>
#include <linux/slab.h>
#include <linux/kobject.h>
#include <linux/platform_device.h>
 
struct att_dev{
	struct platform_device *pdev;
	struct kobject *kobj;
};
 
static ssize_t att_store(struct device *dev, 
					struct device_attribute *attr, 
					const char *buf, size_t count) 
{
	printk("echo debug buf\n");
 
	return count;
}
 
static ssize_t att_show(struct device *dev,
                 struct device_attribute *attr,
                 char *buf)
{
	printk("cat debug buf\n");
	return 0;
}
static DEVICE_ATTR(test,0777,att_show,att_store);
 
static struct att_dev *dev = NULL;
 
static __devinit int att_probe(struct platform_device *ppdev){
	int ret;
	
	dev->kobj = kobject_create_and_add("attkobj", NULL); 
	if(dev->kobj == NULL){
		ret = -ENOMEM;
		goto kobj_err;
	}
 
	ret = sysfs_create_file(&dev->pdev->dev.kobj,&dev_attr_test.attr);
	if(ret < 0){ goto file_err; } return 0; file_err: kobject_del(dev->kobj);  
kobj_err:
	return ret;
}
 
static struct platform_driver att_driver = {
	.probe = att_probe,
	.driver = {
		.owner = THIS_MODULE,
		.name = "att_test",
	},
};
 
static int __init att_init(void)
{
	int ret;
 
	dev = kzalloc(sizeof(struct att_dev),GFP_KERNEL);
	if(dev == NULL){
		printk("%s get dev memory error\n",__func__);
		return -ENOMEM;
	}
	
	dev->pdev = platform_device_register_simple("att_test", -1, NULL, 0);  
	if(IS_ERR(dev->pdev)){
		PTR_ERR(dev->pdev); 
		printk("%s pdev error\n",__func__);
		return -1;
	}
 
    ret = platform_driver_register(&att_driver);
    if(ret < 0)
    { 
        printk("%s register driver error\n",__func__); 
        return ret; 
    } 
    return 0; 
} 
static void __exit att_exit(void) 
{ 
    sysfs_remove_file(&dev->pdev->dev.kobj,&dev_attr_test.attr);
    kobject_del(dev->kobj);
    platform_device_unregister(dev->pdev);
    platform_driver_unregister(&att_driver);
    if(dev != NULL)
        kfree(dev);
}
 
module_init(att_init);
module_exit(att_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("driverSir");

安装之后新增节点:/sys/devices/platform/att_test/test

echo 1 > test

cat test

dmesg之后会看到内核打印出

[  424.793357] echo debug buf
[  427.122139] cat debug buf

 

 

版权声明: 若无特殊说明,文章均为原创,版权归本文作者所有,转载请保留出处和此说明!
本文链接: Linux 设备树(dts)节点相关函数
本文作者: Jan.
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇