驱动分离分层

1、设备分层结构

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

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

2、设备分支

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

platform_device结构体原型

struct platform_device {const char	* name;		//名字,在与platform_driver匹配时依据就是此名字u32		id;				//设备idstruct 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以及后续的操作,也可以加入别的自定以动作


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部