linux驱动模型

来源:互联网 发布:photoshop cc mac微盘 编辑:程序博客网 时间:2024/06/05 21:12

驱动模型
驱动模型的原理
参考文件:
E:\01-code\linux-4.1.6\linux-4.1.6\include\linux\device.h
Device
Driver
Kobject
Kset:
Platform_driver
Platform_device
Sysfs
Attribute
固件加载
可插拔设备驱动
Platform: 是一个虚拟总线
Platform device
struct platform_device {
const char *name;
int id;
bool id_auto;
struct device dev;
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;

};

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 (resume)(struct platform_device );
struct device_driver driver;
const struct platform_device_id *id_table;
bool prevent_deferred_probe;
};

/**
* __platform_driver_register - register a driver for platform-level devices
* @drv: platform driver structure
* @owner: owning module/driver
*/
int __platform_driver_register(struct platform_driver *drv,
struct module *owner)
{
drv->driver.owner = owner;
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;

return driver_register(&drv->driver);

}

调用流程如下:
__platform_driver_register
|–drv->driver.bus = &platform_bus_type;
|–driver_register
|–bus_add_driver
|–driver_attach
|–__driver_attach
|–driver_probe_device
|–really_probe
|–driver_add_groups
注册函数:
int platform_device_register(struct platform_device *pdev)
{
device_initialize(&pdev->dev); //初始化device相关的kobject
arch_setup_pdev_archdata(pdev);
return platform_device_add(pdev); //建立device与bus的关系,这里的总线为platform总线,在bus中增加设备。
}

platform_device_register
|–platform_device_add :add a platform device to device hierarchy
|–device_add :add device to device hierarchy.
|–device_create_file
|–device_add_attrs
|–bus_add_device: add device to bus
|–device_create_file
|–bus_probe_device :probe drivers for a new device
|–device_attach
|–__device_attach
|–driver_probe_device

Device,Driver,Bus
一、驱动注册:
platform_driver_register -》driver_register -》 bus_add_driver -》driver_attach -》__driver_attach -》driver_probe_device -》really_probe
1. 在driver_register函数中,会通过driver_find函数根据struct platform_driver.driver.name和drv->bus,即platform_bus_type来判断此name是否已经有注册。
假如没有注册就通过bus_add_driver函数把驱动添加到bus上, 通过创建struct driver_private *priv; 把driver的对应的kset指向bus的 priv->kobj.kset = bus->p->drivers_kset; 驱动与设备和总线的关系主要就是通过struct driver_private这个结构体。在driver_attach函数中会遍历整个bus上的设备,并在__driver_attach函数中会判断设备和驱动是否匹配。
匹配的话就通过driver_probe_device来probe。通过really_probe来真正实现probe操作。在really_probe中,首先bind pinctrl,然后建立sysfs文件节点。然后执行probe操作。
在probe操作中,首先判断设备的总线probe是否存在,假如存在就执行bus的probe操作;然后判断driver的probe函数指针是否存在,假如存在就执行driver的probe操作。

二、设备注册
platform_device_register -》platform_device_add -》device_add -》
说明:在platform_device_register函数中主要做两件事,
第一件事是device_initialize,初始化device的kobj以及device的属于全局的devices_kset,初始化device的PM操作。
第二件事是通过platform_device_add函数把platform_device增加到设备树中。主要是设置该设备属于什么总线,该设备的父设备。插入设备的resource。然后通过device_add来增加新的设备。
然后通过device和其父设备的关系,建立设备的kobject和父设备的kobject关系。创建设备相关的sysfs文件,然后把设备添加到对应的bus上。然后通过bus_probe_device来probe device. probe首先是判断总线的驱动是否支持drivers_autoprobe,假如支持就执行device_attach操作。

三、总线的注册
1. platform总线的注册:platform bus是一类虚拟的总线,可以把一些常见的外设当做platform device,挂载platform bus上,例如,RTC, WATCHDOG, SPI, IIC, LCD, touch等设备。除了platform总线,此外还有一些实际的物理总线:usb, pCI, SDIO, AMBA, MIPI, I2C, IDE, spi等。
platform_bus_init -》bus_register
在platform_bus_init是通过int __init platform_bus_init(void)来初始化的,是在系统初始化的过程中完成的。然后通过bus_register注册bus_register(&platform_bus_type);
在bus_register函数中,通过分配struct subsys_private结构体,然后建立该结构体中subsys, device, driver三个kset, 并建立device和driver的双链表。

四、device和driver,bus是如何建立联系的呢?
1. device使用struct device, bus使用struct bus_type结构体; driver使用struct device_driver;

首先看下truct device_driver结构体:它包含name, struct bus_type的指针变量, struct of_device_id(用于匹配device的结构体指针), probe,remove, shutdown, suspend, resuem等回调函数。
以及与PM相关的struct dev_pm_ops结构体指针。以及driver属性等成员、和私有的结构体struct driver_private *p;

struct device结构体包括如下成员:
1. struct device *parent; 当前设备的父设备
2. struct bus_type; 当前设备属于哪个总线
3. struct device_type;
4. struct device_driver; 此设备对应的driver
5. void *platform_data;
6. u32 id; device instance
7. struct class *class;
8. struct attribute_group **groups;
9. struct device_node of_node; / associated device tree node */
10. struct kobject kobj;

