平台总线的概念和作用、怎么匹配以及代码编写思路步骤

一,平台总线的概念和作用

1,概念

总线通信都是有协议的。类似一条告诉公路
分为物理总线和虚拟总线
物理总线(现实中看的见的): i2c总线,spi总线,usb总线等,连接两个设备
虚拟总线(内核中):平台总线,连接两个对象
给两个对象提供一个匹配的平台,一个驱动可以匹配多个设备,也就是一夫多妻制

平台总线:
一个驱动的组成:

	1》实例化全局设备对象  ----kzalloc()       	   //与内核相关
    2》申请设备号  		  ----register_chrdev()    //与内核相关
    3》创建类   		      ----class_create()       //与内核相关
    4》创建设备节点  	  ----device_create()      //与内核相关
    5》实现设备操作接口    ----                     //与硬件相关
    6》硬件初始化 		  ----ioremap()       	   // 与硬件相关

利用平台总线:

在编写驱动时, 将驱动中相似操作硬件差异化数据分离
加载驱动时,利用平台总线将相似的操作和硬件差异化数据匹配组成一个完整的驱动

2,作用

在编写驱动时,使用分离的思想实现驱动。
1》可以减少编写重复的代码
2》也便于平台的升级设备升级
也有利于对设备的升级,比方说:板子上的芯片不变,外设时用的这个串口,然后又换了一个串口,此时我们也只需要改一些硬件的资源。所以就减少了我们重复的工作。

二,平台总线编程

面向对象思想:框架

在这里插入图片描述

怎么匹配:

采用面向对象的编程思想
1、在pdrv平台驱动模块中创建这个pdrv对象
2、利用平台总线platform_buspdrv对象通过相关函数注册到总线上去;
3、写pdev.c来描述每一个设备,if有多个设备,就可以写多个pdev.c,同时也是都要注册到平台总线上,此时平台总线会通过id_table去帮你匹配,每注册一个pdev.c就和pdrv.c进行匹配,if匹配不上,就会提示不对,或则有问题;if匹配成功,就会调用 pdrv中的probe() 函数。

pdrv.c怎么体现他可以匹配多个pdev.c呢?

platform_driver里面有一个id_table(用于匹配pdev对象的列表),会与platform_device中的name(用于和pdrv匹配的名称)进行配对。

比如:

在这里插入图片描述

每个pdev.c都有一个名字,此时拿到pdev的名字,然后去与pdrv里面的id_table名字列表进行匹配,if匹配成功,就会调用proble()函数,然后实现对硬件的操作,失败是不会调用proble()函数的。
此时上面pdrv.c里面的操作就不用重复写了

这只是在编写的时候是采用分离思想,但是加载到内核中去后,内核会帮我们合成一个驱动程序,内核会利用平台总线的这个匹配函数帮我们把pdrv和pdev合成一个驱动,也就是说,只是开发方式变了

1,平台总线相关的几个结构体

1.1 总线类型(内核中每个结构体都是这样的一个对象)-----自己可以利用这个结构体写一个自己的总线

struct bus_type {
    const char      *name;	//总线名称
    const char      *dev_name;
    struct device       *dev_root;
    const struct attribute_group **bus_groups;
    const struct attribute_group **dev_groups;
    const struct attribute_group **drv_groups;//if内核里面要实现这个平台总线的功能,内核就会实现这个接口
    int (*match)(struct device *dev, struct device_driver *drv);    //用于匹配的接口
    int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
    int (*probe)(struct device *dev);
    int (*remove)(struct device *dev);
    void (*shutdown)(struct device *dev);struct subsys_private *p;
    struct lock_class_key lock_key;
​
    bool need_parent_lock;
};
//注册和注销总线
extern int __must_check bus_register(struct bus_type *bus);
extern void bus_unregister(struct bus_type *bus);

1.2 平台设备驱动对象类型(pdrv)

struct platform_driver {
    int (*probe)(struct platform_device *);         //封装加载函数中的代码:申请设备号-创建类--创建设备节点等
    int (*remove)(struct platform_device *);        //封装卸载函数中的代码
    void (*shutdown)(struct platform_device *);
    int (*suspend)(struct platform_device *, pm_message_t state);
    int (*resume)(struct platform_device *);
    struct device_driver driver;        //父类
                    |
            const struct of_device_id   *of_match_table;      //用于匹配设备树中节点的列表   
    const struct platform_device_id *id_table;  //用于匹配pdev对象的列表
    bool prevent_deferred_probe;
};//注册和注销平台驱动
extern int __must_check driver_register(struct device_driver *drv);
extern void driver_unregister(struct device_driver *drv);

1.3 平台设备对象类型(pdev)

