平台总线专题

前言

本篇主要总结平台总线相关知识,包括设备驱动模型介绍、平台总线知识点的整理与代码的编写。

1、设备驱动模型

设备驱动模型的三要素:总线、驱动、设备。

1.1 总线对象

总线主要是负责管理驱动和设备,完成设备与驱动的匹配

实例化一个总线,至少要完成总线的名称与匹配方法。
struct bus_type {
	const char		*name;
	int (*match)(struct device *dev, struct device_driver *drv);
	};
总线的申请
int bus_register(struct bus_type *bus)
总线的注销
void bus_unregister(struct bus_type *bus)

1.2 设备对象

设备对象用来描述设备信息,包括地址,中断号,甚至其他自定义的数据

struct device {
	struct kobject kobj;  //所有对象的父类
	const char		*init_name; 
	// 在总线中会有一个名字,用于做匹配,在/sys/bus/mybus/devices/名字
	struct bus_type	*bus; //指向该device对象依附于总线的对象
	void		*platform_data; // 自定义的数据,指向任何类型数据
};
注册和注销的方法:
int device_register(struct device *dev)
void device_unregister(struct device *dev)

1.3 驱动对象

驱动对象描述设备驱动的放法;

struct device_driver {
	const char		*name;
	// 在总线中会有一个名字,用于做匹配,在/sys/bus/mybus/drivers/名字
	struct bus_type		*bus;//指向该driver对象依附于总线的对象
	int (*probe) (struct device *dev); // 如果device和driver匹配之后,driver要做的事情
	int (*remove) (struct device *dev); // 如果device和driver从总线移除之后,driver要做的事情
}
注册和注销:
	int driver_register(struct device_driver *drv)
	void driver_unregister(struct device_driver *drv)

1.4 如何实现总线匹配?

实现总线匹配首先要实现bus对象中的match方法,再保证驱动对象的名字和设备对象的名字相同。,匹配成功后,驱动会自动调用probe方法。

2、平台总线模型

平台总线模型的三元素同样是:总线、驱动、设备。

2.1 Platform_bus

  • Platform_bus不需要自己创建,系统开机的时候会自动创建。
  • 匹配方法:
    1)优先匹配pdriver中的id_table。【id_table里面包含了支持不同平台的名字】
    2)直接匹配pdriver名字和pdevice中的名字
struct platform_device *pdev = to_platform_device(dev);
struct platform_driver *pdrv = to_platform_driver(drv);
if (pdrv->id_table)// 如果pdrv中有idtable,平台列表名字和pdev中的名字
	return platform_match_id(pdrv->id_table, pdev) != NULL;

/* fall-back to driver name match */
return (strcmp(pdev->name, drv->name) == 0);

2.2 device对象

struct platform_device {
		const char	*name;  //用于做匹配
		int		id;  // 一般都是直接给-1
		struct device	dev; // 继承了device父类
		u32		num_resources; // 资源的个数
		struct resource	*resource; // 资源:包括了一个设备的地址和中断
	}
struct resource {
		resource_size_t start; // 开始
		resource_size_t end; //结束
		const char *name; //描述,自定义
		unsigned long flags; //区分当前资源描述的是中断(IORESOURCE_IRQ)还是内存(IORESOURCE_MEM)
		struct resource *parent, *sibling, *child;
	};
注册和注销
		int  platform_device_register(struct platform_device * pdev)void  platform_device_unregister(struct platform_device * pdev)

2.3 driver对象

struct platform_driver {
			int (*probe)(struct platform_device *); //匹配成功之后被调用的函数
			int (*remove)(struct platform_device *);//device移除的时候调用的函数
			struct device_driver driver; //继承了driver父类
			const char		*name;
			const struct platform_device_id *id_table; //如果driver支持多个平台,在列表中写出来
	};
注册和注销
		int platform_driver_register(struct platform_driver *drv);
		void platform_driver_unregister(struct platform_driver *drv)
probe方法:
probe方法: 对硬件进行操作
						a,注册设备号,并且注册fops--为用户提供一个设备标示,同时提供文件操作io接口
						b, 创建设备节点
						c, 初始化硬件
									ioremap(地址);  //地址从pdev需要获取
									readl/writle();
						d,实现各种io接口: xxx_open, xxx_read, ..
获取资源的方式:					
struct resource *platform_get_resource(struct platform_device *dev, unsigned int type, unsigned int num)
			// 参数1: 从哪个pdev中获取资源
			// 参数2:  资源类型
			// 参数3: 表示获取同种资源的第几个
		

3、 平台总线模型代码实现

3.1 pdevice代码实现

#include<linux/init.h>
#include<linux/module.h>
#include<linux/platform_device.h>

