驱动分离分层

1、设备分层结构

led_dev----|
-bus
led_drv----|

在bus总线结构里面,分为设备分支与驱动分支
设备分支里面定义要使用的设备资源,驱动分支里面则写入较稳定的代码,这样把设备资源与驱动分开来,利于开发的模块化

2、设备分支

在此分支里面有一个结构体链表,成员为platform_device结构体

platform_device结构体原型

struct platform_device {
	const char	* name;		//名字,在与platform_driver匹配时依据就是此名字
	u32		id;				//设备id
	struct device	dev;	//设备,加载模块的时候需要其中的release函数
	u32		num_resources;	//设备个数,可用ARRAY_SIZE取得
	//#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
	struct resource	* resource;	//资源结构体
};

资源结构体resource

struct resource {
	resource_size_t start;
	resource_size_t end;
	const char *name;
	unsigned long flags;
	struct resource *parent, *sibling, *child;
};

初始化示例

static struct resource led_resource[] = {
	[0] = {
		.start 	= 0x56000050,
		.end	= 0x56000054,
		.flags	= IORESOURCE_MEM,
	},
	[1] = {
		.start	= 5,
		.end	= 5,
		.flags	= IORESOURCE_IRQ,
	}, 
};
/*下面的资源类型用于标定资源所属的类别*/
#define IORESOURCE_IO 0x00000100 /* Resource type */
#define IORESOURCE_MEM 0x00000200
#define IORESOURCE_IRQ 0x00000400
#define IORESOURCE_DMA 0x00000800


使用 platform_device_register()进行注册
patform_device_unregister()进行卸载

3、驱动分支

在此分支里面有一个结构体链表,成员为platform_driver结构体
platform_driver结构体原型
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 (*suspend_late)(struct platform_device *, pm_message_t state);
	int (*resume_early)(struct platform_device *);
	int (*resume)(struct platform_device *);
	struct device_driver driver;
};

例如下面的初始化
static struct platform_driver led_drv = {
	.probe	= led_drv_probe,	//配对成功后会执行此函数
	.remove	= led_drv_remove,	//设备移除的时候执行此函数
	.driver	= {
		.name	= "by_led",	//与platform_device配对
	},
};

使用 platform_driver_register()进行注册

patform_driver_unregister()进行卸载


4、两个分支加载过程

注册过程,设备的注册过程也与此类似
int platform_driver_register(struct platform_driver *drv)
{
	drv->driver.bus = &platform_bus_type;
	if (drv->probe)												//如果没有指定,则初始化为默认的函数
		drv->driver.probe = platform_drv_probe;
	if (drv->remove)
		drv->driver.remove = platform_drv_remove;
	if (drv->shutdown)
		drv->driver.shutdown = platform_drv_shutdown;
	if (drv->suspend)
		drv->driver.suspend = platform_drv_suspend;
	if (drv->resume)
		drv->driver.resume = platform_drv_resume;
	return driver_register(&drv->driver);
}

任意一边的分支加载如链表的时候都会执行bus里面的match函数进行匹配,若匹配成功就会执行probe函数,所以只有当两边的结构体加载完之后才会执行probe函数
struct bus_type platform_bus_type = {
	.name		= "platform",
	.dev_attrs	= platform_dev_attrs,
	.match		= platform_match,
	.uevent		= platform_uevent,
	.suspend	= platform_suspend,
	.suspend_late	= platform_suspend_late,
	.resume_early	= platform_resume_early,
	.resume		= platform_resume,
};

match函数原型
static int platform_match(struct device * dev, struct device_driver * drv)
{
	struct platform_device *pdev = container_of(dev, struct platform_device, dev);


	return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0);	//比较两个分支的名字
}

而移除的时候,移除任意一边的结构体都会执行到remove函数

probe函数:在这个函数里面可以进行字符设备的初始化等等自定义的事情


5、构建步骤

5.1、指定资源

static struct resource led_resource[] = {
	[0] = {
		.start 	= 0x56000050,
		.end	= 0x56000054,
		.flags	= IORESOURCE_MEM,
	},
	[1] = {
		.start	= 5,
		.end	= 6,
		.flags	= IORESOURCE_IRQ,
	}, 
};

5.2、建立platform_device结构体

static void led_dev_release(struct device * dev)
{
	;
}


static struct platform_device led_dev = {
	.name	=	"by_led",
	.id		= -1,
	.num_resources = ARRAY_SIZE(led_resource),
	.resource	= led_resource,
	.dev	= {
		.release	= led_dev_release,
	},
};

5.3、初始化以及卸载函数

static int led_dev_init(void)
{
	platform_device_register(&led_dev);
	return 0;
}

static void led_dev_exit(void)
{
	platform_device_unregister(&led_dev);
}

以上为device分支


5.4、构建platform_driver结构体

static int led_drv_probe(struct platform_device *p_dev)
{
	/* 输出打印信息,说明两者成功匹配 */
	printk("Found by_led, Connect success\n");
	
	return 0;
}
static int led_drv_remove(struct platform_device *p_dev)
{
	/* 输出打印信息,说明成功卸载设备 */
	printk("Found by_led, Remove success\n");
	
	return 0;
}
static struct platform_driver led_drv = {
	.probe	= led_drv_probe,
	.remove	= led_drv_remove,
	.driver	= {
		.name	= "by_led",
	},
};

5.5、构建初始化以及卸载函数

static int led_drv_init(void)
{
	platform_driver_register(&led_drv);
	return 0;
}


static void led_drv_exit(void)
{
	platform_driver_unregister(&led_drv);
}

5.6、在probe函数里面加入想做的事情

如果是字符设备驱动的话就可以进行register_chrdev以及后续的操作,也可以加入别的自定以动作

你可能感兴趣的:(s3c2440,linux驱动,设备分离分层)