平台设备总线platfrom 框架开发

1:认识平台设备总线

1.1 平台设备总线是什么

平台设备总线:在 Linux 内核中,设备驱动程序是操作系统与硬件设备之间的桥梁。为了管理不同的硬件设备,Linux 内核引入了不同的设备总线(Bus)模型,其中“平台设备总线”(Platform Bus)是一个非常常见的总线类型。

总线设备示意图:

platform 是更早与设备树之前的分层思想

platform是内核抽象/虚拟的一条管理设备驱动的总线

在plaform框架下驱动被分为两层:

        第一层:设备层只提供设备信息

        第二层:驱动层通用动

随着内核的发展:
        其中的设备层演变成->设备树

在platform这条总线的管理下:

        内核里面驱动会自动匹配设备树

        内核层的驱动会自动获取设备树节点

2:平台设备总线的匹配方法:

2.1 老式的匹配方法:

        platform_device * drvier.name 函数传参相对麻烦的方式进行的,需要靠代码驱动的方法加载内核传参。

2.2 新试匹配方法

        在设备树的出现后,匹配方法就改变成:

                compatible = “abb”,“sadc”;

        驱动层platform代码会有一个结构体里面 compatible,只需要保证传入的字符串和设备树的compatible其中的一个相同就可以匹配成功。

3:平台设备树总线的驱动层的相关接口函数

开发平台设备总线的框架:

//头文件
#include "linux/platform_device.h"
//入口函数
static int led_probe(struct platfrom_device *dev)
{
    return 0;
}
//出口函数
static int led_remove(struct platform_device *dev)
{
    return 0;
}
//内核注册信息
static struct platform_driver led_drv=
{
    .probe = led_probe,
    .remove = led_remove,
    匹配 compatible
}

//加载函数
statict int __init led_init(void)
{
    platform_driver_register(&led_drv);
}
//卸载函数
static void __exit led_exit(void)
{
    //平台设备驱动注销
    platform_driver_unregister(&led_drv);
}


platform 只需要学习两个函数:

platform_driver_register();
platform_driver_unregister();

函数原型:

int platform_devicer_register(struct platform_driver * drv)

函数的参数:
drv:
        struct platform_driver {
        int (*probe)(struct platform_device *);//新入口
        int (*remove)(struct platform_device *);//新出口
        struct device_driver driver;//这里肯定有匹配的名字
};

* probe:
        你要提供的设备树匹配成功后执行的回调函数
        就是新入口函数
* remove:
        如果检测到驱动卸载/设备树异常就会执行 remove 回调函数
        新的出口函数
* driver:
        name: 是一个标签名->老式的匹配方法
        of_match_table:
        这就是有设备树的匹配的方法
        在这结构体里面虽说有四个成员
        只需要管 compatible 这个成员变量
函数返回值:
        注册成功返回 0
        注册失败返回 非 0
int platform_driver_unregister(struct platform_driver *drv)
取消注册驱动
怎么取消就行了

4:平台设备总线下LED灯驱动事例

#include "linux/kernel.h"
#include "linux/module.h"
#include "linux/of.h"
#include "linux/cdev.h"
#include "linux/fs.h"
#include "linux/gpio.h"
#include "linux/of_gpio.h"
#include "linux/device/class.h"
#include "linux/device.h"
#include "linux/platform_device.h"
struct class * cls;
dev_t devnum;
struct cdev  xydledcdev;
struct file_operations ops;
struct device_node * led_node;
struct xyd_led_gpio{
	int gpio_num;
	int gpio_flag;
	char name[32];
};
struct xyd_led_gpio myxyd_led_info;

struct of_device_id device_id[]={
	{.compatible = "xyd_led"},
	};
	
struct platform_driver drv;

//开灯回调函数
int led_open (struct inode *i, struct file *f)
{
	gpio_set_value(myxyd_led_info.gpio_num,myxyd_led_info.gpio_flag);
	return 0;
}
//关灯回调函数
int led_close (struct inode *i, struct file *f)
{
	gpio_set_value(myxyd_led_info.gpio_num,!myxyd_led_info.gpio_flag);
	return 0;
}

//新入口
int led_probe(struct platform_device * dev)
{
	//在这里进行资源初始化,设备注册 硬件初始化
	led_node = dev->dev.of_node;//设备树节点信息
	
	//然后一一获取设备树属性 GPIO口 statues 有效点平等
	//1.获取GPIO的属性
	myxyd_led_info.gpio_num = of_get_named_gpio(led_node, "xyd-gpios", 0);
	if(myxyd_led_info.gpio_num < 0)
	{
		printk("该设备树未提供 GPIO 信息! \r\n");
		return -EINVAL;
	}
	
	//2.获取GPIO的有效点平
	enum of_gpio_flags flags =0;
	of_get_named_gpio_flags(led_node,"xyd-gpios" , 0,&flags);
	if(flags == OF_GPIO_ACTIVE_LOW)
	{
		myxyd_led_info.gpio_flag=0;	
	}
	else
	{
		myxyd_led_info.gpio_flag=1;
	}
	
	//3:封装设别名
	sprintf(myxyd_led_info.name,"xyd_led_%d",myxyd_led_info.gpio_num);
	//4:初始化GPIO
	gpio_request(myxyd_led_info.gpio_num,myxyd_led_info.name);
	
	gpio_direction_output(myxyd_led_info.gpio_num,!myxyd_led_info.gpio_flag);
	//5:申请一个设备号
	alloc_chrdev_region(&devnum, 0,1,myxyd_led_info.name);
	//6:初始化cdev
	ops.open = led_open;
	ops.release = led_close;
	ops.owner= THIS_MODULE;
	cdev_init(&xydledcdev,&ops);
	//7:添加到内核
	cdev_add(&xydledcdev,devnum,1);
	//8:生成类结构体
	cls = class_create(THIS_MODULE,myxyd_led_info.name);
	//9:生成设备文件
	device_create(cls, NULL,devnum,NULL,myxyd_led_info.name);
	return 0;
}
//新出口               
int led_remove(struct platform_device *dev)
{
	//这里进行资源卸载 设备的取消注册 硬件释放
	//根据倒序的思想
	//1:销毁设备文件
	device_destroy(cls, myxyd_led_info.gpio_num);
	//2:销毁类文件
	class_destroy(cls);
	//3:从内核中删除
	cdev_del(&xydledcdev);
	//4:释放设备号
	unregister_chrdev_region(devnum, 1);
	//5:注销GPIO设备
	gpio_free(myxyd_led_info.gpio_num);
	return 0;
}

//内核注册信息
//配置对应结构体
static struct platform_driver led_drv=
{
	.probe = led_probe,
	.remove = led_remove,
	.driver = {
		.name = "myxyd_led",
		.of_match_table =  device_id,
	},
};
	
//工程原版框架入口函数
static int __init  leddrv_init(void)
{
	platform_driver_register(&led_drv);	
	return 0;
}

//出口函数
static void __exit leddrv_exit(void)
{
	platform_driver_unregister(&led_drv);
}

module_init(leddrv_init);
module_exit(leddrv_exit);
MODULE_LICENSE("GPL");



 

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值