struct platform_device {
    const char  *name;          //用于和pdrv匹配的名称
    int     id;                 //表示不同的设备编号,一般为-1
    bool        id_auto;
    struct device   dev;        //父类
            |
     void *platform_data;   /* 平台自定义数据 */
    u64     platform_dma_mask;  
    u32     num_resources;      //资源个数
    struct resource *resource;  //资源const struct platform_device_id *id_entry;
    char *driver_override; /* Driver name to force a match *//* MFD cell pointer */
    struct mfd_cell *mfd_cell;/* arch specific additions */
    struct pdev_archdata    archdata;
};//注册和注销平台设备
extern int platform_device_register(struct platform_device *);
extern void platform_device_unregister(struct platform_device *);

1.4 平台资源

资源分为两种地址(内存) 资源, 中断资源

struct resource {
    resource_size_t start;   //如果是地址资源,表示起始地址,如果是中断资源,表示中断号
    resource_size_t end;    //如果是地址资源,表示最后一个字节的地址,如果是中断资源,表示中断号
    const char *name;       //字符串,表示描述信息,自定义
    unsigned long flags;    //表示资源的种类:地址资源(IORESOURCE_MEM)和中断资源(IORESOURCE_IRQ)
    unsigned long desc;
    struct resource *parent, *sibling, *child;
};
1.4.1 在pdrv中获取pdev中封装的资源
1.4.1.1 获取资源platform_get_resource
struct resource *platform_get_resource(struct platform_device *, unsigned int, unsigned int);
//参数1 ----- pdev对象指针
//参数2 ----- 资源的类型
//参数3 ----- 同类型资源的编号,每一种类型的资源编号都是从0开始
//返回值 ----- 成功:资源对象指针,失败:NULL
1.4.1.2 获取中断资源platform_get_irq
int platform_get_irq(struct platform_device *, unsigned int);
//参数1 ----- pdev对象指针
//参数2 ----- 资源的编号,从0开始
//返回值 ----- 成功:中断号,失败:错误码
例如:
int led_pdrv_probe(struct platform_device * pdev)
{
    struct resource *res1,*res2,*res3;
    unsigned int irqno;
    printk("------------^_^ %s-----------------\n",__FUNCTION__);
	//第一个地址资源
    res1 = platform_get_resource(pdev,IORESOURCE_MEM,0);  
    printk("res1->start = 0x%x\n",res1->start);
	
	//第二个地址资源
    res3 = platform_get_resource(pdev,IORESOURCE_MEM,1);  
    printk("res3->start = 0x%x\n",res3->start);
	
	//第一个中断资源 ----方法一
    res2 = platform_get_resource(pdev,IORESOURCE_IRQ,0);  
    printk("res2->start = 0x%x\n",res2->start);

	//获取第一个中断资源,方法二
    irqno = platform_get_irq(pdev, 0);   
    printk("irqno = 0x%x\n",irqno);

    
    return 0;
}

2、代码的实现思路:

xxx_pdev.c

//代码先写模块
1、入口函数、出口函数
	static int __init led_pdev_init(void)
	static void __exit led_pdev_exit(void)


2、函数声明
	module_init(led_pdev_init);
	module_exit(led_pdev_exit);
	MODULE_LICENSE("GPL");
	MODULE_INFO(intree, "Y");

3、实例化pdev对象             //面向对象的编程
	struct platform_device  //平台设备对象类型

3_1、定义资源:
	struct resource    //以数组形式
	例:
	[0] = {				
		.start	=	GPIOZ,	//其实地址
		.end	=	GPIOZ + sizeof(gpio_t)-1,	//末尾字节地址
		.flags	=	IORESOURCE_MEM,		//内存资源
	},
	
	[1] = {				
		.start 	= 0x120,	//中断号
		.end 	= 0x120,	//中断号
		.flags	= IORESOURCE_IRQ,		//中断资源
	},
	

4、注册平台设备  //在入口函数
	extern int platform_device_register(struct platform_device *);

5、注销平台设备  //在出口函数
	extern void platform_device_unregister(struct platform_device *);

xxx_pdrv.c

1、入口函数、出口函数
    static int __init led_pdrv_init(void)
	static void __exit led_pdrv_exit(void)


2、函数声明
    module_init(led_pdrv_init);
    module_exit(led_pdrv_exit);
    MODULE_LICENSE("GPL");
    MODULE_INFO(intree,"Y");
    
3、实例化pdrv对象             //面向对象的编程
    struct platform_driver led_pdrv 
//主要是实现函数接口
    int (*probe)(struct platform_device *);         
    //封装加载函数中的代码:申请设备号-创建类--创建设备节点等
    
    int (*remove)(struct platform_device *);        
    //封装卸载函数中的代码

4、注册平台驱动  //在入口函数
    return platform_driver_register(&led_pdrv);

5、注销平台驱动  //在出口函数
    platform_driver_unregister(&led_pdrv);

注: pdrvpdev匹配成功会调用probe函数

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值