struct bus_type结构体主要包括如下成员:
1. const char *name; 总线的名称
2. struct device *dev_root; 根设备
3. struct device_attribute *dev_attrs; 设备属性
4. bus的回调函数:probe, match, remove, shutdown, suspend, resume, 以及PM相关的函数操作指针。
5. struct subsys_private *p; 子系统相关的私有结构体, 其中包括了subsys、device和driver的kset,以及struct class指针。
Kobject与kset
struct class结构体:设备类,是一个抽象出来的概念,常用的class有block, tty, usb, input等。
1. char *name;
2. struct class_attribute *class_attrs;
3. struct kobject *dev_kobj;
4. struct subsys_private *p;
5. 类相关的结构体

struct subsys结构体:

struct kobject结构体:
1. name:
2. struct kobject *parent;
3. struct kset *kset;
4. struct kobj_type *ktype;

struct kobj_type结构体:

struct kset结构体:
1. 包含了一个双链表
2. 包含了一个struct kobject成员
3. 包含了一个kset_uevent_ops结构体指针变量
实例分析
参考:E:\01-code\linux-4.1.6\linux-4.1.6\drivers\net\wireless\ath\wcn36xx\main.c
static int __init wcn36xx_init(void)
{
platform_driver_register(&wcn36xx_driver);
return 0;
}
static struct platform_driver wcn36xx_driver = {
.probe = wcn36xx_probe,
.remove = wcn36xx_remove,
.driver = {
.name = “wcn36xx”,
},
.id_table = wcn36xx_platform_id_table,
};
static const struct platform_device_id wcn36xx_platform_id_table[] = {
{
.name = “wcn36xx”,
.driver_data = 0
},
{}
};

Platform driver的注册:

Platform device的注册:

总结
========================== 总结
上面几个结构体的关系?
1. device与driver, bus的关系? 这三者的关系主要是通过kobject,kset来建立的。
2. kobject, kset的关系是怎样的?
每增加一个driver时都会增加一个kobject,并把这个kobject的kset指针与对应的bus的bus->p->drivers_kset关联起来。这样就初步确定了driver与bus的关系。
3. class, subsys的关系
4. sysfs 与各个结构体的关系。
Device tree的实现机制
设备树配置文件
配置文件存放在:linux\arch\arm\boot\dts\
文件格式要求
1. Compatible属性:定义系统的名称,它的组织形式为:,。Linux内核透过root结点”/”的compatible 属性即可判断它启动的是什么machine。
在.dts文件的每个设备,都有一个compatible 属性,compatible属性用户驱动和设备的绑定。compatible 属性是一个字符串的列表,列表中的第一个字符串表征了结点代表的确切设备,形式为”,”,其后的字符串表征可兼容的其他设备。
例如:
/ {
compatible = “samsung,s3c24xx”;
interrupt-parent = <&intc>;

  1. reg的组织形式为reg =

ifdef CONFIG_OF

static const struct of_device_id wlcore_sdio_of_match_table[] = {
{ .compatible = “ti,wl1271” },
{ .compatible = “ti,wl1273” },
{ .compatible = “ti,wl1281” },
{ .compatible = “ti,wl1283” },
{ .compatible = “ti,wl1801” },
{ .compatible = “ti,wl1805” },
{ .compatible = “ti,wl1807” },
{ .compatible = “ti,wl1831” },
{ .compatible = “ti,wl1835” },
{ .compatible = “ti,wl1837” },
{ }
};

下面分析: E:\01-code\linux-4.1.6\linux-4.1.6\arch\arm\boot\dts\omap3-cm-t3730.dts
行号 80 - compatible = “

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 不熟的表弟表妹向你借钱怎么办 开货车撞到人家房子了怎么办 坐骨被摔跤后好多年没好怎么办 自动挡汽车电子手刹刹车失灵怎么办 买家拍了不包邮的宝贝付款了怎么办 包邮快递买家不要了运费怎么办 舞蹈劈叉练出肌肉劈不下去怎么办 腰间盘突出压迫神经腿疼怎么办盘 绑定了我身份证的微信被盗了怎么办 用身份证办的手机卡不用了怎么办 平安陆金所交易密码忘了怎么办 陆金所密码交易密码忘记怎么办 带介指手指月肿了拿不下来怎么办 老公搞建筑的要长期在外地怎么办 媳妇跟婆婆吵架老公帮婆婆该怎么办 在家里礼佛香炉剩下的香头怎么办 精索曲张最近一打篮球就蛋疼怎么办 都两天了快递还是显示已发货怎么办 中通快递到达一天就是不派送怎么办 顺丰派送员把快递寄错了怎么办 顺丰快递把户籍卡弄丢了怎么办 金立手机不小心设置成英文了怎么办 三星手机不小心设置成英文了怎么办 手游方舟国际版渡渡鸟跟丢了怎么办 一打电话4g变2g怎么办 手机4g突然变2g怎么办 江湖风云录八卦门任务拒绝了怎么办 百度网盘下载时显示违规信息怎么办 在海马助手下载的游戏闪退怎么办 手机版百度云盘不能普通下载怎么办 手机版百度云盘一直加载中怎么办 登别人的网盘单同步通讯录了怎么办 被培训公司骗了贷款之后该怎么办 乐教乐学孩子登陆你那忘记了怎么办 脸擦破了痂掉了留斑怎么办 挤黑头后鼻子又红又疼怎么办 香奈儿邂逅清新淡香水不喷怎么办 脚面被压了肿起来了怎么办 每天加班很累反而失眠严重怎么办 减肥药吃了口臭嘴巴苦怎么办 上火引起的牙疼怎么办吃什么药