#define GPIO_REG_BASE 0x11400000

#define GPF3_CON GPIO_REG_BASE + 0x01E0
#define GPF3_SIZE  24

#define GPX1_CON  GPIO_REG_BASE + 0x0C20
#define GPX1_SIZE  24


struct resource	 led_res[]={
	[0]={
			.start=GPF3_CON,
			.end  = GPF3_CON + GPF3_SIZE - 1,
			.name = "led_1"
			.flags = IORESOURCE_MEM;
		}
	[1]= {
			.start=GPX1_CON,
			.end  = GPX1_CON + GPX1_SIZE - 1,
			.name = "led_2"
			.flags = IORESOURCE_MEM;
		}
	};

struct platform_device  pdev={
	.id=-1,
	.name = "fs4412_led",
	.resource = led_res,
	.num_resources = ARRAY_SIZE(led_res);
	};

static int __init platform_led_device_init(void)
{
	return platform_device_register(&pdev);
}
static void __exit platform_led_device_exit(void)
{
	platform_device_unregister(&pdev);
}


module_init(platform_led_device_init);
module_exit(platform_led_device_exit);
MODULE_LICENSE("GPL");




3.2 pdriver代码实现

#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/ioport.h>
#include <linux/platform_device.h>
#include <asm/io.h>
#include <asm/uaccess.h>
//设计一个全局的设备对象
struct led_dev{
	int dev_major;
	struct class *cls;
	struct device *dev;
	struct resource *res; //获取到的内存资源
	void *reg_base; //表示物理地址映射之后的虚拟地址
};
struct led_dev *samsung_led;
ssize_t led_pdrv_write (struct file *filp, const char __user *buf, size_t count, loff_t *fpos)
{
	int val;
	int ret;
	ret = copy_from_user(&val, buf, count);
	if(ret > 0)
	{
		printk("copy_from_user error\n");
		return -EFAULT;
	}

	if(val){ //亮
		writel(readl(samsung_led->reg_base + 4) | (0x3<<4) , samsung_led->reg_base+4);
	}else{
		writel(readl(samsung_led->reg_base + 4) & ~(0x3<<4) , samsung_led->reg_base+4);
	}

	return count;

}
int led_pdrv_open(struct inode *inode, struct file *filp)
{
	printk("-----%s------------\n", __FUNCTION__);
	return 0;

}
int led_pdrv_close(struct inode *inode, struct file *filp)
{
	printk("-----%s------------\n", __FUNCTION__);
	return 0;
}
const struct file_operations led_fops = {
	.open = led_pdrv_open,
	.release = led_pdrv_close,
	.write = led_pdrv_write,

};
int led_pdrv_probe(struct platform_device *pdev)
{
	printk("-----%s------------\n", __FUNCTION__);
	int ret;

	samsung_led = kzalloc(sizeof(struct led_dev), GFP_KERNEL);
	if(samsung_led == NULL)
	{
		printk("kzalloc errorn\n");
		return -ENOMEM;
	}
	samsung_led->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);

	samsung_led->dev_major = register_chrdev(0, "led_drv", &led_fops);

	samsung_led->cls = class_create(THIS_MODULE, "led_new_cls");

	samsung_led->dev = device_create(samsung_led->cls, NULL, MKDEV(samsung_led->dev_major, 0),NULL, samsung_led->res->name);
	samsung_led->reg_base = ioremap(samsung_led->res->start,  resource_size(samsung_led->res));	
	//对寄存器进行配置--输出功能
	writel((readl(samsung_led->reg_base) & ~(0xff<<16))| (0x11<<16) , samsung_led->reg_base);

	return 0;
}

int led_pdrv_remove(struct platform_device *pdev)
{
	printk("-----%s------------\n", __FUNCTION__);

	iounmap(samsung_led->reg_base);
	device_destroy(samsung_led->cls, MKDEV(samsung_led->dev_major, 0));
	class_destroy(samsung_led->cls);

	unregister_chrdev(samsung_led->dev_major, "led_drv");
	
		
	kfree(samsung_led);
	
	return 0;
}
const struct platform_device_id led_id_table={
					{"fs4412_led",0x1234};
					{"XXXXXX_led",0x4567};
};	
struct platform_driver  pdrv={
	.probe = plat_led_probe,
	.remove = plat_led_remove,
	.driver = {
				.name = "led_drv",
	}
	.id_table = led_id_table,
};
static int __init platform_led_driver_init(void)
{
	return platform_driver_register(&pdrv);
}
static void __exit platform_led_driver_exit(void)
{
	platform_driver_unregister(&pdrv);
}
module_init(platform_led_driver_init);
module_exit(platform_led_driver_exit);
MODULE_LICENSE("GPL");
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值